[CCSDK-28] populated the seed code for dgbuilder 31/8931/1
authorChinthakayala, Sheshashailavas (sc2914) <sc2914@us.att.com>
Mon, 28 Aug 2017 14:25:46 +0000 (05:25 -0900)
committerChinthakayala, Sheshashailavas (sc2914) <sc2914@att.com>
Mon, 28 Aug 2017 14:36:52 +0000 (05:36 -0900)
updated the code to point to the new package name for sli

Change-Id: I3b5a1d05dc5193664fd4a667afdcd0b2354010a4
Issue-ID:{CCSDK-28}
Signed-off-by: Chinthakayala, Sheshashailavas (sc2914) <sc2914@att.com>
Signed-off-by: Chinthakayala, Sheshashailavas (sc2914) <sc2914@att.com>
379 files changed:
dgbuilder/.gitignore [new file with mode: 0644]
dgbuilder/CONTRIBUTING.md [new file with mode: 0644]
dgbuilder/Gruntfile.js [new file with mode: 0644]
dgbuilder/INSTALL.md [new file with mode: 0644]
dgbuilder/LICENSE [new file with mode: 0644]
dgbuilder/build_pom_for_yang_compile [new file with mode: 0755]
dgbuilder/core_nodes/analysis/72-sentiment.html [new file with mode: 0644]
dgbuilder/core_nodes/analysis/72-sentiment.js [new file with mode: 0644]
dgbuilder/core_nodes/core/20-inject.html [new file with mode: 0644]
dgbuilder/core_nodes/core/20-inject.js [new file with mode: 0644]
dgbuilder/core_nodes/core/58-debug.html [new file with mode: 0644]
dgbuilder/core_nodes/core/58-debug.js [new file with mode: 0644]
dgbuilder/core_nodes/core/75-exec.html [new file with mode: 0644]
dgbuilder/core_nodes/core/75-exec.js [new file with mode: 0644]
dgbuilder/core_nodes/core/80-function.html [new file with mode: 0644]
dgbuilder/core_nodes/core/80-function.js [new file with mode: 0644]
dgbuilder/core_nodes/core/80-template.html [new file with mode: 0644]
dgbuilder/core_nodes/core/80-template.js [new file with mode: 0644]
dgbuilder/core_nodes/core/89-delay.html [new file with mode: 0644]
dgbuilder/core_nodes/core/89-delay.js [new file with mode: 0644]
dgbuilder/core_nodes/core/89-trigger.html [new file with mode: 0644]
dgbuilder/core_nodes/core/89-trigger.js [new file with mode: 0644]
dgbuilder/core_nodes/core/90-comment.html [new file with mode: 0644]
dgbuilder/core_nodes/core/90-comment.js [new file with mode: 0644]
dgbuilder/core_nodes/core/98-unknown.html [new file with mode: 0644]
dgbuilder/core_nodes/core/98-unknown.js [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/61-imap.html [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/61-imap.js [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/73-parsexml.html [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/73-parsexml.js [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/74-js2xml.html [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/74-js2xml.js [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/90-httpget.html [new file with mode: 0644]
dgbuilder/core_nodes/deprecated/90-httpget.js [new file with mode: 0644]
dgbuilder/core_nodes/hardware/35-arduino.html [new file with mode: 0644]
dgbuilder/core_nodes/hardware/35-arduino.js [new file with mode: 0644]
dgbuilder/core_nodes/hardware/36-rpi-gpio.html [new file with mode: 0644]
dgbuilder/core_nodes/hardware/36-rpi-gpio.js [new file with mode: 0644]
dgbuilder/core_nodes/io/10-mqtt.html [new file with mode: 0644]
dgbuilder/core_nodes/io/10-mqtt.js [new file with mode: 0644]
dgbuilder/core_nodes/io/21-httpin.html [new file with mode: 0644]
dgbuilder/core_nodes/io/21-httpin.js [new file with mode: 0644]
dgbuilder/core_nodes/io/22-websocket.html [new file with mode: 0644]
dgbuilder/core_nodes/io/22-websocket.js [new file with mode: 0644]
dgbuilder/core_nodes/io/23-watch.html [new file with mode: 0644]
dgbuilder/core_nodes/io/23-watch.js [new file with mode: 0644]
dgbuilder/core_nodes/io/25-serial.html [new file with mode: 0644]
dgbuilder/core_nodes/io/25-serial.js [new file with mode: 0644]
dgbuilder/core_nodes/io/31-tcpin.html [new file with mode: 0644]
dgbuilder/core_nodes/io/31-tcpin.js [new file with mode: 0644]
dgbuilder/core_nodes/io/32-udp.html [new file with mode: 0644]
dgbuilder/core_nodes/io/32-udp.js [new file with mode: 0644]
dgbuilder/core_nodes/io/lib/mqtt.js [new file with mode: 0644]
dgbuilder/core_nodes/io/lib/mqttConnectionPool.js [new file with mode: 0644]
dgbuilder/core_nodes/logic/10-switch.html [new file with mode: 0644]
dgbuilder/core_nodes/logic/10-switch.js [new file with mode: 0644]
dgbuilder/core_nodes/logic/15-change.html [new file with mode: 0644]
dgbuilder/core_nodes/logic/15-change.js [new file with mode: 0644]
dgbuilder/core_nodes/logic/16-range.html [new file with mode: 0644]
dgbuilder/core_nodes/logic/16-range.js [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-CSV.html [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-CSV.js [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-HTML.html [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-HTML.js [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-JSON.html [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-JSON.js [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-XML.html [new file with mode: 0644]
dgbuilder/core_nodes/parsers/70-XML.js [new file with mode: 0644]
dgbuilder/core_nodes/social/27-twitter.html [new file with mode: 0644]
dgbuilder/core_nodes/social/27-twitter.js [new file with mode: 0644]
dgbuilder/core_nodes/social/32-feedparse.html [new file with mode: 0644]
dgbuilder/core_nodes/social/32-feedparse.js [new file with mode: 0644]
dgbuilder/core_nodes/social/61-email.html [new file with mode: 0644]
dgbuilder/core_nodes/social/61-email.js [new file with mode: 0644]
dgbuilder/core_nodes/social/91-irc.html [new file with mode: 0644]
dgbuilder/core_nodes/social/91-irc.js [new file with mode: 0644]
dgbuilder/core_nodes/storage/28-tail.html [new file with mode: 0644]
dgbuilder/core_nodes/storage/28-tail.js [new file with mode: 0644]
dgbuilder/core_nodes/storage/50-file.html [new file with mode: 0644]
dgbuilder/core_nodes/storage/50-file.js [new file with mode: 0644]
dgbuilder/core_nodes/storage/65-redisout.html [new file with mode: 0644]
dgbuilder/core_nodes/storage/65-redisout.js [new file with mode: 0644]
dgbuilder/core_nodes/storage/66-mongodb.html [new file with mode: 0644]
dgbuilder/core_nodes/storage/66-mongodb.js [new file with mode: 0644]
dgbuilder/createReleaseDir.sh [new file with mode: 0755]
dgbuilder/flowShareUsers.js [new file with mode: 0644]
dgbuilder/generatedJS/.gitignore [new file with mode: 0644]
dgbuilder/git_scripts/gitcheckout [new file with mode: 0755]
dgbuilder/git_scripts/gitckout [new file with mode: 0755]
dgbuilder/git_scripts/gitcurbranch [new file with mode: 0755]
dgbuilder/git_scripts/gitlog [new file with mode: 0755]
dgbuilder/git_scripts/gitpull [new file with mode: 0755]
dgbuilder/git_scripts/gitstatus [new file with mode: 0755]
dgbuilder/nodes/99-sample.html.demo [new file with mode: 0644]
dgbuilder/nodes/99-sample.js.demo [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/block.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/block.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/breakNode.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/breakNode.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/call.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/call.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/configure.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/configure.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/delete.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/delete.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/execute.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/execute.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/exists.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/exists.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/forNode.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/forNode.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/get-resource.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/get-resource.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/is-available.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/is-available.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/notify.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/notify.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/record.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/record.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/release.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/release.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/reserve.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/reserve.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/save.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/save.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/set.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/set.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/switchNode.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/switchNode.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/update.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgelogic/update.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/GenericXML.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/GenericXML.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/comment.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/comment.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/dgstart.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/dgstart.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/method.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/method.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/serviceLogic.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgemain/serviceLogic.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/already-active.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/already-active.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/failure.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/failure.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/not-found.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/not-found.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/other.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/other.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcome.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcome.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/success.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgeoutcome/success.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgereturn/returnFailure.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgereturn/returnFailure.js [new file with mode: 0644]
dgbuilder/nodes/dge/dgereturn/returnSuccess.html [new file with mode: 0644]
dgbuilder/nodes/dge/dgereturn/returnSuccess.js [new file with mode: 0644]
dgbuilder/package.json [new file with mode: 0644]
dgbuilder/pom.xml [new file with mode: 0644]
dgbuilder/public/bootstrap/css/bootstrap.min.css [new file with mode: 0644]
dgbuilder/public/bootstrap/img/glyphicons-halflings-white.png [new file with mode: 0644]
dgbuilder/public/bootstrap/img/glyphicons-halflings.png [new file with mode: 0644]
dgbuilder/public/bootstrap/js/bootstrap.min.js [new file with mode: 0644]
dgbuilder/public/d3.v3.min.js [new file with mode: 0644]
dgbuilder/public/favicon.ico [new file with mode: 0644]
dgbuilder/public/font-awesome/css/font-awesome.min.css [new file with mode: 0644]
dgbuilder/public/font-awesome/fonts/FontAwesome.otf [new file with mode: 0644]
dgbuilder/public/font-awesome/fonts/fontawesome-webfont.eot [new file with mode: 0755]
dgbuilder/public/font-awesome/fonts/fontawesome-webfont.svg [new file with mode: 0755]
dgbuilder/public/font-awesome/fonts/fontawesome-webfont.ttf [new file with mode: 0755]
dgbuilder/public/font-awesome/fonts/fontawesome-webfont.woff [new file with mode: 0755]
dgbuilder/public/grip.png [new file with mode: 0644]
dgbuilder/public/icons/alert.png [new file with mode: 0644]
dgbuilder/public/icons/arduino.png [new file with mode: 0644]
dgbuilder/public/icons/arrow-in.png [new file with mode: 0644]
dgbuilder/public/icons/bridge-dash.png [new file with mode: 0644]
dgbuilder/public/icons/bridge.png [new file with mode: 0644]
dgbuilder/public/icons/comment.png [new file with mode: 0644]
dgbuilder/public/icons/db.png [new file with mode: 0644]
dgbuilder/public/icons/debug.png [new file with mode: 0644]
dgbuilder/public/icons/envelope.png [new file with mode: 0644]
dgbuilder/public/icons/feed.png [new file with mode: 0644]
dgbuilder/public/icons/file.png [new file with mode: 0644]
dgbuilder/public/icons/function.png [new file with mode: 0644]
dgbuilder/public/icons/hash.png [new file with mode: 0644]
dgbuilder/public/icons/inject.png [new file with mode: 0644]
dgbuilder/public/icons/leveldb.png [new file with mode: 0644]
dgbuilder/public/icons/light.png [new file with mode: 0644]
dgbuilder/public/icons/mongodb.png [new file with mode: 0644]
dgbuilder/public/icons/node-changed.png [new file with mode: 0644]
dgbuilder/public/icons/node-error.png [new file with mode: 0644]
dgbuilder/public/icons/range.png [new file with mode: 0644]
dgbuilder/public/icons/redis.png [new file with mode: 0644]
dgbuilder/public/icons/rpi.png [new file with mode: 0644]
dgbuilder/public/icons/serial.png [new file with mode: 0644]
dgbuilder/public/icons/swap.png [new file with mode: 0644]
dgbuilder/public/icons/switch.png [new file with mode: 0644]
dgbuilder/public/icons/template.png [new file with mode: 0644]
dgbuilder/public/icons/timer.png [new file with mode: 0644]
dgbuilder/public/icons/trigger.png [new file with mode: 0644]
dgbuilder/public/icons/twitter.png [new file with mode: 0644]
dgbuilder/public/icons/watch.png [new file with mode: 0644]
dgbuilder/public/icons/white-globe.png [new file with mode: 0644]
dgbuilder/public/images/dgstart.png [new file with mode: 0644]
dgbuilder/public/images/page-loading.gif [new file with mode: 0644]
dgbuilder/public/index.html [new file with mode: 0644]
dgbuilder/public/index.html.orig [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/animated-overlay.gif [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-icons_222222_256x240.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-icons_454545_256x240.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-icons_888888_256x240.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png [new file with mode: 0644]
dgbuilder/public/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css [new file with mode: 0644]
dgbuilder/public/jquery/js/jquery-1.11.1.min.js [new file with mode: 0644]
dgbuilder/public/jquery/js/jquery-ui-1.10.3.custom.min.js [new file with mode: 0644]
dgbuilder/public/jquery/js/jquery.ui.touch-punch.min.js [new file with mode: 0644]
dgbuilder/public/node-red.png [new file with mode: 0644]
dgbuilder/public/orion/built-editor.css [new file with mode: 0644]
dgbuilder/public/orion/built-editor.min.js [new file with mode: 0644]
dgbuilder/public/pw_maze_white.png [new file with mode: 0644]
dgbuilder/public/red/comms.js [new file with mode: 0644]
dgbuilder/public/red/history.js [new file with mode: 0644]
dgbuilder/public/red/main.js [new file with mode: 0644]
dgbuilder/public/red/main.js.orig [new file with mode: 0644]
dgbuilder/public/red/nodes.js [new file with mode: 0644]
dgbuilder/public/red/ui/editor.js [new file with mode: 0644]
dgbuilder/public/red/ui/keyboard.js [new file with mode: 0644]
dgbuilder/public/red/ui/library.js [new file with mode: 0644]
dgbuilder/public/red/ui/menu.js [new file with mode: 0644]
dgbuilder/public/red/ui/notifications.js [new file with mode: 0644]
dgbuilder/public/red/ui/palette.js [new file with mode: 0644]
dgbuilder/public/red/ui/sidebar.js [new file with mode: 0644]
dgbuilder/public/red/ui/state.js [new file with mode: 0644]
dgbuilder/public/red/ui/tab-config.js [new file with mode: 0644]
dgbuilder/public/red/ui/tab-info.js [new file with mode: 0644]
dgbuilder/public/red/ui/tabs.js [new file with mode: 0644]
dgbuilder/public/red/ui/touch/radialMenu.js [new file with mode: 0644]
dgbuilder/public/red/ui/view.js [new file with mode: 0644]
dgbuilder/public/red/ui/view.js.orig [new file with mode: 0644]
dgbuilder/public/red/validators.js [new file with mode: 0644]
dgbuilder/public/spin.svg [new file with mode: 0644]
dgbuilder/public/style.css [new file with mode: 0644]
dgbuilder/public/style.css.orig [new file with mode: 0644]
dgbuilder/public/util/css/validateNodeXml.css [new file with mode: 0644]
dgbuilder/public/util/js/dgeToXml.js [new file with mode: 0644]
dgbuilder/public/util/js/dgeToXml.js.imp [new file with mode: 0644]
dgbuilder/public/util/js/jsonTool.js [new file with mode: 0644]
dgbuilder/public/util/js/migrateFlow.js [new file with mode: 0644]
dgbuilder/public/util/js/sliValues.js [new file with mode: 0644]
dgbuilder/public/util/js/validateNodeXml.js [new file with mode: 0644]
dgbuilder/public/util/js/vkbeautify.0.99.00.beta.js [new file with mode: 0644]
dgbuilder/red.js [new file with mode: 0644]
dgbuilder/red/cli/lib/config.js [new file with mode: 0644]
dgbuilder/red/cli/lib/request.js [new file with mode: 0644]
dgbuilder/red/cli/nr-cli.js [new file with mode: 0755]
dgbuilder/red/comms.js [new file with mode: 0644]
dgbuilder/red/events.js [new file with mode: 0644]
dgbuilder/red/library.js [new file with mode: 0644]
dgbuilder/red/log.js [new file with mode: 0644]
dgbuilder/red/nodes/Node.js [new file with mode: 0644]
dgbuilder/red/nodes/credentials.js [new file with mode: 0644]
dgbuilder/red/nodes/flows.js [new file with mode: 0644]
dgbuilder/red/nodes/index.js [new file with mode: 0644]
dgbuilder/red/nodes/registry.js [new file with mode: 0644]
dgbuilder/red/red.js [new file with mode: 0644]
dgbuilder/red/server.js [new file with mode: 0644]
dgbuilder/red/settings.js [new file with mode: 0644]
dgbuilder/red/sla.js [new file with mode: 0644]
dgbuilder/red/storage/index.js [new file with mode: 0644]
dgbuilder/red/storage/localfilesystem.js [new file with mode: 0644]
dgbuilder/red/ui.js [new file with mode: 0644]
dgbuilder/red/util.js [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/.config.json [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/codecloud/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/conf/svclogic.properties [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/customSettings.js [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/flows/shared/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/flows/shared/backups/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/html/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/lib/flows/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/logs/.gitignore [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/logs/process_pid [new file with mode: 0644]
dgbuilder/releases/sdnc1.0/xml/.gitignore [new file with mode: 0644]
dgbuilder/show_status.sh [new file with mode: 0755]
dgbuilder/src/assembly/assemble_zip.xml [new file with mode: 0644]
dgbuilder/start.sh [new file with mode: 0755]
dgbuilder/stop.sh [new file with mode: 0755]
dgbuilder/svclogic/copy_xml.sh [new file with mode: 0755]
dgbuilder/svclogic/dg.xml [new file with mode: 0644]
dgbuilder/svclogic/lib/.gitignore [new file with mode: 0644]
dgbuilder/svclogic/load_dg [new file with mode: 0755]
dgbuilder/svclogic/svclogic.properties [new file with mode: 0644]
dgbuilder/svclogic/svclogic.sh [new file with mode: 0755]
dgbuilder/test/_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/20-inject_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/58-debug_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/80-function_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/80-template_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/89-delay_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/core/90-comment_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/logic/10-switch_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/logic/15-change_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/logic/16-range_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/parsers/70-HTML_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/parsers/70-JSON_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/parsers/70-XML_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/core/storage/28-tail_spec.js [new file with mode: 0644]
dgbuilder/test/nodes/helper.js [new file with mode: 0644]
dgbuilder/test/red/cli/lib/config_spec.js [new file with mode: 0644]
dgbuilder/test/red/cli/lib/request_spec.js [new file with mode: 0644]
dgbuilder/test/red/cli/nr-cli_spec.js [new file with mode: 0644]
dgbuilder/test/red/comms_spec.js [new file with mode: 0644]
dgbuilder/test/red/events_spec.js [new file with mode: 0644]
dgbuilder/test/red/library_spec.js [new file with mode: 0644]
dgbuilder/test/red/log_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/Node_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/credentials_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/flows_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/index_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/registry_spec.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/icons/file.txt [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.js [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.html [new file with mode: 0644]
dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.js [new file with mode: 0644]
dgbuilder/test/red/red_spec.js [new file with mode: 0644]
dgbuilder/test/red/server_spec.js [new file with mode: 0644]
dgbuilder/test/red/settings_spec.js [new file with mode: 0644]
dgbuilder/test/red/storage/index_spec.js [new file with mode: 0644]
dgbuilder/test/red/storage/localfilesystem_spec.js [new file with mode: 0644]
dgbuilder/test/red/ui_spec.js [new file with mode: 0644]
dgbuilder/test/red/util_spec.js [new file with mode: 0644]
dgbuilder/test/resources/70-HTML-test-file.html [new file with mode: 0644]
dgbuilder/tools/FormatXml.java [new file with mode: 0644]
dgbuilder/tools/PrintYangToProp.java [new file with mode: 0644]
dgbuilder/tools/dot_to_json.js [new file with mode: 0644]
dgbuilder/tools/formatXml.py [new file with mode: 0644]
dgbuilder/tools/format_json.sh [new file with mode: 0755]
dgbuilder/tools/format_xml.sh [new file with mode: 0755]
dgbuilder/tools/generate_props_from_yang.sh [new file with mode: 0755]
dgbuilder/tools/getModuleName.sh [new file with mode: 0755]
dgbuilder/tools/getRpcsClassFromYang.sh [new file with mode: 0755]
dgbuilder/tools/jsonTool.js [new file with mode: 0644]
dgbuilder/tools/json_to_html [new file with mode: 0644]
dgbuilder/tools/json_to_html_table [new file with mode: 0755]
dgbuilder/tools/json_to_prop [new file with mode: 0755]
dgbuilder/tools/output_js/.gitignore [new file with mode: 0644]
dgbuilder/tools/pom.xml_base [new file with mode: 0644]
dgbuilder/tools/printYangProps.sh [new file with mode: 0755]
dgbuilder/tools/printYangToProp.jar [new file with mode: 0644]
dgbuilder/tools/rs [new file with mode: 0755]
dgbuilder/tools/setClasspath [new file with mode: 0755]
dgbuilder/yangFiles/.gitignore [new file with mode: 0644]
pom.xml

diff --git a/dgbuilder/.gitignore b/dgbuilder/.gitignore
new file mode 100644 (file)
index 0000000..1b8a6ba
--- /dev/null
@@ -0,0 +1,12 @@
+org.eclipse.core.resources.prefs
+.classpath\r
+.project\r
+.settings\r
+.idea\r
+.externalToolBuilders\r
+maven-eclipse.xml\r
+*.class\r
+target/\r
+MANIFEST.MF\r
+.DS_STORE\r
+.metadata\r
diff --git a/dgbuilder/CONTRIBUTING.md b/dgbuilder/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..52fe891
--- /dev/null
@@ -0,0 +1,82 @@
+# Contributing to Node-RED
+
+We welcome contributions, but request you follow these guidelines.
+
+## Raising issues
+
+Please raise any bug reports on the project's 
+[issue tracker](https://github.com/node-red/node-red/issues?state=open). Be sure to
+search the list to see if your issue has already been raised.
+
+A good bug report is one that make it easy for us to understand what you were
+trying to do and what went wrong.
+
+Provide as much context as possible so we can try to recreate the issue.
+If possible, include the relevant part of your flow. To do this, select the
+relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
+
+At a minimum, please include:
+
+ - Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
+ - Version of node.js - what does `node -v` say?
+
+
+## New features
+
+For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
+
+## Pull-Requests
+
+### Changes to existing code
+if you want to raise a pull-request with a new feature, or a refactoring
+of existing code, it may well get rejected if you haven't discussed it on 
+the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
+
+### New nodes
+
+The plugin nature of Node-RED means anyone can create a new node to extend
+its capabilities.
+
+We want to avoid duplication as that can lead to confusion. Many of our existing
+nodes offer a starting point of functionality. If they are missing features,
+we would rather extend them than add separate 'advanced' versions. But the key
+to that approach is getting the UX right to not lose the simplicity.
+
+To contribute a new node, please raise a pull-request against the 
+`node-red-nodes` repository.
+
+Eventually, the nodes will be npm-installable, but we're not there yet. We'll
+also have some sort of registry of nodes to help with discoverability.
+
+### Coding standards
+
+Please ensure you follow the coding standards used through-out the existing
+code base. Some basic rules include:
+
+ - all files must have the Apache license in the header.
+ - indent with 4-spaces, no tabs. No arguments.
+ - opening brace on same line as `if`/`for`/`function`/etc, closing brace on its
+   own line.
+
+### Contributor License Aggreement
+
+In order for us to accept pull-requests, the contributor must first complete
+a Contributor License Agreement (CLA). This clarifies the intellectual 
+property license granted with any contribution. It is for your protection as a 
+Contributor as well as the protection of IBM and its customers; it does not 
+change your rights to use your own Contributions for any other purpose.
+
+You can download the CLAs here:
+
+ - [individual](http://nodered.org/cla/node-red-cla-individual.pdf)
+ - [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf)
+
+If you are an IBMer, please contact us directly as the contribution process is
+slightly different.
+
+
+
+
+
+
+
diff --git a/dgbuilder/Gruntfile.js b/dgbuilder/Gruntfile.js
new file mode 100644 (file)
index 0000000..62a553f
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(grunt) {
+    
+    // Project configuration.
+    grunt.initConfig({
+            pkg: grunt.file.readJSON('package.json'),
+            simplemocha: {
+                options: {
+                    globals: ['expect'],
+                    timeout: 3000,
+                    ignoreLeaks: false,
+                    ui: 'bdd',
+                    reporter: 'spec'
+                },
+                all: { src: ['test/**/*_spec.js'] },
+                core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
+                nodes: { src: ["test/nodes/**/*_spec.js"]}
+            },
+            jshint: {
+                options: {
+                    // http://www.jshint.com/docs/options/
+                    "asi": true,      // allow missing semicolons
+                    "curly": true,    // require braces
+                    "eqnull": true,   // ignore ==null
+                    "forin": true,    // require property filtering in "for in" loops
+                    "immed": true,    // require immediate functions to be wrapped in ( )
+                    "nonbsp": true,   // warn on unexpected whitespace breaking chars
+                    //"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
+                    "loopfunc": true, // allow functions to be defined in loops
+                    "sub": true       // don't warn that foo['bar'] should be written as foo.bar
+                },
+                all: [
+                    'Gruntfile.js',
+                    'red.js',
+                    'red/**/*.js',
+                    'nodes/**/*.js',
+                    'public/red/**/*.js'
+                ],
+                
+                core: {
+                    files: {
+                        src: [
+                            'Gruntfile.js',
+                            'red.js',
+                            'red/**/*.js'
+                        ]
+                    }
+                },
+                nodes: {
+                    files: {
+                        src: [ 'nodes/**/*.js' ]
+                    }
+                },
+                editor: {
+                    files: {
+                        src: [ 'public/red/**/*.js' ]
+                    }
+                },
+                tests: {
+                    files: {
+                        src: ['test/**/*.js']
+                    },
+                    options: {
+                        "expr": true
+                    }
+                }
+                
+            }
+    });
+    
+    grunt.loadNpmTasks('grunt-simple-mocha');
+    grunt.loadNpmTasks('grunt-contrib-jshint');
+    
+    grunt.registerTask('default', ['jshint:core','jshint:tests','jshint:editor','simplemocha:core','simplemocha:nodes']);
+    
+};
diff --git a/dgbuilder/INSTALL.md b/dgbuilder/INSTALL.md
new file mode 100644 (file)
index 0000000..90922e6
--- /dev/null
@@ -0,0 +1,57 @@
+Node-RED Install
+================
+
+## Install node.js
+
+You can get the latest version from <http://nodejs.org/download/>.
+
+Or, you may want to use a version from your operating system's package manager:
+ <https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager>
+
+## Get Node-RED
+
+Clone the repository from GitHub:
+
+    $ git clone git@github.com:node-red/node-red.git
+
+## Install the pre-requisite modules
+
+From the top-level directory of Node-RED, run:
+
+    $ npm install
+
+This will install the core pre-requisite modules.
+
+## Run Node-RED
+
+From the top-level directory, run:
+
+    $ node red.js
+
+You can then access Node-RED at <http://localhost:1880>.
+
+Online documentation is available at <http://nodered.org/docs>.
+
+## Installing individual node dependencies
+
+When Node-RED starts, it attempts to load the nodes from the `nodes/` directory.
+Each will have its own set of dependencies that will need to be installed before
+the node is available in the palette.
+
+To help identify the dependencies, Node-RED logs any modules it fails to find
+for a particular node. You don't have to install these unless you want or need
+that node to appear.
+
+Alternatively, a node's `.js` file can be examined to identify the modules it
+explicitly requires. For example, the Twitter node is defined in
+`nodes/social/27-twitter.js` and contains:
+
+       var RED = require("../../red/red");
+       var ntwitter = require('ntwitter');
+       var OAuth= require('oauth').OAuth;
+
+Of these, `ntwitter` and `oauth` are neither built-in modules nor ones provided
+by Node-RED itself. They can subsequently be installed by running:
+
+    $ npm install ntwitter oauth
+
diff --git a/dgbuilder/LICENSE b/dgbuilder/LICENSE
new file mode 100644 (file)
index 0000000..f433b1a
--- /dev/null
@@ -0,0 +1,177 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
diff --git a/dgbuilder/build_pom_for_yang_compile b/dgbuilder/build_pom_for_yang_compile
new file mode 100755 (executable)
index 0000000..c9aa38a
--- /dev/null
@@ -0,0 +1,86 @@
+echo "Version of dgbuilder pom is : $4"
+echo "Building pom.xml_base for compiling yang"
+
+model_pom_content=$(cat <<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.onap.ccsdk.distribution</groupId>
+               <artifactId>distribution-root</artifactId>      
+                <version>${1}</version>
+       </parent>
+       <artifactId>yangApp-model</artifactId>
+       <packaging>bundle</packaging>
+        <version>1.0.0-SNAPSHOT</version>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Import-Package>*</Import-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-maven-plugin</artifactId>
+                               <version>\${odl.yangtools.yang.maven.plugin.version}</version>
+                               <dependencies>
+                                       <dependency>
+                                               <groupId>org.opendaylight.mdsal</groupId>
+                                               <artifactId>maven-sal-api-gen-plugin</artifactId>
+                                               <version>\${odl.sal.api.gen.plugin.version}</version>
+                                               <type>jar</type>
+                                       </dependency>
+                               </dependencies>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>generate-sources</goal>
+                                               </goals>
+                                               <configuration>
+                                                       <yangFilesRootDir>\${yang.file.directory}</yangFilesRootDir>
+                                                       <codeGenerators>
+                                                               <generator>
+                                                                       <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                                                       <outputBaseDir>\${salGeneratorPath}</outputBaseDir>
+                                                               </generator>
+                                                       </codeGenerators>
+                                                       <inspectDependencies>true</inspectDependencies>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal</groupId>
+                       <artifactId>yang-binding</artifactId>
+                       <version>\${odl.mdsal.yang.binding.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.yangtools</groupId>
+                       <artifactId>yang-common</artifactId>
+                       <version>\${odl.yangtools.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal.model</groupId>
+                       <artifactId>ietf-inet-types</artifactId>
+                       <version>\${odl.ietf-inet-types.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal.model</groupId>
+                       <artifactId>ietf-yang-types</artifactId>
+                       <version>\${odl.ietf-yang-types.version}</version>
+               </dependency>
+       </dependencies>
+</project>
+EOF
+)
+echo "$model_pom_content" >tools/pom.xml_base
diff --git a/dgbuilder/core_nodes/analysis/72-sentiment.html b/dgbuilder/core_nodes/analysis/72-sentiment.html
new file mode 100644 (file)
index 0000000..c33b873
--- /dev/null
@@ -0,0 +1,49 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="sentiment">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="sentiment">
+    <p>Analyses the <b>msg.payload</b> and adds a <b>msg.sentiment</b> object that contains the resulting AFINN-111 sentiment score as <b>msg.sentiment.score</b>.</p>
+    <p>A score greater than zero is positive and less than zero is negative.</p>
+    <p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
+    <p>An object of word score overrides can be supplied as <b>msg.overrides</b>.</p>
+    <p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_new">the Sentiment docs here</a>.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('sentiment',{
+        category: 'analysis-function',
+        color:"#E6E0F8",
+        defaults: {
+            name: {value:""},
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name||"sentiment";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/analysis/72-sentiment.js b/dgbuilder/core_nodes/analysis/72-sentiment.js
new file mode 100644 (file)
index 0000000..747e079
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var sentiment = require('sentiment');
+
+    function SentimentNode(n) {
+        RED.nodes.createNode(this,n);
+        var node = this;
+
+        this.on("input", function(msg) {
+            sentiment(msg.payload, msg.overrides || null, function (err, result) {
+                msg.sentiment = result;
+                node.send(msg);
+            });
+        });
+    }
+    RED.nodes.registerType("sentiment",SentimentNode);
+}
diff --git a/dgbuilder/core_nodes/core/20-inject.html b/dgbuilder/core_nodes/core/20-inject.html
new file mode 100644 (file)
index 0000000..38aa6ef
--- /dev/null
@@ -0,0 +1,437 @@
+<!--\r
+  Copyright 2013 IBM Corp.\r
+\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+\r
+  http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+-->\r
+\r
+<script type="text/x-red" data-template-name="inject">\r
+    <div class="form-row node-input-payload">\r
+        <label for="node-input-payloadType"><i class="fa fa-envelope"></i> Payload</label>\r
+        <select id="node-input-payloadType" style="width:125px !important">\r
+          <option value="date">timestamp</option>\r
+          <option value="none">blank</option>\r
+          <option value="string">string</option>\r
+        </select>\r
+    </div>\r
+\r
+    <div class="form-row" id="node-input-row-payload">\r
+        <label for="node-input-payload"></label>\r
+        <input type="text" id="node-input-payload" placeholder="payload">\r
+    </div>\r
+\r
+    <div class="form-row">\r
+        <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>\r
+        <input type="text" id="node-input-topic" placeholder="topic">\r
+    </div>\r
+\r
+    <div class="form-row">\r
+        <label for=""><i class="fa fa-repeat"></i> Repeat</label>\r
+        <select id="inject-time-type-select"  style="width: 288px"><option value="none">none</option><option value="interval">interval</option><option value="interval-time">interval between times</option><option value="time">at a specific time</option></select>\r
+        <input type="hidden" id="node-input-repeat" placeholder="payload">\r
+        <input type="hidden" id="node-input-crontab" placeholder="payload">\r
+    </div>\r
+\r
+    <div class="form-row inject-time-row hidden" id="inject-time-row-interval">\r
+        every <input id="inject-time-interval-count" class="inject-time-count" value="1"></input>\r
+              <select style="width: 100px" id="inject-time-interval-units"><option value="s">seconds</option><option value="m">minutes</option><option value="h">hours</option></select><br/>\r
+        <!-- on <select disabled id="inject-time-interval-days" class="inject-time-days"></select> -->\r
+    </div>\r
+\r
+    <div class="form-row inject-time-row hidden" id="inject-time-row-interval-time">\r
+        at every <select style="width: 90px" id="inject-time-interval-time-units" class="inject-time-int-count" value="1">\r
+            <option value="1">1</option>\r
+            <option value="2">2</option>\r
+            <option value="3">3</option>\r
+            <option value="4">4</option>\r
+            <option value="5">5</option>\r
+            <option value="6">6</option>\r
+            <option value="10">10</option>\r
+            <option value="12">12</option>\r
+            <option value="15">15</option>\r
+            <option value="20">20</option>\r
+            <option value="30">30</option>\r
+            <option value="0">60</option>\r
+        </select> minutes<br/>\r
+        between <select id="inject-time-interval-time-start" class="inject-time-times"></select>\r
+        and <select id="inject-time-interval-time-end" class="inject-time-times"></select><br/>\r
+        on <select id="inject-time-interval-time-days" class="inject-time-days"></select>\r
+    </div>\r
+\r
+    <div class="form-row inject-time-row hidden" id="inject-time-row-time">\r
+        at <input id="inject-time-time" value="12:00"></input><br/>\r
+        on <select id="inject-time-time-days" class="inject-time-days"></select>\r
+    </div>\r
+\r
+    <div class="form-row" id="node-once">\r
+        <label>&nbsp;</label>\r
+        <input type="checkbox" id="node-input-once" style="display: inline-block; width: auto; vertical-align: top;">\r
+        <label for="node-input-once" style="width: 70%;">Fire once at start ?</label>\r
+    </div>\r
+\r
+    <div class="form-row">\r
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>\r
+        <input type="text" id="node-input-name" placeholder="name">\r
+    </div>\r
+\r
+    <div class="form-tips"><b>Note:</b> "interval between times" and "at a specific time" will use cron.<br/>See info box for details.</div>\r
+</script>\r
+<style>\r
+    .inject-time-row {\r
+        padding-left: 110px;\r
+    }\r
+    .inject-time-row select {\r
+        margin: 3px 0;\r
+    }\r
+    .inject-time-days {\r
+        width: 262px;\r
+    }\r
+    .inject-time-times {\r
+        width: 90px;\r
+    }\r
+    .inject-time-row > .ui-spinner {\r
+        height: 28px;\r
+        margin: 3px 0;\r
+        border-color: rgb(204, 204, 204);\r
+    }\r
+    #inject-time-time {\r
+        margin-top: 3px;\r
+        width: 75px;\r
+    }\r
+    .inject-time-count {\r
+        width: 40px !important;\r
+    }\r
+</style>\r
+<script type="text/x-red" data-help-name="inject">\r
+    <p>Pressing the button on the left side of the node allows a message on a topic to be injected into the flow. This is mainly for test purposes.</p>\r
+    <p>If no payload is specified the payload is set to the current time in millisecs since 1970. This allows subsequent functions to perform time based actions.</p>\r
+    <p>The repeat function does what it says on the tin and continuously sends the payload every x seconds.</p>\r
+    <p>The Fire once at start option actually waits 50mS before firing to give other nodes a chance to instantiate properly.</p>\r
+    <p><b>Note: </b>"Interval between times" and "at a specific time" will use cron. This means that 20 minutes will be at the next hour, 20 minutes past and 40 minutes past - not in 20 minutes time.\r
+    If you want every 20 minutes from now - use the basic "interval" option.</p>\r
+</script>\r
+\r
+<script type="text/javascript">\r
+    RED.nodes.registerType('inject',{\r
+        category: 'input',\r
+        color:"#a6bbcf",\r
+        defaults: {\r
+            name: {value:""},\r
+            topic: {value:""},\r
+            payload: {value:""},\r
+            payloadType: {value:"date"},\r
+            repeat: {value:""},\r
+            crontab: {value:""},\r
+            once: {value:false}\r
+        },\r
+        inputs:0,\r
+        outputs:1,\r
+        icon: "inject.png",\r
+        label: function() {\r
+            if (this.payloadType === "string") {\r
+                return this.name||this.topic||this.payload||"inject";\r
+            }\r
+            else { return this.name||this.topic||"inject"; }\r
+        },\r
+        labelStyle: function() {\r
+            return this.name?"node_label_italic":"";\r
+        },\r
+        oneditprepare: function() {\r
+            $("#inject-time-type-select").change(function() {\r
+                $("#node-input-crontab").val('');\r
+                var id = $("#inject-time-type-select option:selected").val();\r
+                $(".inject-time-row").hide();\r
+                $("#inject-time-row-"+id).show();\r
+                if ((id == "none") || (id == "interval")) {\r
+                    $("#node-once").show();\r
+                }\r
+                else {\r
+                    $("#node-once").hide();\r
+                    $("#node-input-once").prop('checked', false);\r
+                }\r
+            });\r
+\r
+            var days = [\r
+                {v:"*",t:"every day"},\r
+                {v:"1-5",t:"Mondays to Fridays"},\r
+                {v:"0,6",t:"Saturdays and Sundays"},\r
+                {v:"1",t:"Mondays"},\r
+                {v:"2",t:"Tuesdays"},\r
+                {v:"3",t:"Wednesdays"},\r
+                {v:"4",t:"Thursdays"},\r
+                {v:"5",t:"Fridays"},\r
+                {v:"6",t:"Saturdays"},\r
+                {v:"0",t:"Sundays"}\r
+            ];\r
+\r
+            $(".inject-time-days").each(function() {\r
+                for (var d in days) {\r
+                    $(this).append($("<option></option>").val(days[d].v).text(days[d].t));\r
+                }\r
+            });\r
+\r
+            $(".inject-time-times").each(function() {\r
+                for (var i=0;i<24;i++) {\r
+                    var l = (i<10?"0":"")+i+":00";\r
+                    $(this).append($("<option></option>").val(i).text(l));\r
+                }\r
+            });\r
+\r
+            $(".inject-time-count").spinner({\r
+                //max:60,\r
+                min:1\r
+            });\r
+\r
+            $("#inject-time-interval-units").change(function() {\r
+                var units = $("#inject-time-interval-units option:selected").val();\r
+                //$("#inject-time-interval-days").prop("disabled",(units == "s")?"disabled":false);\r
+                //$(".inject-time-count").spinner("option","max",(units == "h")?24:60);\r
+            });\r
+\r
+            $.widget( "ui.injecttimespinner", $.ui.spinner, {\r
+                options: {\r
+                    // seconds\r
+                    step: 60 * 1000,\r
+                    // hours\r
+                    page: 60\r
+                },\r
+                _parse: function( value ) {\r
+                    if ( typeof value === "string" ) {\r
+                        // already a timestamp\r
+                        if ( Number( value ) == value ) {\r
+                            return Number( value );\r
+                        }\r
+                        var p = value.split(":");\r
+                        var offset = new Date().getTimezoneOffset();\r
+                        return (((Number(p[0])+1)*60)+Number(p[1])+offset)*60*1000;\r
+                    }\r
+                    return value;\r
+                },\r
+                _format: function( value ) {\r
+                    var d = new Date(value);\r
+                    var h = d.getHours();\r
+                    var m = d.getMinutes();\r
+                    return ((h < 10)?"0":"")+h+":"+((m < 10)?"0":"")+m;\r
+                }\r
+            });\r
+\r
+            $("#inject-time-time").injecttimespinner();\r
+\r
+            var repeattype = "none";\r
+            if (this.repeat != "" && this.repeat != 0) {\r
+                repeattype = "interval";\r
+                var r = "s";\r
+                var c = this.repeat;\r
+                if (this.repeat % 60 === 0) { r = "m"; c = c/60; }\r
+                if (this.repeat % 1440 === 0) { r = "h"; c = c/24; }\r
+                $("#inject-time-interval-count").val(c);\r
+                $("#inject-time-interval-units").val(r);\r
+                //$("#inject-time-interval-units option").filter(function() {return $(this).val() == "s";}).attr('selected',true);\r
+                $("#inject-time-interval-days").prop("disabled","disabled");\r
+            } else if (this.crontab) {\r
+                var cronparts = this.crontab.split(" ");\r
+                var days = cronparts[4];\r
+                if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {\r
+                    repeattype = "time";\r
+                    // Fixed time\r
+                    var time = cronparts[1]+":"+cronparts[0];\r
+                    $("#inject-time-time").val(time);\r
+                    $("#inject-time-type-select option").filter(function() {return $(this).val() == "s";}).attr('selected',true);\r
+                    $("#inject-time-time-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);\r
+                }\r
+                //else if (cronparts[0] == "0") {\r
+                //    // interval - hours\r
+                //    var hours = cronparts[1].slice(2);\r
+                //    repeattype = "interval";\r
+                //    $("#inject-time-interval-days").prop("disabled",false);\r
+                //    $("#inject-time-interval-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);\r
+                //    $("#inject-time-interval-count").val(hours)\r
+                //    $("#inject-time-interval-units option").filter(function() {return $(this).val() == "h";}).attr('selected',true);\r
+                //} else if (cronparts[1] == "*") {\r
+                //    // interval - minutes\r
+                //    var minutes = cronparts[0].slice(2);\r
+                //    repeattype = "interval";\r
+                //    $("#inject-time-interval-days").prop("disabled",false);\r
+                //    $("#inject-time-interval-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);\r
+                //    $("#inject-time-interval-count").val(minutes)\r
+                //    $("#inject-time-interval-units option").filter(function() {return $(this).val() == "m";}).attr('selected',true);\r
+                //}\r
+                else {\r
+                    repeattype = "interval-time";\r
+                    // interval - time period\r
+                    var minutes = cronparts[0].slice(2);\r
+                    if (minutes === "") { minutes = "0"; }\r
+                    $("#inject-time-interval-time-units").val(minutes);\r
+                    $("#inject-time-interval-time-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);\r
+                    var time = cronparts[1];\r
+                    var timeparts = time.split(",");\r
+                    var start;\r
+                    var end;\r
+                    if (timeparts.length == 1) {\r
+                        // 0 or 0-10\r
+                        var hours = timeparts[0].split("-");\r
+                        if (hours.length == 1) {\r
+                            if (hours[0] === "") {\r
+                                start = "0";\r
+                                end = "0";\r
+                            }\r
+                            else {\r
+                                start = hours[0];\r
+                                end = Number(hours[0])+1;\r
+                            }\r
+                        } else {\r
+                            start = hours[0];\r
+                            end = (Number(hours[1])+1)%24;\r
+                        }\r
+                    } else {\r
+                        // 23,0 or 17-23,0-10 or 23,0-2 or 17-23,0\r
+                        var startparts = timeparts[0].split("-");\r
+                        start = startparts[0];\r
+\r
+                        var endparts = timeparts[1].split("-");\r
+                        if (endparts.length == 1) {\r
+                            end = Number(endparts[0])+1;\r
+                        } else {\r
+                            end = Number(endparts[1])+1;\r
+                        }\r
+                    }\r
+                    $("#inject-time-interval-time-start option").filter(function() {return $(this).val() == start;}).attr('selected',true);\r
+                    $("#inject-time-interval-time-end option").filter(function() {return $(this).val() == end;}).attr('selected',true);\r
+\r
+                }\r
+            } else {\r
+                $("#inject-time-type-select option").filter(function() {return $(this).val() == "none";}).attr('selected',true);\r
+            }\r
+\r
+            $(".inject-time-row").hide();\r
+            $("#inject-time-type-select option").filter(function() {return $(this).val() == repeattype;}).attr('selected',true);\r
+            $("#inject-time-row-"+repeattype).show();\r
+\r
+            if (this.payloadType == null) {\r
+                if (this.payload == "") {\r
+                    this.payloadType = "date";\r
+                } else {\r
+                    this.payloadType = "string";\r
+                }\r
+            }\r
+\r
+            $("#node-input-payloadType").change(function() {\r
+                var id = $("#node-input-payloadType option:selected").val();\r
+                if (id == "string") {\r
+                    $("#node-input-row-payload").show();\r
+                } else {\r
+                    $("#node-input-row-payload").hide();\r
+                }\r
+            });\r
+            $("#node-input-payloadType").val(this.payloadType);\r
+            $("#node-input-payloadType").change();\r
+            $("#inject-time-type-select").change();\r
+\r
+        },\r
+        oneditsave: function() {\r
+            var repeat = "";\r
+            var crontab = "";\r
+            var type = $("#inject-time-type-select option:selected").val();\r
+            if (type == "none") {\r
+                // nothing\r
+            } else if (type == "interval") {\r
+                var count = $("#inject-time-interval-count").val();\r
+                var units = $("#inject-time-interval-units option:selected").val();\r
+                var days = $("#inject-time-interval-days option:selected").val();\r
+                if (units == "s") {\r
+                    repeat = count;\r
+                } else {\r
+                    if (units == "m") {\r
+                        //crontab = "*/"+count+" * * * "+days;\r
+                        repeat = count * 60;\r
+                    } else if (units == "h") {\r
+                        //crontab = "0 */"+count+" * * "+days;\r
+                        repeat = count * 60 * 24;\r
+                    }\r
+                }\r
+            } else if (type == "interval-time") {\r
+                var count = $("#inject-time-interval-time-units").val();\r
+                var startTime = Number($("#inject-time-interval-time-start option:selected").val());\r
+                var endTime = Number($("#inject-time-interval-time-end option:selected").val());\r
+                var days = $("#inject-time-interval-time-days option:selected").val();\r
+                var timerange = "*";\r
+                if (startTime == endTime) {\r
+                    //TODO: invalid\r
+                    repeat = "";\r
+                    crontab = "";\r
+                } else if (endTime == 0) {\r
+                    timerange = startTime+"-23";\r
+                } else if (startTime+1 < endTime) {\r
+                    timerange = startTime+"-"+(endTime-1);\r
+                } else if (startTime+1 == endTime) {\r
+                    timerange = startTime;\r
+                } else {\r
+                    var startpart = "";\r
+                    var endpart = "";\r
+                    if (startTime == 23) {\r
+                        startpart = "23";\r
+                    } else {\r
+                        startpart = startTime+"-23";\r
+                    }\r
+                    if (endTime == 1) {\r
+                        endpart = "0";\r
+                    } else {\r
+                        endpart = "0-"+(endTime-1);\r
+                    }\r
+                    timerange = startpart+","+endpart;\r
+                }\r
+                repeat = "";\r
+                if (count === "0") {\r
+                    crontab = count+" "+timerange+" * * "+days;\r
+                }\r
+                else {\r
+                    crontab = "*/"+count+" "+timerange+" * * "+days;\r
+                }\r
+            } else if (type == "time") {\r
+                var time = $("#inject-time-time").val();\r
+                var days = $("#inject-time-time-days option:selected").val();\r
+                var parts = time.split(":");\r
+                repeat = "";\r
+                crontab = parts[1]+" "+parts[0]+" * * "+days;\r
+            }\r
+\r
+            $("#node-input-repeat").val(repeat);\r
+            $("#node-input-crontab").val(crontab);\r
+\r
+        },\r
+        button: {\r
+            onclick: function() {\r
+                var label = (this.name||this.payload).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");\r
+                if (this.payloadType === "date") { label = "timestamp"; }\r
+                if (this.payloadType === "none") { label = "blank"; }\r
+                d3.xhr("inject/"+this.id).post(function(err,resp) {\r
+                        if (err) {\r
+                            if (err.status == 404) {\r
+                                RED.notify("<strong>Error</strong>: inject node not deployed","error");\r
+                            } else if (err.status == 500) {\r
+                                RED.notify("<strong>Error</strong>: inject failed, see log for details.","error");\r
+                            } else if (err.status == 0) {\r
+                                RED.notify("<strong>Error</strong>: no response from server","error");\r
+                            } else {\r
+                                RED.notify("<strong>Error</strong>: unexpected error: ("+err.status+")"+err.response,"error");\r
+                            }\r
+                        } else if (resp.status == 200) {\r
+                            RED.notify("Successfully injected: "+label,"success");\r
+                        } else {\r
+                            RED.notify("<strong>Error</strong>: unexpected response: ("+resp.status+") "+resp.response,"error");\r
+                        }\r
+                });\r
+            }\r
+        }\r
+    });\r
+\r
+</script>\r
diff --git a/dgbuilder/core_nodes/core/20-inject.js b/dgbuilder/core_nodes/core/20-inject.js
new file mode 100644 (file)
index 0000000..dff0fb6
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    var cron = require("cron");
+    
+    function InjectNode(n) {
+        RED.nodes.createNode(this,n);
+        this.topic = n.topic;
+        this.payload = n.payload;
+        this.payloadType = n.payloadType;
+        this.repeat = n.repeat;
+        this.crontab = n.crontab;
+        this.once = n.once;
+        var node = this;
+        this.interval_id = null;
+        this.cronjob = null;
+    
+        if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
+            this.repeat = this.repeat * 1000;
+            this.log("repeat = "+this.repeat);
+            this.interval_id = setInterval( function() {
+                node.emit("input",{});
+            }, this.repeat );
+        } else if (this.crontab) {
+            if (cron) {
+                this.log("crontab = "+this.crontab);
+                this.cronjob = new cron.CronJob(this.crontab,
+                    function() {
+                        node.emit("input",{});
+                    },
+                    null,true);
+            } else {
+                this.error("'cron' module not found");
+            }
+        }
+    
+        if (this.once) {
+            setTimeout( function(){ node.emit("input",{}); }, 100);
+        }
+    
+        this.on("input",function(msg) {
+            var msg = {topic:this.topic};
+            if ( (this.payloadType == null && this.payload == "") || this.payloadType == "date") {
+                msg.payload = Date.now();
+            } else if (this.payloadType == null || this.payloadType == "string") {
+                msg.payload = this.payload;
+            } else {
+                msg.payload = "";
+            }
+            this.send(msg);
+            msg = null;
+        });
+    }
+    
+    RED.nodes.registerType("inject",InjectNode);
+    
+    InjectNode.prototype.close = function() {
+        if (this.interval_id != null) {
+            clearInterval(this.interval_id);
+            this.log("inject: repeat stopped");
+        } else if (this.cronjob != null) {
+            this.cronjob.stop();
+            this.log("inject: cronjob stopped");
+            delete this.cronjob;
+        }
+    }
+    
+    RED.httpAdmin.post("/inject/:id", function(req,res) {
+            var node = RED.nodes.getNode(req.params.id);
+            if (node != null) {
+                try {
+                    node.receive();
+                    res.send(200);
+                } catch(err) {
+                    res.send(500);
+                    node.error("Inject failed:"+err);
+                    console.log(err.stack);
+                }
+            } else {
+                res.send(404);
+            }
+    });
+}
diff --git a/dgbuilder/core_nodes/core/58-debug.html b/dgbuilder/core_nodes/core/58-debug.html
new file mode 100644 (file)
index 0000000..04aa507
--- /dev/null
@@ -0,0 +1,248 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="debug">
+    <div class="form-row">
+        <label for="node-input-complete"><i class="fa fa-list"></i> Output</label>
+        <select type="text" id="node-input-complete" style="display: inline-block; width: 250px; vertical-align: top;">
+            <option value="false">payload only</option>
+            <option value="true">complete msg object</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-console"><i class="fa fa-random"></i> to</label>
+        <select type="text" id="node-input-console" style="display: inline-block; width: 250px; vertical-align: top;">
+            <option value="false">debug tab</option>
+            <option value="true">debug tab and console</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="debug">
+    <p>The Debug node can be connected to the output of any node. It will display the timestamp, <b>msg.topic</b> and <b>msg.payload</b> fields of any messages it receives in the debug tab of the sidebar.
+    <br/>The sidebar can be accessed under the options drop-down in the top right corner.</p>
+    <p>The button to the right of the node will toggle it's output on and off so you can de-clutter the debug window.</p>
+    <p>If the payload is an object it will be stringified first for display and indicate that by saying "(Object) ".</p>
+    <p>If the payload is a buffer it will be stringified first for display and indicate that by saying "(Buffer) ".</p>
+    <p>Selecting any particular message will highlight (in red) the debug node that reported it. This is useful if you wire up multiple debug nodes.</p>
+    <p>Optionally can show the complete msg object - but the screen can get messy.</p>
+    <p>In addition any calls to node.warn or node.error will appear here.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('debug',{
+        category: 'output',
+        defaults: {
+            name: {value:""},
+            active: {value:true},
+            console: {value:"false"},
+            complete: {value:"false"}
+        },
+        label: function() {
+            return this.name||"debug";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        color:"#87a980",
+        inputs:1,
+        outputs:0,
+        icon: "debug.png",
+        align: "right",
+        button: {
+            toggle: "active",
+            onclick: function() {
+                var label = this.name||"debug";
+                d3.xhr("debug/"+this.id+"/"+(this.active?"enable":"disable")).post(function(err,resp) {
+                    if (err) {
+                        if (err.status == 404) {
+                            RED.notify("<strong>Error</strong>: debug node not deployed","error");
+                        } else if (err.status == 0) {
+                            RED.notify("<strong>Error</strong>: no response from server","error");
+                        } else {
+                            RED.notify("<strong>Error</strong>: unexpected error: ("+err.status+")"+err.response,"error");
+                        }
+                    } else if (resp.status == 200) {
+                        RED.notify("Successfully activated: "+label,"success");
+                    } else if (resp.status == 201) {
+                        RED.notify("Successfully deactivated: "+label,"success");
+                    } else {
+                        RED.notify("<strong>Error</strong>: unexpected response: ("+resp.status+") "+resp.response,"error");
+                    }
+                });
+            }
+        },
+        onpaletteadd: function() {
+            var content = document.createElement("div");
+            content.id = "tab-debug";
+    
+            var toolbar = document.createElement("div");
+            toolbar.id = "debug-toolbar";
+            content.appendChild(toolbar);
+    
+            toolbar.innerHTML = '<div class="btn-group pull-right"><a id="debug-tab-clear" title="clear log" class="btn btn-mini" href="#"><i class="fa fa-trash"></i></a></div> ';
+    
+            var messages = document.createElement("div");
+            messages.id = "debug-content";
+            content.appendChild(messages);
+    
+            RED.sidebar.addTab("debug",content);
+    
+            function getTimestamp() {
+                var d = new Date();
+                return d.toLocaleString();
+            }
+    
+            var sbc = document.getElementById("debug-content");
+    
+            var messageCount = 0;
+            var that = this;
+            RED._debug = function(msg) {
+                that.handleDebugMessage("",{
+                    name:"debug",
+                    msg:msg
+                });
+            }
+    
+            this.handleDebugMessage = function(t,o) {
+                var msg = document.createElement("div");
+                msg.onmouseover = function() {
+                    msg.style.borderRightColor = "#999";
+                    var n = RED.nodes.node(o.id);
+                    if (n) {
+                        n.highlighted = true;
+                        n.dirty = true;
+                    }
+                    RED.view.redraw();
+                };
+                msg.onmouseout = function() {
+                    msg.style.borderRightColor = "";
+                    var n = RED.nodes.node(o.id);
+                    if (n) {
+                        n.highlighted = false;
+                        n.dirty = true;
+                    }
+                    RED.view.redraw();
+                };
+                msg.onclick = function() {
+                    var node = RED.nodes.node(o.id);
+                    if (node) {
+                        RED.view.showWorkspace(node.z);
+                    }
+    
+                };
+                var name = (o.name?o.name:o.id).toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                var topic = (o.topic||"").toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                var payload = (o.msg||"").toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                msg.className = 'debug-message'+(o.level?(' debug-message-level-'+o.level):'');
+                msg.innerHTML = '<span class="debug-message-date">'+getTimestamp()+'</span>'+
+                                '<span class="debug-message-name">['+name+']</span>'+
+                                (o.topic?'<span class="debug-message-topic">'+topic+'</span>':'')+
+                                '<span class="debug-message-payload">'+payload+'</span>';
+                var atBottom = (sbc.scrollHeight-messages.offsetHeight-sbc.scrollTop) < 5;
+                messageCount++;
+                $(messages).append(msg);
+    
+                if (messageCount > 200) {
+                    $("#debug-content .debug-message:first").remove();
+                    messageCount--;
+                }
+                if (atBottom) {
+                    $(sbc).scrollTop(sbc.scrollHeight);
+                }
+            };
+            RED.comms.subscribe("debug",this.handleDebugMessage);
+    
+            $("#debug-tab-clear").click(function() {
+                $(".debug-message").remove();
+                messageCount = 0;
+                RED.nodes.eachNode(function(node) {
+                    node.highlighted = false;
+                    node.dirty = true;
+                });
+                RED.view.redraw();
+            });
+        },
+        onpaletteremove: function() {
+            RED.comms.unsubscribe("debug",this.handleDebugMessage);
+            RED.sidebar.removeTab("debug");
+            delete RED._debug;
+        }
+    });
+</script>
+
+<style>
+    #debug-content {
+        position: absolute;
+        top: 30px;
+        bottom: 0px;
+        left:0px;
+        right: 0px;
+        overflow-y: scroll;
+    }
+    #debug-toolbar {
+        padding: 3px 10px;
+        height: 24px;
+        background: #f3f3f3;
+    }
+    .debug-message {
+        cursor: pointer;
+        border-bottom: 1px solid #eee;
+        border-left: 8px solid #eee;
+        border-right: 8px solid #eee;
+        padding: 2px;
+    }
+    .debug-message-date {
+        background: #fff;
+        font-size: 9px;
+        color: #aaa;
+        padding: 1px 5px 1px 1px;
+    }
+    .debug-message-topic {
+        display: block;
+        background: #fff;
+        padding: 1px 5px;
+        font-size: 9px;
+        color: #a66;
+    }
+    .debug-message-name {
+        background: #fff;
+        padding: 1px 5px;
+        font-size: 9px;
+        color: #aac;
+    }
+    .debug-message-payload {
+        display: block;
+        padding: 2px;
+        background: #fff;
+    }
+    .debug-message-level-log {
+        border-left-color: #eee;
+        border-right-color: #eee;
+    }
+    .debug-message-level-warn {
+        border-left-color: #ffdf9d;
+        border-right-color: #ffdf9d;
+    }
+    .debug-message-level-error {
+        border-left-color: #f99;
+        border-right-color: #f99;
+    }
+</style>
diff --git a/dgbuilder/core_nodes/core/58-debug.js b/dgbuilder/core_nodes/core/58-debug.js
new file mode 100644 (file)
index 0000000..7436bf2
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    var util = require("util");
+    var events = require("events");
+    var debuglength = RED.settings.debugMaxLength||1000;
+    var useColors = false;
+    // util.inspect.styles.boolean = "red";
+    
+    function DebugNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.complete = n.complete;
+        this.console = n.console;
+        this.active = (n.active == null)||n.active;
+        var node = this;
+    
+        this.on("input",function(msg) {
+            if (this.complete == "true") { // debug complete msg object
+                if (this.console == "true") {
+                    node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
+                }
+                if (this.active) {
+                    sendDebug({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
+                }
+            } else { // debug just the msg.payload
+                if (this.console == "true") {
+                    if (typeof msg.payload === "string") {
+                        node.log((msg.payload.indexOf("\n") != -1 ? "\n" : "") + msg.payload);
+                    }
+                    else if (typeof msg.payload === "object") { node.log("\n"+util.inspect(msg.payload, {colors:useColors, depth:10})); }
+                    else { node.log(util.inspect(msg.payload, {colors:useColors})); }
+                }
+                if (this.active) {
+                    sendDebug({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path});
+                }
+            }
+        });
+    }
+   
+    RED.nodes.registerType("debug",DebugNode);
+    
+    function sendDebug(msg) {
+        if (msg.msg instanceof Error) {
+            msg.msg = msg.msg.toString();
+        } else if (msg.msg instanceof Buffer) {
+            msg.msg = "(Buffer) "+msg.msg.toString('hex');
+        } else if (typeof msg.msg === 'object') {
+            var seen = [];
+            var ty = "(Object) ";
+            if (util.isArray(msg.msg)) { ty = "(Array) "; }
+            msg.msg = ty + JSON.stringify(msg.msg, function(key, value) {
+                if (typeof value === 'object' && value !== null) {
+                    if (seen.indexOf(value) !== -1) { return "[circular]"; }
+                    seen.push(value);
+                }
+                return value;
+            }," ");
+            seen = null;
+        } else if (typeof msg.msg === "boolean") {
+            msg.msg = "(boolean) "+msg.msg.toString();
+        } else if (msg.msg === 0) {
+            msg.msg = "0";
+        } else if (msg.msg == null) {
+            msg.msg = "(undefined)";
+        }
+    
+        if (msg.msg.length > debuglength) {
+            msg.msg = msg.msg.substr(0,debuglength) +" ....";
+        }
+        
+        RED.comms.publish("debug",msg);
+    }
+    
+    DebugNode.logHandler = new events.EventEmitter();
+    DebugNode.logHandler.on("log",function(msg) {
+        if (msg.level == "warn" || msg.level == "error") {
+            sendDebug(msg);
+        }
+    });
+    RED.log.addHandler(DebugNode.logHandler);
+    
+    RED.httpAdmin.post("/debug/:id/:state", function(req,res) {
+        var node = RED.nodes.getNode(req.params.id);
+        var state = req.params.state;
+        if (node != null) {
+            if (state === "enable") {
+                node.active = true;
+                res.send(200);
+            } else if (state === "disable") {
+                node.active = false;
+                res.send(201);
+            } else {
+                res.send(404);
+            }
+        } else {
+            res.send(404);
+        }
+    });
+}
diff --git a/dgbuilder/core_nodes/core/75-exec.html b/dgbuilder/core_nodes/core/75-exec.html
new file mode 100644 (file)
index 0000000..567a34c
--- /dev/null
@@ -0,0 +1,68 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="exec">
+    <div class="form-row">
+        <label for="node-input-command"><i class="fa fa-file"></i> Command</label>
+        <input type="text" id="node-input-command" placeholder="command">
+    </div>
+    <div class="form-row">
+        <label for="node-input-append"><i class="fa fa-list"></i> Append</label>
+        <input type="text" id="node-input-append" placeholder="extra input">
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-useSpawn" placeholder="spawn" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-useSpawn" style="width: 70%;">Use spawn() instead of exec() ?</label>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: <i>spawn</i> expects only one command word - and appended args to be comma separated.</div>
+</script>
+
+<script type="text/x-red" data-help-name="exec">
+    <p>Calls out to a system command.<br/></p>
+    <p>Provides 3 outputs... stdout, stderr, and return code.</p>
+    <p>By default uses exec() which calls the command, blocks while waiting for completion, and then returns the complete result in one go, along with any errors.</p>
+    <p>Optionally can use spawn() instead, which returns output from stdout and stderr as the command runs (ie one line at a time). On completion it then returns a return code (on the 3rd output).</p>
+    <p>Spawn only expect one command word, with all extra parameters to be comma separated and passed as the append.</p>
+    <p>The optional append gets added to the command after the <b>msg.payload</b> - so you can do things like pipe the result to another command.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('exec',{
+        category: 'advanced-function',
+        color:"darksalmon",
+        defaults: {
+            command: {value:"",required:true},
+            append: {value:""},
+            useSpawn: {value:""},
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:3,
+        icon: "arrow-in.png",
+        align: "right",
+        label: function() {
+            return this.name||this.command;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/75-exec.js b/dgbuilder/core_nodes/core/75-exec.js
new file mode 100644 (file)
index 0000000..a07b140
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var spawn = require('child_process').spawn;
+    var exec = require('child_process').exec;
+
+    function ExecNode(n) {
+        RED.nodes.createNode(this,n);
+        this.cmd = n.command.trim();
+        this.append = n.append.trim() || "";
+        this.useSpawn = n.useSpawn;
+
+        var node = this;
+        this.on("input", function(msg) {
+            node.status({fill:"blue",shape:"dot"});
+            if (this.useSpawn === true) {
+                // make the extra args into an array
+                // then prepend with the msg.payload
+                if (typeof(msg.payload !== "string")) { msg.payload = msg.payload.toString(); }
+                var arg = [];
+                if (node.append.length > 0) { arg = node.append.split(","); }
+                if (msg.payload.trim() !== "") { arg.unshift(msg.payload); }
+                node.log(node.cmd+" ["+arg+"]");
+                if (node.cmd.indexOf(" ") == -1) {
+                    var ex = spawn(node.cmd,arg);
+                    ex.stdout.on('data', function (data) {
+                        //console.log('[exec] stdout: ' + data);
+                        msg.payload = data.toString();
+                        node.send([msg,null,null]);
+                    });
+                    ex.stderr.on('data', function (data) {
+                        //console.log('[exec] stderr: ' + data);
+                        msg.payload = data.toString();
+                        node.send([null,msg,null]);
+                    });
+                    ex.on('close', function (code) {
+                        //console.log('[exec] result: ' + code);
+                        msg.payload = code;
+                        node.status({});
+                        node.send([null,null,msg]);
+                    });
+                    ex.on('error', function (code) {
+                        node.warn(code);
+                    });
+                }
+                else { node.error("Spawn command must be just the command - no spaces or extra parameters"); }
+            }
+            else {
+                var cl = node.cmd+" "+msg.payload+" "+node.append;
+                node.log(cl);
+                var child = exec(cl, function (error, stdout, stderr) {
+                    msg.payload = stdout;
+                    var msg2 = {payload:stderr};
+                    var msg3 = null;
+                    //console.log('[exec] stdout: ' + stdout);
+                    //console.log('[exec] stderr: ' + stderr);
+                    if (error !== null) {
+                        msg3 = {payload:error};
+                        //console.log('[exec] error: ' + error);
+                    }
+                    node.status({});
+                    node.send([msg,msg2,msg3]);
+                });
+            }
+        });
+    }
+
+    RED.nodes.registerType("exec",ExecNode);
+}
diff --git a/dgbuilder/core_nodes/core/80-function.html b/dgbuilder/core_nodes/core/80-function.html
new file mode 100644 (file)
index 0000000..442c391
--- /dev/null
@@ -0,0 +1,110 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="function">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-func"><i class="fa fa-wrench"></i> Function</label>
+        <input type="hidden" id="node-input-func" autofocus="autofocus">
+        <div style="height: 250px;" class="node-text-editor" id="node-input-func-editor" ></div>
+    </div>
+    <div class="form-row">
+        <label for="node-input-outputs"><i class="fa fa-random"></i> Outputs</label>
+        <input id="node-input-outputs" style="width: 60px; height: 1.7em;" value="1">
+    </div>
+    <div class="form-tips">See the Info tab for help writing functions.</div>
+</script>
+
+<script type="text/x-red" data-help-name="function">
+       <p>A function block where you can write code to do more interesting things.</p>
+       <p>The message is passed in as a JavaScript object called <code>msg</code>.</p>
+       <p>By convention it will have a <code>msg.payload</code> property containing
+          the body of the message.</p>
+       <p>The function should return the messages it wants to pass on to the next nodes
+       in the flow. It can return:</p>
+       <ul>
+         <li>a single message object - passed to nodes connected to the first output</li>
+         <li>an array of message objects - passed to nodes connected to the corresponding outputs</li>
+    </ul>
+    <p>If any element of the array is itself an array of messages, multiple
+             messages are sent to the corresponding output.</p>
+       <p>If null is returned, either by itself or as an element of the array, no
+             message is passed on.</p>
+       <p>See the <a target="_new" href="http://nodered.org/docs/writing-functions.html">online documentation</a> for more help.</p>
+             
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('function',{
+        color:"#fdd0a2",
+        category: 'function',
+        defaults: {
+            name: {value:""},
+            func: {value:"\nreturn msg;"},
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "function.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-func-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-func-editor'),
+                    lang:"js",
+                    contents: $("#node-input-func").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+
+            });
+        },
+        oneditsave: function() {
+            $("#node-input-func").val(this.editor.getText())
+            delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/80-function.js b/dgbuilder/core_nodes/core/80-function.js
new file mode 100644 (file)
index 0000000..e1413a7
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function FunctionNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.func = n.func;
+        var functionText = "var results = null; results = (function(msg){"+this.func+"\n})(msg);";
+        this.topic = n.topic;
+        var sandbox = {
+            console:console,
+            util:util,
+            Buffer:Buffer,
+            context: {
+                global:RED.settings.functionGlobalContext || {}
+            }
+        };
+        var context = vm.createContext(sandbox);
+        try {
+            this.script = vm.createScript(functionText);
+            this.on("input", function(msg) {
+                try {
+                    var start = process.hrtime();
+                    context.msg = msg;
+                    this.script.runInContext(context);
+                    var results = context.results;
+                    if (results == null) {
+                        results = [];
+                    } else if (results.length == null) {
+                        results = [results];
+                    }
+                    if (msg._topic) {
+                        for (var m in results) {
+                            if (results[m]) {
+                                if (util.isArray(results[m])) {
+                                    for (var n=0; n < results[m].length; n++) {
+                                        results[m][n]._topic = msg._topic;
+                                    }
+                                } else {
+                                    results[m]._topic = msg._topic;
+                                }
+                            }
+                        }
+                    }
+                    this.send(results);
+                    var duration = process.hrtime(start);
+                    if (process.env.NODE_RED_FUNCTION_TIME) {
+                        this.status({fill:"yellow",shape:"dot",text:""+Math.floor((duration[0]* 1e9 +  duration[1])/10000)/100});
+                    }
+                } catch(err) {
+                    this.error(err.toString());
+                }
+            });
+        } catch(err) {
+            this.error(err);
+        }
+    }
+
+    RED.nodes.registerType("function",FunctionNode);
+    RED.library.register("functions");
+}
diff --git a/dgbuilder/core_nodes/core/80-template.html b/dgbuilder/core_nodes/core/80-template.html
new file mode 100644 (file)
index 0000000..dc014d3
--- /dev/null
@@ -0,0 +1,102 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="template">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-template"><i class="fa fa-file-code-o"></i> Template</label>
+        <input type="hidden" id="node-input-template" autofocus="autofocus">
+        <div style="height: 250px;" class="node-text-editor" id="node-input-template-editor" ></div>
+    </div>
+    <div class="form-row">
+        <label for="node-input-field"><i class="fa fa-edit"></i> Property</label>
+        msg.<input type="text" id="node-input-field" placeholder="payload" style="width: 64%;">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="template">
+    <p>Creates a new message based on the provided template.</p>
+    <p>This uses the <i><a href="http://mustache.github.io/mustache.5.html" target="_new">mustache</a></i> format.</p>
+    <p>For example, when a template of:
+    <pre>Hello {{name}}. Today is {{date}}</pre>
+    <p>receives a message containing:
+    <pre>{
+  name: "Fred",
+  date: "Monday"
+  payload: ...
+}</pre>
+    <p>The resulting payload will be:
+    <pre>Hello Fred. Today is Monday</pre>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('template',{
+        color:"rgb(243, 181, 103)",
+        category: 'function',
+        defaults: {
+            name: {value:""},
+            field: {value:"payload"},
+            template: {value:"This is the payload: {{payload}}!"},
+        },
+        inputs:1,
+        outputs:1,
+        icon: "template.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+
+            function templateDialogResize(ev,ui) {
+                $("#node-input-template-editor").css("height",(ui.size.height-200)+"px");
+            };
+
+            $( "#dialog" ).on("dialogresize", templateDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-template');
+                if (size) {
+                    templateDialogResize(null,{size:size});
+                }
+            });
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",templateDialogResize);
+            });
+
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-template-editor'),
+                    lang:"html",
+                    contents: $("#node-input-template").val()
+                });
+                RED.library.create({
+                    url:"templates", // where to get the data from
+                    type:"template", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','field']
+                });
+                $("#node-input-name").focus();
+            });
+        },
+        oneditsave: function() {
+            $("#node-input-template").val(this.editor.getText())
+            delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/80-template.js b/dgbuilder/core_nodes/core/80-template.js
new file mode 100644 (file)
index 0000000..7c84142
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var mustache = require("mustache");
+
+    function TemplateNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.field = n.field || "payload";
+        this.template = n.template;
+        var node = this;
+
+        var b = node.field.split(".");
+        var i = 0;
+        var m = null;
+        var rec = function(obj) {
+            i += 1;
+            if ((i < b.length) && (typeof obj[b[i-1]] === "object")) {
+                rec(obj[b[i-1]]); // not there yet - carry on digging
+            }
+            else {
+                 if (i === b.length) { // we've finished so assign the value
+                     obj[b[i-1]] = mustache.render(node.template,m);
+                     node.send(m);
+                 }
+                 else {
+                     obj[b[i-1]] = {}; // needs to be a new object so create it
+                     rec(obj[b[i-1]]); // and carry on digging
+                 }
+            }
+        }
+
+        node.on("input", function(msg) {
+            try {
+                m = msg;
+                i = 0;
+                rec(msg);
+            } catch(err) {
+                node.error(err.message);
+            }
+        });
+    }
+
+    RED.nodes.registerType("template",TemplateNode);
+    RED.library.register("templates");
+}
diff --git a/dgbuilder/core_nodes/core/89-delay.html b/dgbuilder/core_nodes/core/89-delay.html
new file mode 100644 (file)
index 0000000..dcb0a5b
--- /dev/null
@@ -0,0 +1,167 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- First, the content of the edit dialog is defined.                       -->
+<script type="text/x-red" data-template-name="delay">
+
+    <div class="form-row">
+        <label for="node-input-pauseType"><i class="fa fa-tasks"></i> Action</label>
+        <select id="node-input-pauseType" style="width:270px !important">
+          <option value="delay">Delay message</option>
+          <option value="rate">Limit rate to</option>
+          <option value="random">Random delay</option>
+        </select>
+    </div>
+    <div id="delay-details" class="form-row">
+        <label for="node-input-timeout"><i class="fa fa-clock-o"></i> For</label>
+        <input type="text" id="node-input-timeout" placeholder="Time" style="direction:rtl; width:50px !important">
+        <select id="node-input-timeoutUnits" style="width:200px !important">
+          <option value="milliseconds">Milliseconds</option>
+          <option value="seconds">Seconds</option>
+          <option value="minutes">Minutes</option>
+          <option value="hours">Hours</option>
+          <option value="days">Days</option>
+        </select>
+    </div>
+
+    <div id="rate-details" class="form-row">
+        <label for="node-input-rate"><i class="fa fa-clock-o"></i> To</label>
+        <input type="text" id="node-input-rate" placeholder="1" style="direction:rtl; width:30px !important">
+        <label for="node-input-reateUnits">msg(s) per</label>
+        <select id="node-input-rateUnits" style="width:140px !important">
+          <option value="second">Second</option>
+          <option value="minute">Minute</option>
+          <option value="hour">Hour</option>
+          <option value="day">Day</option>
+        </select>
+        <br/>
+        <input style="margin: 20px 0 20px 100px; width: 30px;" type="checkbox" id="node-input-drop"><label style="width: 250px;" for="node-input-drop">drop intermediate messages</label>
+    </div>
+
+    <div id="random-details" class="form-row">
+        <label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> Between</label>
+        <input type="text" id="node-input-randomFirst" placeholder="" style="directon:rtl; width:30px !important">
+        <label for="node-input-randomLast" style="width:20px"> &amp; </label>
+        <input type="text" id="node-input-randomLast" placeholder="" style="directon:rtl; width:30px !important">
+        <select id="node-input-randomUnits" style="width:140px !important">
+          <option value="milliseconds">Milliseconds</option>
+          <option value="seconds">Seconds</option>
+          <option value="minutes">Minutes</option>
+          <option value="hours">Hours</option>
+          <option value="days">Days</option>
+        </select>
+    </div>
+
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+
+</script>
+
+<!-- Next, some simple help text is provided for the node.                   -->
+<script type="text/x-red" data-help-name="delay">
+    <p>Introduces a delay into a flow or rate limts messges</p>
+    <p>Default delay is 5 seconds and rate limit of 1 msg/second, but both can be configured</p>
+</script>
+
+<!-- Finally, the node type is registered along with all of its properties   -->
+<script type="text/javascript">
+    RED.nodes.registerType('delay',{
+        category: 'function',      // the palette category
+        color:"#E6E0F8",
+        defaults: {             // defines the editable properties of the node
+            name: {value:""},   //  along with default values.
+            pauseType: {value:"delay", required:true},
+            timeout: {value:"5", required:true, validate:RED.validators.number()},
+            timeoutUnits: {value:"seconds"},
+            rate: {value:"1", required:true, validate:RED.validators.number()},
+            rateUnits: {value: "second"},
+            randomFirst: {value:"1", required:true, validate:RED.validators.number()},
+            randomLast: {value:"5", required:true, validate:RED.validators.number()},
+            randomUnits: {value: "seconds"},
+            drop: {value:false}
+        },
+        inputs:1,                // set the number of inputs - only 0 or 1
+        outputs:1,               // set the number of outputs - 0 to n
+        icon: "timer.png",    // set the icon (held in public/icons)
+        label: function() {      // sets the default label contents
+            if (this.pauseType == "delay") {
+              var units = this.timeoutUnits ? this.timeoutUnits.charAt(0) : "s";
+              if (this.timeoutUnits == "milliseconds") { units = "ms"; }
+              return this.name||"delay "+this.timeout+" " + units;
+            } else if (this.pauseType == "rate") {
+              var units = this.rateUnits ? this.rateUnits.charAt(0) : "s";
+              return this.name||"limit "+this.rate+" msg/"+ units;
+            } else if (this.pauseType == "random") {
+              return this.name || "random";
+            }
+            return "foo";
+        },
+        labelStyle: function() { // sets the class to apply to the label
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+          $( "#node-input-timeout" ).spinner({min:1,max:60});
+          $( "#node-input-rate" ).spinner({min:1});
+
+          $( "#node-input-randomFirst" ).spinner({min:0});
+          $( "#node-input-randomLast" ).spinner({min:1});
+
+          if (this.pauseType == "delay") {
+            $("#delay-details").show();
+            $("#rate-details").hide();
+            $("#random-details").hide();
+          } else if (this.pauseType == "rate") {
+            $("#delay-details").hide();
+            $("#rate-details").show();
+            $("#random-details").hide();
+          } else if (this.pauseType == "random") {
+            $("#delay-details").hide();
+            $("#rate-details").hide();
+            $("#random-details").show();
+          }
+
+          if (!this.timeoutUnits) {
+            $("#node-input-timeoutUnits option").filter(function() {
+              return $(this).val() == 'seconds';
+            }).attr('selected', true);
+          }
+
+          if (!this.randomUnits) {
+            $("#node-input-randomUnits option").filter(function() {
+               return $(this).val() == 'seconds';
+            }).attr('selected', true);
+          }
+
+          $("#node-input-pauseType").on("change",function() {
+            if (this.value == "delay") {
+              $("#delay-details").show();
+              $("#rate-details").hide();
+              $("#random-details").hide();
+            } else if (this.value == "rate") {
+              $("#delay-details").hide();
+              $("#rate-details").show();
+              $("#random-details").hide();
+            } else if (this.value == "random") {
+              $("#delay-details").hide();
+              $("#rate-details").hide();
+              $("#random-details").show();
+            }
+          });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/89-delay.js b/dgbuilder/core_nodes/core/89-delay.js
new file mode 100644 (file)
index 0000000..3c4e1c0
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+//Simple node to introduce a pause into a flow
+module.exports = function(RED) {
+    "use strict";
+    
+    var MILLIS_TO_NANOS = 1000000;
+    var SECONDS_TO_NANOS = 1000000000;
+    
+    function random(n) {
+        var wait = n.randomFirst + (n.diff * Math.random());
+        if (n.buffer.length > 0) {
+            n.send(n.buffer.pop());
+            n.randomID = setTimeout(function() {random(n);},wait);
+        } else {
+            n.randomID = -1;
+        }
+    }
+
+    function DelayNode(n) {
+        RED.nodes.createNode(this,n);
+
+        this.pauseType = n.pauseType;
+        this.timeoutUnits = n.timeoutUnits;
+        this.randomUnits = n.randomUnits;
+        this.rateUnits = n.rateUnits;
+
+        if (n.timeoutUnits === "milliseconds") {
+            this.timeout = n.timeout;
+        } else if (n.timeoutUnits === "seconds") {
+            this.timeout = n.timeout * 1000;
+        } else if (n.timeoutUnits === "minutes") {
+            this.timeout = n.timeout * (60 * 1000);
+        } else if (n.timeoutUnits === "hours") {
+            this.timeout = n.timeout * (60 * 60 * 1000);
+        } else if (n.timeoutUnits === "days") {
+            this.timeout = n.timeout * (24 * 60 * 60 * 1000);
+        }
+
+        if (n.rateUnits === "second") {
+            this.rate = 1000/n.rate;
+        } else if (n.rateUnits === "minute") {
+            this.rate = (60 * 1000)/n.rate;
+        } else if (n.rateUnits === "hour") {
+            this.rate = (60 * 60 * 1000)/n.rate;
+        } else if (n.rateUnits === "day") {
+            this.rate = (24 * 60 * 60 * 1000)/n.rate;
+        }
+
+        if (n.randomUnits === "milliseconds") {
+            this.randomFirst = n.randomFirst;
+            this.randomLast = n.randomLast;
+        } else if (n.randomUnits === "seconds") {
+            this.randomFirst = n.randomFirst * 1000;
+            this.randomLast = n.randomLast * 1000;
+        } else if (n.randomUnits === "minutes") {
+            this.randomFirst = n.randomFirst * (60 * 1000);
+            this.randomLast = n.randomLast * (60 * 1000);
+        } else if (n.randomUnits === "hours") {
+            this.randomFirst = n.randomFirst * (60 * 60 * 1000);
+            this.randomLast = n.randomLast * (60 * 60 * 1000);
+        } else if (n.randomUnits === "days") {
+            this.randomFirst = n.randomFirst * (24 * 60 * 60 * 1000);
+            this.randomLast = n.randomLast * (24 * 60 * 60 * 1000);
+        }
+
+        this.diff = this.randomLast - this.randomFirst;
+        this.name = n.name;
+        this.idList = [];
+        this.buffer = [];
+        this.intervalID = -1;
+        this.randomID = -1;
+        this.lastSent;
+        this.drop = n.drop;
+        var node = this;
+
+        if (this.pauseType === "delay") {
+            this.on("input", function(msg) {
+                var id;
+                id = setTimeout(function(){
+                    node.idList.splice(node.idList.indexOf(id),1);
+                    node.send(msg);
+                }, node.timeout);
+                this.idList.push(id);
+            });
+
+            this.on("close", function() {
+                for (var i=0; i<this.idList.length; i++ ) {
+                    clearTimeout(this.idList[i]);
+                }
+                this.idList = [];
+            });
+
+        } else if (this.pauseType === "rate") {
+            this.on("input", function(msg) {
+                if (!node.drop) {
+                    if ( node.intervalID !== -1) {
+                        node.buffer.push(msg);
+                        if (node.buffer.length > 0) {
+                            node.status({text:node.buffer.length});
+                        }
+                        if (node.buffer.length > 1000) {
+                            node.warn(this.name + " buffer exceeded 1000 messages");
+                        }
+                    } else {
+                        node.send(msg);
+                        node.intervalID = setInterval(function() {
+                            if (node.buffer.length === 0) {
+                                clearInterval(node.intervalID);
+                                node.intervalID = -1;
+                                node.status({text:""});
+                            }
+
+                            if (node.buffer.length > 0) {
+                                node.send(node.buffer.shift());
+                                node.status({text:node.buffer.length});
+                            }
+                        },node.rate);
+                    }
+                } else {
+                    var timeSinceLast;
+                    if (node.lastSent) {
+                        timeSinceLast = process.hrtime(node.lastSent);
+                    }
+                    if (!node.lastSent) { // ensuring that we always send the first message 
+                        node.lastSent = process.hrtime();
+                        node.send(msg);
+                    } else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
+                        node.lastSent = process.hrtime();
+                        node.send(msg);
+                    }
+                }
+            });
+
+            this.on("close", function() {
+                clearInterval(this.intervalID);
+                this.buffer = [];
+            });
+
+        } else if (this.pauseType === "random") {
+            this.on("input",function(msg){
+                node.buffer.push(msg);
+                if (node.randomID === -1) {
+                    var wait = node.randomFirst + (node.diff * Math.random());
+                    node.randomID = setTimeout(function() {random(node);},wait);
+                }
+            });
+
+            this.on("close", function (){
+                if (this.randomID !== -1) {
+                    clearTimeout(this.randomID);
+                }
+            });
+        }
+    }
+    RED.nodes.registerType("delay",DelayNode);
+}
diff --git a/dgbuilder/core_nodes/core/89-trigger.html b/dgbuilder/core_nodes/core/89-trigger.html
new file mode 100644 (file)
index 0000000..f3ec530
--- /dev/null
@@ -0,0 +1,130 @@
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="trigger">
+    <div class="form-row">
+        <label for="node-input-op1type"><i class="fa fa-arrow-up"></i> Output</label>
+        <select id="node-input-op1type" style="width:73% !important">
+            <option value="val">the value below</option>
+            <option value="pay">the existing payload</option>
+            <option value="nul">nothing (no output)</option>
+        </select>
+    </div>
+    <div class="form-row" id="node-op1">
+        <label for="node-input-op1">&nbsp;</label>
+        <input type="text" id="node-input-op1">
+    </div>
+    <div class="form-row">
+        <label for="node-input-duration"><i class="fa fa-clock-o"></i> then wait</label>
+        <input type="text" id="node-input-duration" placeholder="250" style="direction:rtl; width:70px !important">
+        <select id="node-input-units" style="width:140px !important">
+            <option value="ms">Milliseconds</option>
+            <option value="s">Seconds</option>
+            <option value="min">Minutes</option>
+            <option value="hr">Hours</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-op2type"><i class="fa fa-arrow-down"></i> output</label>
+        <select id="node-input-op2type" style="width:73% !important">
+            <option value="val">the value below</option>
+            <option value="pay">the existing payload</option>
+            <option value="nul">nothing (no output)</option>
+        </select>
+    </div>
+    <div class="form-row" id="node-op2">
+        <label for="node-input-op2">&nbsp;</label>
+        <input type="text" id="node-input-op2">
+    </div>
+    <div class="form-row">
+        <label for="node-input-extend"><i class="fa fa-repeat"></i> and</label>
+        <select id="node-input-extend" style="width:73% !important">
+            <option value="false">don't extend the timer if retriggered</option>
+            <option value="true">extend the timer if retriggered</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <!-- <div class="form-tips">Tip: Outputs can be values, null, {{templated}} or msg.payload<br/> -->
+    <div class="form-tips">Setting the timeout to 0 sets an infinite timeout = single shot.</div>
+    <script>
+    {
+        $("#node-input-op1type").change(function() {
+            if ($("#node-input-op1type").val() == "val") { $("#node-op1").show(); }
+            else { $("#node-op1").hide(); }
+        });
+        $("#node-input-op2type").change(function() {
+            if ($("#node-input-op2type").val() == "val") { $("#node-op2").show(); }
+            else { $("#node-op2").hide(); }
+        });
+    }
+    </script>
+</script>
+
+<script type="text/x-red" data-help-name="trigger">
+    <p>Creates two messages on the output separated by a timeout whenever ANY <b>msg</b> arrives on the input.</p>
+    <p>For example, this can be used to toggle a Raspberry PI GPIO pin on and off.</p>
+    <p>The two output states can be specified as can the duration of the timer.
+    Either output can be set to a value, or templated from the inbound
+    <b>msg</b> using mustache syntax. <pre>The payload is {{payload}}</pre></p>
+    <p>If the payload is an object then setting the output to <i>existing payload</i> will pass the complete payload object through.</p>
+    <p>Optionally the timer can be extended by being retriggered... or not.</p>
+    <p>By setting the first output to <i>nothing</i>, and selecting extend timer - a watchdog timer can be created.
+    No output will happen as long as repeated inputs occur within the timeout period.</p>
+    <p>Setting the timer to 0 creates an "infinite" timeout - the first output will happen but the second
+    never will, and neither can the first be retriggered - so a true one shot.</p>
+    <p>If a <b>msg.reset</b> property is present any timeout currently in progress
+    will be cleared and the second output will not happen.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('trigger',{
+        category: 'function',
+        color:"#E6E0F8",
+        defaults: {
+            op1: {value:"1"},
+            op2: {value:"0"},
+            op1type: {value:""},
+            op2type: {value:""},
+            duration: {value:"250",required:true,validate:RED.validators.number()},
+            extend: {value:"false"},
+            units: {value: "ms"},
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "trigger.png",
+        label: function() {
+            if (this.duration > 0) {
+                return this.name||"trigger "+this.duration+this.units;
+            }
+            else {
+                return this.name||"trigger once &infin;";
+            }
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $( "#node-input-duration" ).spinner({
+                min:1,
+                increment:25
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/89-trigger.js b/dgbuilder/core_nodes/core/89-trigger.js
new file mode 100644 (file)
index 0000000..d86a213
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var mustache = require("mustache");
+    function TriggerNode(n) {
+        RED.nodes.createNode(this,n);
+        this.op1 = n.op1 || "1";
+        this.op2 = n.op2 || "0";
+        this.op1type = n.op1type || "val";
+        this.op2type = n.op2type || "val";
+        this.extend = n.extend || false;
+        this.units = n.units || "ms";
+        this.duration = n.duration || 250;
+        if (this.duration <= 0) { this.duration = 0; }
+        else {
+            if (this.units == "s") { this.duration = this.duration * 1000; }
+            if (this.units == "min") { this.duration = this.duration * 1000 * 60; }
+            if (this.units == "hr") { this.duration = this.duration * 1000 *60 * 60; }
+        }
+        this.op1Templated = this.op1.indexOf("{{") != -1;
+        this.op2Templated = this.op2.indexOf("{{") != -1;
+        if (!isNaN(this.op1)) { this.op1 = Number(this.op1); }
+        if (!isNaN(this.op2)) { this.op2 = Number(this.op2); }
+        if (this.op1 == "true") { this.op1 = true; }
+        if (this.op2 == "true") { this.op1 = true; }
+        if (this.op1 == "false") { this.op2 = false; }
+        if (this.op2 == "false") { this.op2 = false; }
+        if (this.op1 == "null") { this.op1 = null; }
+        if (this.op2 == "null") { this.op1 = null; }
+        try { this.op1 = JSON.parse(this.op1); }
+        catch(e) { this.op1 = this.op1; }
+        try { this.op2 = JSON.parse(this.op2); }
+        catch(e) { this.op2 = this.op2; }
+
+        var node = this;
+        var tout = null;
+        var m2;
+        this.on("input", function(msg) {
+            if (msg.hasOwnProperty("reset")) {
+                clearTimeout(tout);
+                tout = null;
+            }
+            else {
+                if (!tout) {
+                    if (node.op2type === "pay") { m2 = msg.payload; }
+                    else if (node.op2Templated) { m2 = mustache.render(node.op2,msg); }
+                    else { m2 = node.op2; }
+                    if (node.op1type === "pay") { }
+                    else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
+                    else { msg.payload = node.op1; }
+                    if (node.op1type !== "nul") { node.send(msg); }
+                    if (node.duration === 0) { tout = "infinite"; }
+                    else {
+                        tout = setTimeout(function() {
+                            msg.payload = m2;
+                            if (node.op2type !== "nul") { node.send(msg); }
+                            tout = null;
+                        },node.duration);
+                    }
+                }
+                else if ((node.extend == "true") && (node.duration > 0)) {
+                    clearTimeout(tout);
+                    tout = setTimeout(function() {
+                        msg.payload = m2;
+                        if (node.op2type !== "nul") { node.send(msg); }
+                        tout = null;
+                    },node.duration);
+                }
+            }
+        });
+        this.on("close", function() {
+            if (tout) { clearTimeout(tout); }
+        });
+    }
+    RED.nodes.registerType("trigger",TriggerNode);
+}
diff --git a/dgbuilder/core_nodes/core/90-comment.html b/dgbuilder/core_nodes/core/90-comment.html
new file mode 100644 (file)
index 0000000..3638fda
--- /dev/null
@@ -0,0 +1,86 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="comment">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-comment"></i> Comment</label>
+        <input type="text" id="node-input-name" placeholder="Comment">
+    </div>
+    <div class="form-row">
+        <label for="node-input-info" style="width: 100% !important;"><i class="fa fa-comments"></i> More</label>
+        <input type="hidden" id="node-input-info" autofocus="autofocus">
+        <div style="height: 250px;" class="node-text-editor" id="node-input-info-editor" ></div>
+    </div>
+    <div class="form-tips">Tip: this isn't meant for "War and Peace" - but useful notes can be kept here.</div>
+</script>
+
+<script type="text/x-red" data-help-name="comment">
+    <p>Simple comment block.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('comment',{
+        category: 'function',
+        color:"#ffffff",
+        defaults: {
+            name: {value:""},
+            info: {value:""}
+        },
+        inputs:0,
+        outputs:0,
+        icon: "comment.png",
+        label: function() {
+            return this.name||"";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+            function functionDialogResize(ev,ui) {
+                $("#node-input-info-editor").css("height",(ui.size.height-235)+"px");
+            };
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-info-editor'),
+                    lang:"text",
+                    showLinesRuler:false,
+                    showFoldingRuler:false,
+                    contents: $("#node-input-info").val()
+                });
+                $("#node-input-name").focus();
+            });
+        },
+        oneditsave: function() {
+            $("#node-input-info").val(this.editor.getText());
+            delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/90-comment.js b/dgbuilder/core_nodes/core/90-comment.js
new file mode 100644 (file)
index 0000000..ef5f080
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function CommentNode(n) {
+        RED.nodes.createNode(this,n);
+    }
+    RED.nodes.registerType("comment",CommentNode);
+}
diff --git a/dgbuilder/core_nodes/core/98-unknown.html b/dgbuilder/core_nodes/core/98-unknown.html
new file mode 100644 (file)
index 0000000..19a4ad5
--- /dev/null
@@ -0,0 +1,49 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="unknown">
+    <div class="form-tips"><p>This node is a type unknown to your installation of Node-RED.</p>
+    <p><i>If you deploy with the node in this state, it will lose all of its configuration.</i></p>
+    <p>See the Info side bar for more help</p></div>
+</script>
+
+<script type="text/x-red" data-help-name="unknown">
+    <p>This node is a type unknown to your installation of Node-RED.</p>
+    <p><i>If you deploy with the node in this state, it will lose all of its configuration.</i></p>
+    <p>It is possible this node type is already installed, but is missing a dependency. Check the Node-RED start-up log for
+       any error messages associated with the missing node type. Use <b>npm install &lt;module&gt;</b> to install any missing modules
+       and restart Node-RED and reimport the nodes.</p>
+    <p>Otherwise, you should contact the author of the flow to obtain a copy of the missing node type.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('unknown',{
+        category: 'unknown',
+        color:"#fff0f0",
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "",
+        label: function() {
+            return "("+this.name+")"||"unknown";
+        },
+        labelStyle: function() {
+            return "node_label_unknown";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/core/98-unknown.js b/dgbuilder/core_nodes/core/98-unknown.js
new file mode 100644 (file)
index 0000000..ed4716b
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function UnknownNode(n) {
+        RED.nodes.createNode(this,n);
+    }
+    RED.nodes.registerType("unknown",UnknownNode);
+}
diff --git a/dgbuilder/core_nodes/deprecated/61-imap.html b/dgbuilder/core_nodes/deprecated/61-imap.html
new file mode 100644 (file)
index 0000000..9702cd6
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="imap">
+    <div class="form-row node-input-repeat">
+        <label for="node-input-repeat"><i class="fa fa-repeat"></i>Repeat (S)</label>
+        <input type="text" id="node-input-repeat" placeholder="300">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="imap">
+    <p>Repeatedly gets a <b>single email</b> from an IMAP server and forwards on as a msg if not already seen.</p>
+    <p>The subject is loaded into <b>msg.topic</b> and <b>msg.payload</b> is the plain text body.
+       If there is text/html then that is returned in <b>msg.html</b>. <b>msg.from</b> and <b>msg.date</b> are also set if you need them.</p>
+    <p>Uses the imap module - you also need to pre-configure your email settings in a file emailkeys.js as per below.</p>
+    <p><pre>module.exports = { service: "Gmail", user: "blahblah@gmail.com", pass: "password", server: "imap.gmail.com", port: "993" }</pre></p>
+    <p>This <b>must</b> be located in the directory <b>above</b> node-red.</p>
+    <p><b>Note:</b> this node <i>only</i> gets the most recent single email from the inbox, so set the repeat (polling) time appropriately.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('imap',{
+        category: 'deprecated',
+        color:"#c7e9c0",
+        defaults: {
+            repeat: {value:"300",required:true},
+            name: {value:""}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "envelope.png",
+        label: function() {
+            return this.name||"IMAP";
+        },
+        labelStyle: function() {
+            return (this.name||!this.topic)?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/deprecated/61-imap.js b/dgbuilder/core_nodes/deprecated/61-imap.js
new file mode 100644 (file)
index 0000000..aa2b4be
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
+var Imap = require('imap');
+var util = require('util');
+
+try {
+    var emailkey = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js");
+} catch (err) {
+    //util.log("[61-imap.js] Info : No Email credentials found.");
+}
+
+if (emailkey) {
+    var imap = new Imap({
+        user: emailkey.user,
+        password: emailkey.pass,
+        host: emailkey.server||"imap.gmail.com",
+        port: emailkey.port||"993",
+        tls: true,
+        tlsOptions: { rejectUnauthorized: false }
+    });
+
+    function openInbox(cb) {
+        imap.openBox('INBOX', true, cb);
+    }
+}
+
+function ImapNode(n) {
+    RED.nodes.createNode(this,n);
+    this.warn("This node has been deprecated and will be deleted in a future release. Please update your flow to use the 'e-mail in' node.");
+    this.name = n.name;
+    this.repeat = n.repeat * 1000 || 300000;
+    var node = this;
+    this.interval_id = null;
+    var oldmail = {};
+
+    if (!isNaN(this.repeat) && this.repeat > 0) {
+        node.log("repeat = "+this.repeat);
+        this.interval_id = setInterval( function() {
+            node.emit("input",{});
+        }, this.repeat );
+    }
+
+    this.on("input", function(msg) {
+        if (imap) {
+            imap.once('ready', function() {
+                var pay = {};
+                openInbox(function(err, box) {
+                    if (box.messages.total > 0) {
+                        var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)','TEXT'] });
+                        f.on('message', function(msg, seqno) {
+                            node.log('message: #'+ seqno);
+                            var prefix = '(#' + seqno + ') ';
+                            msg.on('body', function(stream, info) {
+                                var buffer = '';
+                                stream.on('data', function(chunk) {
+                                    buffer += chunk.toString('utf8');
+                                });
+                                stream.on('end', function() {
+                                    if (info.which !== 'TEXT') {
+                                        pay.from = Imap.parseHeader(buffer).from[0];
+                                        pay.topic = Imap.parseHeader(buffer).subject[0];
+                                        pay.date = Imap.parseHeader(buffer).date[0];
+                                    } else {
+                                        var parts = buffer.split("Content-Type");
+                                        for (var p in parts) {
+                                            if (parts[p].indexOf("text/plain") >= 0) {
+                                                pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim();
+                                            }
+                                            if (parts[p].indexOf("text/html") >= 0) {
+                                                pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim();
+                                            }
+                                        }
+                                        //pay.body = buffer;
+                                    }
+                                });
+                            });
+                            msg.on('end', function() {
+                                //node.log('Finished: '+prefix);
+                            });
+                        });
+                        f.on('error', function(err) {
+                            node.warn('fetch error: ' + err);
+                        });
+                        f.on('end', function() {
+                            if (JSON.stringify(pay) !== oldmail) {
+                                node.send(pay);
+                                oldmail = JSON.stringify(pay);
+                                node.log('sent new message: '+pay.topic);
+                            }
+                            else { node.log('duplicate not sent: '+pay.topic); }
+                            imap.end();
+                        });
+                    }
+                    else {
+                        // node.log("you have achieved inbox zero");
+                        imap.end();
+                    }
+                });
+            });
+            imap.connect();
+        }
+        else { node.warn("No Email credentials found. See info panel."); }
+    });
+
+    if (imap) {
+        imap.on('error', function(err) {
+            util.log(err);
+        });
+    }
+
+    this.on("error", function(err) {
+        node.log("error: ",err);
+    });
+
+    this.on("close", function() {
+        if (this.interval_id != null) {
+            clearInterval(this.interval_id);
+        }
+        if (imap) { imap.destroy(); }
+    });
+
+    node.emit("input",{});
+}
+RED.nodes.registerType("imap",ImapNode);
diff --git a/dgbuilder/core_nodes/deprecated/73-parsexml.html b/dgbuilder/core_nodes/deprecated/73-parsexml.html
new file mode 100644 (file)
index 0000000..b6fc16f
--- /dev/null
@@ -0,0 +1,53 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="xml2js">
+    <!-- <div class="form-row">
+        <label>Use Console</label>
+        <input type="checkbox" id="node-input-useEyes" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-useEyes" style="width: 70%;">Debug output in console ?</label>
+    </div> -->
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <!-- <div class="form-tips">Uses xml2js to process xml into javascript object.</div> -->
+</script>
+
+<script type="text/x-red" data-help-name="xml2js">
+    <p>A function that parses the <b>msg.payload</b> using the xml2js library. Places the result in the payload.</p>
+    <p>See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md" target="_new">the xml2js docs <i>here</i></a> for more information.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('xml2js',{
+        category: 'deprecated',
+        color:"#E6E0F8",
+        defaults: {
+        //useEyes: {value:false},
+        name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name||"xml2json";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/deprecated/73-parsexml.js b/dgbuilder/core_nodes/deprecated/73-parsexml.js
new file mode 100644 (file)
index 0000000..92850cb
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var parseString = require('xml2js').parseString;
+    var useColors = true;
+    //util.inspect.styles.boolean = "red";
+
+    function Xml2jsNode(n) {
+        RED.nodes.createNode(this,n);
+        this.warn("This node has been deprecated and will be deleted in a future release. Please update your flow to use the 'xml' node.");
+        this.useEyes = n.useEyes||false;
+        var node = this;
+        this.on("input", function(msg) {
+            try {
+                parseString(msg.payload, {strict:true,async:true}, function (err, result) {
+                //parseString(msg.payload, {strict:false,async:true}, function (err, result) {
+                    if (err) { node.error(err); }
+                    else {
+                        msg.payload = result;
+                        node.send(msg);
+                        if (node.useEyes == true) {
+                            node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
+                        }
+                    }
+                });
+            }
+            catch(e) { util.log("[73-parsexml.js] "+e); }
+        });
+    }
+    RED.nodes.registerType("xml2js",Xml2jsNode);
+}
diff --git a/dgbuilder/core_nodes/deprecated/74-js2xml.html b/dgbuilder/core_nodes/deprecated/74-js2xml.html
new file mode 100644 (file)
index 0000000..f614579
--- /dev/null
@@ -0,0 +1,51 @@
+<!--\r
+  Copyright 2013 IBM Corp.\r
+\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+\r
+  http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+-->\r
+\r
+<script type="text/x-red" data-template-name="json2xml">\r
+    <div class="form-row">\r
+        <label for="node-input-name"><i class="fa fa-list"></i> XML Root</label>\r
+        <input type="text" id="node-input-root" placeholder="object"></input>\r
+    </div>\r
+    <div class="form-row">\r
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>\r
+        <input type="text" id="node-input-name" placeholder="Name"></input>\r
+    </div>\r
+</script>\r
+\r
+<script type="text/x-red" data-help-name="json2xml">\r
+    <p>A function that parses the <b>msg.payload</b> using the js2xmlparser library. Places the result back in <b>msg.payload</b>.</p>\r
+    <p>See the <a href="https://github.com/michaelkourlas/node-js2xmlparser" target="_new">js2xmlparser docs</a> for more information.</p>\r
+</script>\r
+\r
+<script type="text/javascript">\r
+    RED.nodes.registerType('json2xml',{\r
+        category: 'deprecated',\r
+        color:"#E6E0F8",\r
+        defaults: {\r
+            name: {value:""},\r
+            root: {value:"object"},\r
+        },\r
+        inputs:1,\r
+        outputs:1,\r
+        icon: "arrow-in.png",\r
+        label: function() {\r
+            return this.name||"json2xml";\r
+        },\r
+        labelStyle: function() {\r
+            return this.name?"node_label_italic":"";\r
+        }\r
+    });\r
+</script>\r
diff --git a/dgbuilder/core_nodes/deprecated/74-js2xml.js b/dgbuilder/core_nodes/deprecated/74-js2xml.js
new file mode 100644 (file)
index 0000000..164bafa
--- /dev/null
@@ -0,0 +1,39 @@
+/**\r
+ * Copyright 2013 IBM Corp.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ **/\r
+\r
+module.exports = function(RED) {\r
+    "use strict";\r
+    var js2xmlparser = require("js2xmlparser");\r
+\r
+    function Js2XmlNode(n) {\r
+        RED.nodes.createNode(this,n);\r
+        this.warn("This node has been deprecated and will be deleted in a future release. Please update your flow to use the 'xml' node.");\r
+        this.root = n.root;\r
+        var node = this;\r
+\r
+        this.on("input", function(msg) {\r
+            try {\r
+                var root = node.root || typeof msg.payload;\r
+                if (typeof msg.payload !== "object") { msg.payload = '"'+msg.payload+'"'; }\r
+                console.log(root, typeof msg.payload,msg.payload);\r
+                msg.payload = js2xmlparser(root, msg.payload);\r
+                node.send(msg);\r
+            }\r
+            catch(e) { console.log(e); }\r
+        });\r
+    }\r
+    RED.nodes.registerType("json2xml",Js2XmlNode);\r
+}\r
diff --git a/dgbuilder/core_nodes/deprecated/90-httpget.html b/dgbuilder/core_nodes/deprecated/90-httpget.html
new file mode 100644 (file)
index 0000000..b1f2e08
--- /dev/null
@@ -0,0 +1,61 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="httpget">
+    <div class="form-tips"><b>Deprecated</b>: please use the <i>http request</i> node.</div>
+    <br>
+    <div class="form-row">
+        <label for="node-input-baseurl"><i class="fa fa-tasks"></i> Base URL</label>
+        <input type="text" id="node-input-baseurl" placeholder="http(s)://url">
+    </div>
+    <div class="form-row">
+        <label for="node-input-append"><i class="fa fa-tasks"></i> Append</label>
+        <input type="text" id="node-input-append" placeholder="">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">The <b>Base URL</b> gets prepended to whatever payload is passed in. Leave blank if you pass in a full url.<br/>The append gets added to the end after any payload.<br/>The output Topic is the same as the input Topic.</div>
+</script>
+
+<script type="text/x-red" data-help-name="httpget">
+       <p>Performs an HTTP or HTTPS GET and returns the fetched page.</p>
+       <p>The return code is placed in <b>msg.rc</b>, and the full text of the result is in <b>msg.payload</b>.</p>
+       <p>The <b>msg.payload</b> is added to the base url, and then the optional append is added after.</p>
+       <p>This is mostly suitable for small pages as large results will need a lot of parsing....</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('httpget',{
+        category: 'deprecated',
+        color:"rgb(231, 231, 174)",
+        defaults: {
+            name: {value:""},
+            baseurl: {value:""},
+            append: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "white-globe.png",
+        label: function() {
+            return this.name||this.baseurl;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/deprecated/90-httpget.js b/dgbuilder/core_nodes/deprecated/90-httpget.js
new file mode 100644 (file)
index 0000000..63e16b9
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
+
+function HttpGet(n) {
+    RED.nodes.createNode(this,n);
+    this.warn("This node has been deprecated and will be deleted in a future release. Please update your flow to use the 'http request' node.");
+    this.baseurl = n.baseurl || "";
+    this.append = n.append || "";
+    var node = this;
+    if (this.baseurl.substring(0,5) === "https") { var http = require("https"); }
+    else { var http = require("http"); }
+    this.on("input", function(msg) {
+        msg._payload = msg.payload;
+        //util.log("[httpget] "+this.baseurl+msg.payload+this.append);
+        http.get(this.baseurl+msg.payload+this.append, function(res) {
+            node.log("Http response: " + res.statusCode);
+            msg.rc = res.statusCode;
+            msg.payload = "";
+            if ((msg.rc != 200) && (msg.rc != 404)) {
+                node.send(msg);
+            }
+            res.setEncoding('utf8');
+            res.on('data', function(chunk) {
+                msg.payload += chunk;
+            });
+            res.on('end', function() {
+                node.send(msg);
+            });
+        }).on('error', function(e) {
+            //node.error(e);
+            msg.rc = 503;
+            msg.payload = e;
+            node.send(msg);
+        });
+    });
+}
+
+RED.nodes.registerType("httpget",HttpGet);
diff --git a/dgbuilder/core_nodes/hardware/35-arduino.html b/dgbuilder/core_nodes/hardware/35-arduino.html
new file mode 100644 (file)
index 0000000..17f0289
--- /dev/null
@@ -0,0 +1,171 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<script type="text/x-red" data-template-name="arduino in">
+    <div class="form-row">
+        <label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
+        <input type="text" id="node-input-arduino">
+    </div>
+    <div class="form-row">
+        <label for="node-input-pin"><i class="fa fa-circle"></i> Pin</label>
+        <input type="text" id="node-input-pin" placeholder="2">
+    </div>
+    <div class="form-row">
+        <label for="node-input-state"><i class="fa fa-wrench"></i> Type</label>
+        <select type="text" id="node-input-state" style="width: 150px;">
+            <option value="INPUT">Digital pin</option>
+            <option value="ANALOG">Analogue pin</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips"><b>Note:</b> You cannot use the same pin for both output and input.</div>
+</script>
+
+<script type="text/x-red" data-help-name="arduino in">
+    <p>Arduino input node. Connects to local Arduino and monitors the selected pin for changes. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p>
+    <p>The Arduino must be loaded with the Standard Firmata sketch available in the Arduino examples.</p>
+    <p>You can select either Digital or Analogue input. Outputs the value read as <b>msg.payload</b> and the pin number as <b>msg.topic</b>.</p>
+    <p>It only outputs on a change of value - fine for digital inputs, but you can get a lot of data from analogue pins which you must then handle.</p>
+    <p>You can set the sample rate in ms from 20 to 65535.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('arduino in',{
+        category: 'Arduino',
+        color:"#3fadb5",
+        defaults: {
+            name: {value:""},
+            pin: {value:"",required:true},
+            state: {value:"INPUT",required:true},
+            arduino: {type:"arduino-board"}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "arduino.png",
+        label: function() {
+            var a = "";
+            if (this.state == "ANALOG") a = "A";
+            return this.name||"Pin: "+a+this.pin;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+<script type="text/x-red" data-template-name="arduino out">
+    <div class="form-row">
+        <label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
+        <input type="text" id="node-input-arduino">
+    </div>
+    <div class="form-row">
+        <label for="node-input-pin"><i class="fa fa-circle"></i> Pin</label>
+        <input type="text" id="node-input-pin" placeholder="13">
+    </div>
+    <div class="form-row">
+        <label for="node-input-state"><i class="fa fa-wrench"></i> Type</label>
+        <select type="text" id="node-input-state" style="width: 200px;">
+            <option value="OUTPUT">Digital (0/1)</option>
+            <option value="PWM">Analogue (0-255)</option>
+            <option value="SERVO">Servo (0-180)</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips"><b>Note:</b> You cannot use the same pin for both output and input.</div>
+</script>
+
+<script type="text/x-red" data-help-name="arduino out">
+    <p>Arduino output node. Connects to local Arduino and writes to the selected digital pin. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p>
+    <p>The Arduino must be loaded with the Standard Firmata sketch available in the Arduino examples.</p>
+    <p>You can select Digital, Analogue (PWM) or Servo type outputs. Expects a numeric value in <b>msg.payload</b>. The pin number is set in the properties panel.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('arduino out',{
+        category: 'Arduino',
+        color:"#3fadb5",
+        defaults: {
+            name: {value:""},
+            pin: {value:"",required:true},
+            state: {value:"",required:true},
+            arduino: {type:"arduino-board"}
+        },
+        inputs:1,
+        outputs:0,
+        icon: "arduino.png",
+        align: "right",
+        label: function() {
+            return this.name||"Pin: "+this.pin;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="arduino-board">
+    <div class="form-row">
+        <label for="node-config-input-device"><i class="fa fa-random"></i> Port</label>
+        <input type="text" id="node-config-input-device" style="width:60%;" placeholder="e.g. /dev/ttyUSB0  COM1"/>
+        <a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
+    </div>
+    <div class="form-tips"><b>Tip:</b> Use search to try to auto-detect serial port.</div>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('arduino-board',{
+        category: 'config',
+        defaults: {
+            device: {value:"",required:true}
+        },
+        label: function() {
+            return this.device||"arduino";
+        },
+        oneditprepare: function() {
+            try {
+                $("#node-config-input-device").autocomplete( "destroy" );
+            } catch(err) { }
+            $("#node-config-lookup-serial").click(function() {
+                $("#node-config-lookup-serial-icon").removeClass('fa-search');
+                $("#node-config-lookup-serial-icon").addClass('spinner');
+                $("#node-config-lookup-serial").addClass('disabled');
+
+                $.getJSON('arduinoports',function(data) {
+                    $("#node-config-lookup-serial-icon").addClass('fa-search');
+                    $("#node-config-lookup-serial-icon").removeClass('spinner');
+                    $("#node-config-lookup-serial").removeClass('disabled');
+                    var ports = [];
+                    $.each(data, function(i, port){
+                        ports.push(port);
+                    });
+                    $("#node-config-input-device").autocomplete({
+                        source:ports,
+                        minLength:0,
+                        close: function( event, ui ) {
+                            $("#node-config-input-device").autocomplete( "destroy" );
+                        }
+                    }).autocomplete("search","");
+                });
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/hardware/35-arduino.js b/dgbuilder/core_nodes/hardware/35-arduino.js
new file mode 100644 (file)
index 0000000..795e990
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var ArduinoFirmata = require('arduino-firmata');
+    var fs = require('fs');
+    var plat = require('os').platform();
+    var portlist = ArduinoFirmata.list(function (err, ports) {
+        portlist = ports;
+    });
+
+    // The Board Definition - this opens (and closes) the connection
+    function ArduinoNode(n) {
+        RED.nodes.createNode(this,n);
+        this.device = n.device || null;
+        this.repeat = n.repeat||25;
+        //node.log("opening connection "+this.device);
+        var node = this;
+        node.board = new ArduinoFirmata();
+        if (portlist.indexOf(node.device) === -1) {
+            node.warn("Device "+node.device+" not found");
+        }
+        else {
+            node.board.connect(node.device);
+        }
+
+        node.board.on('boardReady', function(){
+            node.log("version "+node.board.boardVersion);
+        });
+
+        node.on('close', function() {
+            if (node.board) {
+                try {
+                    node.board.close(function() {
+                        node.log("port closed");
+                    });
+                } catch(e) { }
+            }
+        });
+    }
+    RED.nodes.registerType("arduino-board",ArduinoNode);
+
+
+    // The Input Node
+    function DuinoNodeIn(n) {
+        RED.nodes.createNode(this,n);
+        this.buttonState = -1;
+        this.pin = n.pin;
+        this.state = n.state;
+        this.arduino = n.arduino;
+        this.serverConfig = RED.nodes.getNode(this.arduino);
+        if (typeof this.serverConfig === "object") {
+            this.board = this.serverConfig.board;
+            //this.repeat = this.serverConfig.repeat;
+            var node = this;
+            node.status({fill:"red",shape:"ring",text:"connecting"});
+
+            node.board.on('connect', function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+                //console.log("i",node.state,node.pin);
+                if (node.state == "ANALOG") {
+                    node.board.on('analogChange', function(e) {
+                        if (e.pin == node.pin) {
+                            var msg = {payload:e.value, topic:"A"+e.pin};
+                            node.send(msg);
+                        }
+                    });
+
+                }
+                else {
+                    node.board.pinMode(node.pin, ArduinoFirmata.INPUT);
+                    node.board.on('digitalChange', function(e) {
+                        if (e.pin == node.pin) {
+                            var msg = {payload:e.value, topic:e.pin};
+                            node.send(msg);
+                        }
+                    });
+                }
+            });
+        }
+        else {
+            util.log("[Firmata-arduino] port not configured");
+        }
+    }
+    RED.nodes.registerType("arduino in",DuinoNodeIn);
+
+
+    // The Output Node
+    function DuinoNodeOut(n) {
+        RED.nodes.createNode(this,n);
+        this.buttonState = -1;
+        this.pin = n.pin;
+        this.state = n.state;
+        this.arduino = n.arduino;
+        this.serverConfig = RED.nodes.getNode(this.arduino);
+        if (typeof this.serverConfig === "object") {
+            this.board = this.serverConfig.board;
+            var node = this;
+            node.status({fill:"red",shape:"ring",text:"connecting"});
+
+            node.board.on('connect', function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+                //console.log("o",node.state,node.pin);
+                node.board.pinMode(node.pin, node.state);
+                node.on("input", function(msg) {
+                    if (node.state == "OUTPUT") {
+                        if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
+                            node.board.digitalWrite(node.pin, true);
+                        }
+                        if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) {
+                            node.board.digitalWrite(node.pin, false);
+                        }
+                    }
+                    if (node.state == "PWM") {
+                        msg.payload = msg.payload * 1;
+                        if ((msg.payload >= 0) && (msg.payload <= 255)) {
+                            //console.log(msg.payload, node.pin);
+                            node.board.servoWrite(node.pin, msg.payload);
+                        }
+                    }
+                    if (node.state == "SERVO") {
+                        msg.payload = msg.payload * 1;
+                        if ((msg.payload >= 0) && (msg.payload <= 180)) {
+                            //console.log(msg.payload, node.pin);
+                            node.board.servoWrite(node.pin, msg.payload);
+                        }
+                    }
+                });
+            });
+        }
+        else {
+            util.log("[Firmata-arduino] port not configured");
+        }
+    }
+    RED.nodes.registerType("arduino out",DuinoNodeOut);
+
+    RED.httpAdmin.get("/arduinoports",function(req,res) {
+        ArduinoFirmata.list(function (err, ports) {
+            //console.log(JSON.stringify(ports));
+            res.writeHead(200, {'Content-Type': 'text/plain'});
+            res.write(JSON.stringify(ports));
+            res.end();
+        });
+    });
+}
diff --git a/dgbuilder/core_nodes/hardware/36-rpi-gpio.html b/dgbuilder/core_nodes/hardware/36-rpi-gpio.html
new file mode 100644 (file)
index 0000000..9e705c2
--- /dev/null
@@ -0,0 +1,182 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="rpi-gpio in">
+    <div class="form-row">
+        <label for="node-input-pin"><i class="fa fa-circle"></i> GPIO Pin</label>
+        <select type="text" id="node-input-pin" style="width: 200px;">
+            <option value="-" disabled>select pin </option>
+            <option value="3">3 - SDA1 </option>
+            <option value="5">5 - SCL1 </option>
+            <option value="7">7 - GPIO7</option>
+            <option value="8">8 - TxD </option>
+            <option value="10">10 - RxD </option>
+            <option value="11">11 - GPIO0</option>
+            <option value="12">12 - GPIO1</option>
+            <option value="13">13 - GPIO2</option>
+            <option value="15">15 - GPIO3</option>
+            <option value="16">16 - GPIO4</option>
+            <option value="18">18 - GPIO5</option>
+            <option value="19">19 - MOSI </option>
+            <option value="21">21 - MISO </option>
+            <option value="22">22 - GPIO6</option>
+            <option value="23">23 - SCLK </option>
+            <option value="24">24 - CE0 </option>
+            <option value="26">26 - CE1 </option>
+         </select>
+         &nbsp;<span id="pitype"></span>
+    </div>
+    <div class="form-row">
+        <label for="node-input-intype"><i class="fa fa-long-arrow-up"></i> Resistor?</label>
+        <select type="text" id="node-input-intype" style="width: 150px;">
+        <option value="tri">none</option>
+        <option value="up">pullup</option>
+        <option value="down">pulldown</option>
+        <!--<option value="tri">tristate</option>-->
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: Only Digital I/O is supported - input must be 0 or 1.</div>
+</script>
+
+<script type="text/x-red" data-help-name="rpi-gpio in">
+    <p>Raspberry Pi input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin. Requires the gpio command to work.</p>
+    <p>You may also enable the input pullup resitor or the pulldown resistor.</p>
+    <p>The <b>msg.topic</b> is set to <i>pi/{the pin number}</i></p>
+    <p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
+    <p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu, and will be rewritten shortly to try to use interrupts.</p>
+
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('rpi-gpio in',{
+        category: 'advanced-input',
+        color:"#c6dbef",
+        defaults: {
+            name: { value:"" },
+            intype: { value: "in" },
+            pin: { value:"",required:true,validate:RED.validators.number() },
+        },
+        inputs:0,
+        outputs:1,
+        icon: "rpi.png",
+        label: function() {
+            return this.name||"Pin: "+this.pin ;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $.getJSON('rpi-gpio/'+this.id,function(data) {
+                $('#pitype').text(data.type);
+                if (data.type === "Model B+") {
+                    $('#node-input-pin').append($("<option></option>").attr("value",27).text("27 - SDA0"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",28).text("28 - SCL0"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",29).text("29 - GPIO21"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",31).text("31 - GPIO22"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",32).text("32 - GPIO26"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",33).text("33 - GPIO23"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",35).text("35 - GPIO24"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",36).text("36 - GPIO27"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",37).text("37 - GPIO25"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",38).text("38 - GPIO28"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",40).text("40 - GPIO29"));
+                }
+            });
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="rpi-gpio out">
+    <div class="form-row">
+        <label for="node-input-pin"><i class="fa fa-circle"></i> GPIO Pin</label>
+        <select type="text" id="node-input-pin" style="width: 200px;">
+            <option value="-">select pin </option>
+            <option value="3">3 - SDA1 </option>
+            <option value="5">5 - SCL1 </option>
+            <option value="7">7 - GPIO7</option>
+            <option value="8">8 - TxD </option>
+            <option value="10">10 - RxD </option>
+            <option value="11">11 - GPIO0</option>
+            <option value="12">12 - GPIO1</option>
+            <option value="13">13 - GPIO2</option>
+            <option value="15">15 - GPIO3</option>
+            <option value="16">16 - GPIO4</option>
+            <option value="18">18 - GPIO5</option>
+            <option value="19">19 - MOSI </option>
+            <option value="21">21 - MISO </option>
+            <option value="22">22 - GPIO6</option>
+            <option value="23">23 - SCLK </option>
+            <option value="24">24 - CE0 </option>
+            <option value="26">26 - CE1 </option>
+         </select>
+         &nbsp;<span id="pitype"></span>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: Only Digital I/O is supported - input must be 0 or 1.</div>
+</script>
+
+<script type="text/x-red" data-help-name="rpi-gpio out">
+    <p>Raspberry Pi output node. Expects a <b>msg.payload</b> with either a 0 or 1 (or true or false). Requires the gpio command to work.</p>
+    <p>Will set the selected physical pin high or low depending on the value passed in.</p>
+    <p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('rpi-gpio out',{
+        category: 'advanced-output',
+        color:"#c6dbef",
+        defaults: {
+            name: { value:"" },
+            pin: { value:"",required:true,validate:RED.validators.number() },
+        },
+        inputs:1,
+        outputs:0,
+        icon: "rpi.png",
+        align: "right",
+        label: function() {
+            return this.name||"Pin: "+this.pin;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $.getJSON('rpi-gpio/'+this.id,function(data) {
+                $('#pitype').text(data.type);
+                if (data.type === "Model B+") {
+                    $('#node-input-pin').append($("<option></option>").attr("value",27).text("27 - SDA0"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",28).text("28 - SCL0"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",29).text("29 - GPIO21"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",31).text("31 - GPIO22"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",32).text("32 - GPIO26"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",33).text("33 - GPIO23"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",35).text("35 - GPIO24"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",36).text("36 - GPIO27"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",37).text("37 - GPIO25"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",38).text("38 - GPIO28"));
+                    $('#node-input-pin').append($("<option></option>").attr("value",40).text("40 - GPIO29"));
+                }
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/hardware/36-rpi-gpio.js b/dgbuilder/core_nodes/hardware/36-rpi-gpio.js
new file mode 100644 (file)
index 0000000..93cbc4e
--- /dev/null
@@ -0,0 +1,185 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var exec = require('child_process').exec;
+    var fs =  require('fs');
+
+    var gpioCommand = '/usr/local/bin/gpio';
+
+    if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi
+        throw "Info : Ignoring Raspberry Pi specific node.";
+    }
+
+    if (!fs.existsSync(gpioCommand)) { // gpio command not installed
+        throw "Info : Can't find Raspberry Pi wiringPi gpio command.";
+    }
+
+    // Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
+    var pintable = {
+    // Physical : WiringPi
+            "11":"0",
+            "12":"1",
+            "13":"2",
+            "15":"3",
+            "16":"4",
+            "18":"5",
+            "22":"6",
+             "7":"7",
+             "3":"8",
+             "5":"9",
+            "24":"10",
+            "26":"11",
+            "19":"12",
+            "21":"13",
+            "23":"14",
+             "8":"15",
+            "10":"16",
+            "27":"30",
+            "28":"31",
+            "29":"21",
+            "31":"22",
+            "32":"26",
+            "33":"23",
+            "35":"24",
+            "36":"27",
+            "37":"25",
+            "38":"28",
+            "40":"29"
+    }
+    var tablepin = {
+    // WiringPi : Physical
+            "0":"11",
+            "1":"12",
+            "2":"13",
+            "3":"15",
+            "4":"16",
+            "5":"18",
+            "6":"22",
+            "7":"7",
+            "8":"3",
+            "9":"5",
+           "10":"24",
+           "11":"26",
+           "12":"19",
+           "13":"21",
+           "14":"23",
+           "15":"8",
+           "16":"10",
+           "30":"27",
+           "31":"28",
+           "21":"29",
+           "22":"31",
+           "26":"32",
+           "23":"33",
+           "24":"35",
+           "27":"36",
+           "25":"37",
+           "28":"38",
+           "29":"40"
+    }
+
+    function GPIOInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.buttonState = -1;
+        this.pin = pintable[n.pin];
+        this.intype = n.intype;
+        var node = this;
+
+        if (node.pin !== undefined) {
+            exec(gpioCommand+" mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
+                if (err) { node.error(err); }
+                else {
+                    node._interval = setInterval( function() {
+                        exec(gpioCommand+" read "+node.pin, function(err,stdout,stderr) {
+                            if (err) { node.error(err); }
+                            else {
+                                if (node.buttonState !== Number(stdout)) {
+                                    var previousState = node.buttonState;
+                                    node.buttonState = Number(stdout);
+                                    if (previousState !== -1) {
+                                        var msg = {topic:"pi/"+tablepin[node.pin], payload:node.buttonState};
+                                        node.send(msg);
+                                    }
+                                }
+                            }
+                        });
+                    }, 250);
+                }
+            });
+        }
+        else {
+            node.error("Invalid GPIO pin: "+node.pin);
+        }
+
+        node.on("close", function() {
+            clearInterval(node._interval);
+        });
+    }
+
+    function GPIOOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.pin = pintable[n.pin];
+        var node = this;
+
+        if (node.pin !== undefined) {
+            process.nextTick(function() {
+                exec(gpioCommand+" mode "+node.pin+" out", function(err,stdout,stderr) {
+                    if (err) { node.error(err); }
+                    else {
+                        node.on("input", function(msg) {
+                            if (msg.payload === "true") { msg.payload = true; }
+                            if (msg.payload === "false") { msg.payload = false; }
+                            var out = Number(msg.payload);
+                            if ((out === 0)|(out === 1)) {
+                                exec(gpioCommand+" write "+node.pin+" "+out, function(err,stdout,stderr) {
+                                    if (err) { node.error(err); }
+                                });
+                            }
+                            else { node.warn("Invalid input - not 0 or 1"); }
+                        });
+                    }
+                });
+            });
+        }
+        else {
+            node.error("Invalid GPIO pin: "+node.pin);
+        }
+
+        node.on("close", function() {
+            exec(gpioCommand+" mode "+node.pin+" in");
+        });
+    }
+
+    var pitype = { type:"" };
+    exec(gpioCommand+" -v | grep Type", function(err,stdout,stderr) {
+        if (err) {
+            util.log('[36-rpi-gpio.js] Error: "'+gpioCommand+' -v" command failed for some reason.');
+        }
+        else {
+            pitype = { type:(stdout.split(","))[0].split(": ")[1], rev:(stdout.split(","))[1].split(": ")[1] };
+        }
+    });
+
+    RED.nodes.registerType("rpi-gpio in",GPIOInNode);
+    RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
+
+    RED.httpAdmin.get('/rpi-gpio/:id',function(req,res) {
+        res.send( JSON.stringify(pitype) );
+    });
+}
diff --git a/dgbuilder/core_nodes/io/10-mqtt.html b/dgbuilder/core_nodes/io/10-mqtt.html
new file mode 100644 (file)
index 0000000..2ff5eb2
--- /dev/null
@@ -0,0 +1,157 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="mqtt in">
+    <div class="form-row">
+        <label for="node-input-broker"><i class="fa fa-globe"></i> Broker</label>
+        <input type="text" id="node-input-broker">
+    </div>
+    <div class="form-row">
+        <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
+        <input type="text" id="node-input-topic" placeholder="Topic">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="mqtt in">
+    <p>MQTT input node. Connects to a broker and subscribes to the specified topic. The topic may contain MQTT wildcards.</p>
+    <p>Outputs an object called <b>msg</b> containing <b>msg.topic, msg.payload, msg.qos</b> and <b>msg.retain</b>.</p>
+    <p><b>msg.payload</b> is a String.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('mqtt in',{
+        category: 'input',
+        defaults: {
+            name: {value:""},
+            topic: {value:"",required:true},
+            broker: {type:"mqtt-broker", required:true}
+        },
+        color:"#d8bfd8",
+        inputs:0,
+        outputs:1,
+        icon: "bridge.png",
+        label: function() {
+            return this.name||this.topic||"mqtt";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+<script type="text/x-red" data-template-name="mqtt out">
+    <div class="form-row">
+        <label for="node-input-broker"><i class="fa fa-globe"></i> Broker</label>
+        <input type="text" id="node-input-broker">
+    </div>
+    <div class="form-row">
+        <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
+        <input type="text" id="node-input-topic" placeholder="Topic">
+    </div>
+    <div class="form-row">
+        <label for="node-input-qos"><i class="fa fa-empire"></i> QoS</label>
+        <select id="node-input-qos" style="width:125px !important">
+            <option value=""></option>
+            <option value="0">0</option>
+            <option value="1">1</option>
+            <option value="2">2</option>
+        </select>
+        &nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;Retain &nbsp;<select id="node-input-retain" style="width:125px !important">
+            <option value=""></option>
+            <option value="false">false</option>
+            <option value="true">true</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: Leave topic, qos or retain blank if you want to set them via msg properties.</div>
+</script>
+
+<script type="text/x-red" data-help-name="mqtt out">
+    <p>Connects to a MQTT broker and publishes <b>msg.payload</b> either to the <b>msg.topic</b> or to the topic specified in the edit window. The value in the edit window has precedence.</p>
+    <p>Likewise QoS and/or retain values in the edit panel will overwrite any <b>msg.qos</b> and <b>msg.retain</b> properties. If nothing is set they default to <i>0</i> and <i>false</i> respectively.</p>
+    <p>If <b>msg.payload</b> contains an object it will be stringified before being sent.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('mqtt out',{
+        category: 'output',
+        defaults: {
+            name: {value:""},
+            topic: {value:""},
+            qos: {value:""},
+            retain: {value:""},
+            broker: {type:"mqtt-broker", required:true}
+        },
+        color:"#d8bfd8",
+        inputs:1,
+        outputs:0,
+        icon: "bridge.png",
+        align: "right",
+        label: function() {
+            return this.name||this.topic||"mqtt";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+<script type="text/x-red" data-template-name="mqtt-broker">
+    <div class="form-row node-input-broker">
+        <label for="node-config-input-broker"><i class="fa fa-globe"></i> Broker</label>
+        <input class="input-append-left" type="text" id="node-config-input-broker" placeholder="localhost" style="width: 40%;" >
+        <label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
+        <input type="text" id="node-config-input-port" placeholder="Port" style="width:45px">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-clientid"><i class="fa fa-tag"></i> Client ID</label>
+        <input type="text" id="node-config-input-clientid" placeholder="Leave blank for auto generated">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-user"><i class="fa fa-user"></i> Username</label>
+        <input type="text" id="node-config-input-user">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
+        <input type="password" id="node-config-input-password">
+    </div>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('mqtt-broker',{
+        category: 'config',
+        defaults: {
+            broker: {value:"",required:true},
+            port: {value:1883,required:true,validate:RED.validators.number()},
+            clientid: { value:"" }
+        },
+        credentials: {
+            user: {type:"text"},
+            password: {type: "password"}
+        },
+        label: function() {
+            if (this.broker == "") { this.broker = "localhost"; }
+            return (this.clientid?this.clientid+"@":"")+this.broker+":"+this.port;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/10-mqtt.js b/dgbuilder/core_nodes/io/10-mqtt.js
new file mode 100644 (file)
index 0000000..c8bc490
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var connectionPool = require("./lib/mqttConnectionPool");
+
+    function MQTTBrokerNode(n) {
+        RED.nodes.createNode(this,n);
+        this.broker = n.broker;
+        this.port = n.port;
+        this.clientid = n.clientid;
+        if (this.credentials) {
+            this.username = this.credentials.user;
+            this.password = this.credentials.password;
+        }
+    }
+    RED.nodes.registerType("mqtt-broker",MQTTBrokerNode,{
+        credentials: {
+            user: {type:"text"},
+            password: {type: "password"}
+        }
+    });
+
+    function MQTTInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.topic = n.topic;
+        this.broker = n.broker;
+        this.brokerConfig = RED.nodes.getNode(this.broker);
+        if (this.brokerConfig) {
+            this.status({fill:"red",shape:"ring",text:"disconnected"});
+            this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
+            var node = this;
+            this.client.subscribe(this.topic,2,function(topic,payload,qos,retain) {
+                    var msg = {topic:topic,payload:payload,qos:qos,retain:retain};
+                    if ((node.brokerConfig.broker == "localhost")||(node.brokerConfig.broker == "127.0.0.1")) {
+                        msg._topic = topic;
+                    }
+                    node.send(msg);
+            });
+            this.client.on("connectionlost",function() {
+                node.status({fill:"red",shape:"ring",text:"disconnected"});
+            });
+            this.client.on("connect",function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+            });
+            this.client.connect();
+        } else {
+            this.error("missing broker configuration");
+        }
+        this.on('close', function() {
+            if (this.client) {
+                this.client.disconnect();
+            }
+        });
+    }
+    RED.nodes.registerType("mqtt in",MQTTInNode);
+
+    function MQTTOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.topic = n.topic;
+        this.qos = n.qos || null;
+        this.retain = n.retain;
+        this.broker = n.broker;
+        this.brokerConfig = RED.nodes.getNode(this.broker);
+
+        if (this.brokerConfig) {
+            this.status({fill:"red",shape:"ring",text:"disconnected"},true);
+            this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
+            var node = this;
+            this.on("input",function(msg) {
+                if (msg.qos) {
+                    msg.qos = parseInt(msg.qos);
+                    if ((msg.qos !== 0) && (msg.qos !== 1) && (msg.qos !== 2)) {
+                        msg.qos = null;
+                    }
+                }
+                msg.qos = Number(node.qos || msg.qos || 0);
+                msg.retain = node.retain || msg.retain || false;
+                msg.retain = ((msg.retain === true) || (msg.retain === "true")) || false;
+                if (node.topic) {
+                    msg.topic = node.topic;
+                }
+                if ((msg.hasOwnProperty("topic")) && (typeof msg.topic === "string") && (msg.topic !== "")) { // topic must exist
+                    this.client.publish(msg);  // send the message
+                }
+                else { node.warn("Invalid topic specified"); }
+            });
+            this.client.on("connectionlost",function() {
+                node.status({fill:"red",shape:"ring",text:"disconnected"});
+            });
+            this.client.on("connect",function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+            });
+            this.client.connect();
+        } else {
+            this.error("missing broker configuration");
+        }
+        this.on('close', function() {
+            if (this.client) {
+                this.client.disconnect();
+            }
+        });
+    }
+    RED.nodes.registerType("mqtt out",MQTTOutNode);
+}
diff --git a/dgbuilder/core_nodes/io/21-httpin.html b/dgbuilder/core_nodes/io/21-httpin.html
new file mode 100644 (file)
index 0000000..059b859
--- /dev/null
@@ -0,0 +1,254 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="http in">
+    <div class="form-row">
+        <label for="node-input-method"><i class="fa fa-tasks"></i> Method</label>
+        <select type="text" id="node-input-method" style="width:72%;">
+        <option value="get">GET</option>
+        <option value="post">POST</option>
+        <option value="put">PUT</option>
+        <option value="delete">DELETE</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-url"><i class="fa fa-globe"></i> url</label>
+        <input type="text" id="node-input-url" placeholder="/url">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div id="node-input-tip" class="form-tips">The url will be relative to <code><span id="node-input-path"></span></code>.</div>
+</script>
+
+<script type="text/x-red" data-help-name="http in">
+    <p>Provides an input node for http requests, allowing the creation of simple web services.</p>
+    <p>The resulting message has the following properties:
+        <ul>
+            <li>msg.req : <a href="http://expressjs.com/api.html#req">http request</a></li>
+            <li>msg.res : <a href="http://expressjs.com/api.html#res">http response</a></li>
+        </ul>
+    </p>
+    <p>For POST/PUT requests, the body is available under <code>msg.req.body</code>. This
+       uses the <a href="http://expressjs.com/api.html#bodyParser">Express bodyParser middleware</a> to parse the content to a JSON object.
+    </p>
+    <p>
+       By default, this expects the body of the request to be url encoded:
+       <pre>foo=bar&amp;this=that</pre>
+    </p>
+    <p>
+       To send JSON encoded data to the node, the content-type header of the request must be set to
+       <code>application/json</code>.
+    </p>
+    <p>
+       <b>Note: </b>This node does not send any response to the http request. This should be done with
+       a subsequent HTTP Response node, or Function node.
+       In the case of a Function node, the <a href="http://expressjs.com/api.html#res">Express response documentation</a>
+       describes how this should be done. For example:
+       <pre>msg.res.send(200, 'Thanks for the request ');<br/>return msg;</pre>
+    </p>
+
+</script>
+
+<script type="text/x-red" data-template-name="http response">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">The messages sent to this node <b>must</b> originate from an <i>http input</i> node</div>
+</script>
+
+<script type="text/x-red" data-help-name="http response">
+    <p>Sends responses back to http requests received from an HTTP Input node.</p>
+    <p>The response can be customised using the following message properties:</p>
+    <ul>
+        <li><code>payload</code> is sent as the body of the response</li>
+        <li><code>statusCode</code>, if set, is used as the response status code (default: 200)</li>
+        <li><code>headers</code>, if set, should be an object containing field/value
+        pairs to be added as response headers.</li>
+    </ul>
+</script>
+
+<script type="text/x-red" data-template-name="http request">
+    <div class="form-row">
+        <label for="node-input-method"><i class="fa fa-tasks"></i> Method</label>
+        <select type="text" id="node-input-method" style="width:72%;">
+        <option value="GET">GET</option>
+        <option value="POST">POST</option>
+        <option value="PUT">PUT</option>
+        <option value="DELETE">DELETE</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-url"><i class="fa fa-globe"></i> URL</label>
+        <input type="text" id="node-input-url" placeholder="http://">
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-useAuth" style="width: 70%;">Use basic authentication?</label>
+    </div>
+    <div class="form-row node-input-useAuth-row">
+        <label for="node-input-user"><i class="fa fa-user"></i> Username</label>
+        <input type="text" id="node-input-user">
+    </div>
+    <div class="form-row node-input-useAuth-row">
+        <label for="node-input-password"><i class="fa fa-lock"></i> Password</label>
+        <input type="password" id="node-input-password">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="http request">
+    <p>Provides a node for making http requests.</p>
+    <p>The URL and HTTP method can be configured in the node, but also
+       overridden by the incoming message:
+    <ul>
+        <li><code>url</code>, if set, is used as the url of the request. Must start with http: or https:</li>
+        <li><code>method</code>, if set, is used as the HTTP method of the request.
+        Must be one of <code>GET</code>, <code>PUT</code>, <code>POST</code> or <code>DELETE</code> (default: GET)</li>
+        <li><code>headers</code>, if set, should be an object containing field/value
+        pairs to be added as request headers</li>
+        <li><code>payload</code> is sent as the body of the request</li>
+    </ul>
+    <p>When configured within the node, the URL property can contain <a href="http://mustache.github.io/mustache.5.html" target="_new">mustache-style</a> tags. These allow the
+    url to be constructed using values of the incoming message. For example, if the url is set to
+    <code>example.com/{{topic}}</code>, it will have the value of <code>msg.topic</code> automatically inserted.</p>
+    <p>
+    The output message contains the following properties:
+    <ul>
+        <li><code>payload</code> is the body of the response</li>
+        <li><code>statusCode</code> is the status code of the response, or the error code if the request could not be completed</li>
+        <li><code>headers</code> is an object containing the response headers</li>
+    </ul>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('http in',{
+        category: 'input',
+        color:"rgb(231, 231, 174)",
+        defaults: {
+            name: {value:""},
+            url: {value:"",required:true},
+            method: {value:"get",required:true}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "white-globe.png",
+        label: function() {
+            if (this.name) {
+                return this.name;
+            } else if (this.url) {
+                var root = RED.settings.httpNodeRoot;
+                if (root.slice(-1) != "/") { 
+                    root = root+"/";
+                }
+                if (this.url.charAt(0) == "/") {
+                    root += this.url.slice(1);
+                } else {
+                    root += this.url;
+                }
+                return "["+this.method+"] "+root;
+            } else {
+                return "http";
+            }
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            var root = RED.settings.httpNodeRoot;
+            if (root.slice(-1) == "/") { 
+                root = root.slice(0,-1);
+            }
+            if (root == "") {
+                $("#node-input-tip").hide();
+            } else {
+                $("#node-input-path").html(root);
+                $("#node-input-tip").show();
+            }
+            //document.getElementById("node-config-wsdocpath").innerHTML=
+        }
+
+    });
+
+    RED.nodes.registerType('http response',{
+        category: 'output',
+        color:"rgb(231, 231, 174)",
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:0,
+        align: "right",
+        icon: "white-globe.png",
+        label: function() {
+            return this.name||"http";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+
+    RED.nodes.registerType('http request',{
+        category: 'function',
+        color:"rgb(231, 231, 174)",
+        defaults: {
+            name: {value:""},
+            method:{value:"GET"},
+            url:{value:""},
+            //user -> credentials
+            //pass -> credentials
+        },
+        credentials: {
+            user: {type:"text"},
+            password: {type: "password"}
+        },
+        inputs:1,
+        outputs:1,
+        align: "right",
+        icon: "white-globe.png",
+        label: function() {
+            return this.name||"http request";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if (this.credentials.user || this.credentials.has_password) {
+                $('#node-input-useAuth').prop('checked', true);
+                $(".node-input-useAuth-row").show();
+            } else {
+                $('#node-input-useAuth').prop('checked', false);
+                $(".node-input-useAuth-row").hide();
+            }
+
+            $("#node-input-useAuth").change(function() {
+                if ($(this).is(":checked")) {
+                    $(".node-input-useAuth-row").show();
+                } else {
+                    $(".node-input-useAuth-row").hide();
+                    $('#node-input-user').val('');
+                    $('#node-input-password').val('');
+                }
+            });
+        },
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/21-httpin.js b/dgbuilder/core_nodes/io/21-httpin.js
new file mode 100644 (file)
index 0000000..877ccc0
--- /dev/null
@@ -0,0 +1,241 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var http = require("follow-redirects").http;
+    var https = require("follow-redirects").https;
+    var urllib = require("url");
+    var express = require("express");
+    var getBody = require('raw-body');
+    var mustache = require("mustache");
+    var querystring = require("querystring");
+
+    var cors = require('cors');
+    var jsonParser = express.json();
+    var urlencParser = express.urlencoded();
+
+    function rawBodyParser(req, res, next) {
+        if (req._body) { return next(); }
+        req.body = "";
+        req._body = true;
+        getBody(req, {
+            limit: '1mb',
+            length: req.headers['content-length'],
+            encoding: 'utf8'
+        }, function (err, buf) {
+            if (err) { return next(err); }
+            req.body = buf;
+            next();
+        });
+    }
+
+
+    function HTTPIn(n) {
+        RED.nodes.createNode(this,n);
+        if (RED.settings.httpNodeRoot !== false) {
+
+            this.url = n.url;
+            this.method = n.method;
+
+            var node = this;
+
+            this.errorHandler = function(err,req,res,next) {
+                node.warn(err);
+                res.send(500);
+            };
+
+            this.callback = function(req,res) {
+                if (node.method == "post") {
+                    node.send({req:req,res:res,payload:req.body});
+                } else if (node.method == "get") {
+                    node.send({req:req,res:res,payload:req.query});
+                } else {
+                    node.send({req:req,res:res});
+                }
+            }
+
+            var corsHandler = function(req,res,next) { next(); }
+
+            if (RED.settings.httpNodeCors) {
+                corsHandler = cors(RED.settings.httpNodeCors);
+                RED.httpNode.options(this.url,corsHandler);
+            }
+
+            if (this.method == "get") {
+                RED.httpNode.get(this.url,corsHandler,this.callback,this.errorHandler);
+            } else if (this.method == "post") {
+                RED.httpNode.post(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
+            } else if (this.method == "put") {
+                RED.httpNode.put(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
+            } else if (this.method == "delete") {
+                RED.httpNode.delete(this.url,corsHandler,this.callback,this.errorHandler);
+            }
+
+            this.on("close",function() {
+                var routes = RED.httpNode.routes[this.method];
+                for (var i = 0; i<routes.length; i++) {
+                    if (routes[i].path == this.url) {
+                        routes.splice(i,1);
+                        //break;
+                    }
+                }
+                if (RED.settings.httpNodeCors) {
+                    var route = RED.httpNode.route['options'];
+                    for (var j = 0; j<route.length; j++) {
+                        if (route[j].path == this.url) {
+                            route.splice(j,1);
+                            //break;
+                        }
+                    }
+                }
+            });
+        } else {
+            this.warn("Cannot create http-in node when httpNodeRoot set to false");
+        }
+    }
+    RED.nodes.registerType("http in",HTTPIn);
+
+
+    function HTTPOut(n) {
+        RED.nodes.createNode(this,n);
+        var node = this;
+        this.on("input",function(msg) {
+            if (msg.res) {
+                if (msg.headers) {
+                    msg.res.set(msg.headers);
+                }
+                var statusCode = msg.statusCode || 200;
+                if (typeof msg.payload == "object" && !Buffer.isBuffer(msg.payload)) {
+                    msg.res.jsonp(statusCode,msg.payload);
+                } else {
+                    if (msg.res.get('content-length') == null) {
+                        var len;
+                        if (msg.payload == null) {
+                            len = 0;
+                        } else if (typeof msg.payload == "number") {
+                            len = Buffer.byteLength(""+msg.payload);
+                        } else {
+                            len = Buffer.byteLength(msg.payload);
+                        }
+                        msg.res.set('content-length', len);
+                    }
+                    msg.res.send(statusCode,msg.payload);
+                }
+            } else {
+                node.warn("No response object");
+            }
+        });
+    }
+    RED.nodes.registerType("http response",HTTPOut);
+
+    function HTTPRequest(n) {
+        RED.nodes.createNode(this,n);
+        var nodeUrl = n.url;
+        var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
+        var nodeMethod = n.method || "GET";
+        var node = this;
+        this.on("input",function(msg) {
+            node.status({fill:"blue",shape:"dot",text:"requesting"});
+            var url;
+            if (msg.url) {
+                url = msg.url;
+            } else if (isTemplatedUrl) {
+                url = mustache.render(nodeUrl,msg);
+            } else {
+                url = nodeUrl;
+            }
+            // url must start http:// or https:// so assume http:// if not set
+            if (!((url.indexOf("http://")===0) || (url.indexOf("https://")===0))) {
+                url = "http://"+url;
+            }
+
+            var method = (msg.method||nodeMethod).toUpperCase();
+            //node.log(method+" : "+url);
+            var opts = urllib.parse(url);
+            opts.method = method;
+            opts.headers = {};
+            if (msg.headers) {
+                for (var v in msg.headers) {
+                    if (msg.headers.hasOwnProperty(v)) {
+                        var name = v.toLowerCase();
+                        if (name !== "content-type" && name !== "content-length") {
+                            // only normalise the known headers used later in this
+                            // function. Otherwise leave them alone.
+                            name = v;
+                        }
+                        opts.headers[name] = msg.headers[v];
+                    }
+                }
+            }
+            if (this.credentials && this.credentials.user) {
+                opts.auth = this.credentials.user+":"+(this.credentials.password||"");
+            }
+            var payload = null;
+
+            if (msg.payload && (method == "POST" || method == "PUT") ) {
+                if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
+                    payload = msg.payload;
+                } else if (typeof msg.payload == "number") {
+                    payload = msg.payload+"";
+                } else {
+                    if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
+                        payload = querystring.stringify(msg.payload);
+                    } else {
+                        payload = JSON.stringify(msg.payload);
+                        if (opts.headers['content-type'] == null) {
+                            opts.headers['content-type'] = "application/json";
+                        }
+                    }
+                }
+                if (opts.headers['content-length'] == null) {
+                    opts.headers['content-length'] = Buffer.byteLength(payload);
+                }
+            }
+
+            var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
+                res.setEncoding('utf8');
+                msg.statusCode = res.statusCode;
+                msg.headers = res.headers;
+                msg.payload = "";
+                res.on('data',function(chunk) {
+                    msg.payload += chunk;
+                });
+                res.on('end',function() {
+                    node.send(msg);
+                    node.status({});
+                });
+            });
+            req.on('error',function(err) {
+                msg.payload = err.toString() + " : " + url;
+                msg.statusCode = err.code;
+                node.send(msg);
+                node.status({fill:"red",shape:"ring",text:err.code});
+            });
+            if (payload) {
+                req.write(payload);
+            }
+            req.end();
+        });
+    }
+
+    RED.nodes.registerType("http request",HTTPRequest,{
+        credentials: {
+            user: {type:"text"},
+            password: {type: "password"}
+        }
+    });
+}
diff --git a/dgbuilder/core_nodes/io/22-websocket.html b/dgbuilder/core_nodes/io/22-websocket.html
new file mode 100644 (file)
index 0000000..ff6ed74
--- /dev/null
@@ -0,0 +1,163 @@
+<!--\r
+  Copyright 2013 IBM Corp.\r
+\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+\r
+  http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+-->\r
+\r
+<!-- WebSocket Input Node -->\r
+<script type="text/x-red" data-template-name="websocket in">\r
+    <div class="form-row">\r
+        <label for="node-input-server"><i class="fa fa-bookmark"></i> Path</label>\r
+        <input type="text" id="node-input-server">\r
+    </div>\r
+    <div class="form-row">\r
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>\r
+        <input type="text" id="node-input-name" placeholder="Name">\r
+    </div>\r
+</script>\r
+\r
+<script type="text/x-red" data-help-name="websocket in">\r
+    <p>WebSocket input node.</p>\r
+    <p>By default, the data received from the WebSocket will be in <b>msg.payload</b>.\r
+    The listener can be configured to expect a properly formed JSON string, in which\r
+    case it will parse the JSON and send on the resulting object as the entire message.</p>\r
+</script>\r
+\r
+<script type="text/javascript">\r
+    RED.nodes.registerType('websocket in',{\r
+        category: 'input',\r
+        defaults: {\r
+            name: {value:""},\r
+            server: {type:"websocket-listener"}\r
+        },\r
+        color:"rgb(215, 215, 160)",\r
+        inputs:0,\r
+        outputs:1,\r
+        icon: "white-globe.png",\r
+        label: function() {\r
+            var wsNode = RED.nodes.node(this.server);\r
+            return this.name||(wsNode?"[ws] "+wsNode.label():"websocket");\r
+        },\r
+        labelStyle: function() {\r
+            return this.name?"node_label_italic":"";\r
+        }\r
+    });\r
+</script>\r
+\r
+<!-- WebSocket out Node -->\r
+<script type="text/x-red" data-template-name="websocket out">\r
+    <div class="form-row">\r
+        <label for="node-input-server"><i class="fa fa-bookmark"></i> Path</label>\r
+        <input type="text" id="node-input-server">\r
+    </div>\r
+    <div class="form-row">\r
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>\r
+        <input type="text" id="node-input-name" placeholder="Name">\r
+    </div>\r
+</script>\r
+\r
+<script type="text/x-red" data-help-name="websocket out">\r
+    <p>WebSocket out node.</p>\r
+    <p>By default, <b>msg.payload</b> will be sent over the WebSocket. The listener\r
+    can be configured to encode the entire message object as a JSON string and send that\r
+    over the WebSocket.</p>\r
+\r
+    <p>If the message arriving at this node started at a WebSocket In node, the message\r
+    will be sent back to the client that triggered the flow. Otherwise, the message\r
+    will be broadcast to all connected clients.</p>\r
+    <p>If you want to broadcast a message that started at a WebSocket In node, you\r
+    should delete the <b>msg._session</b> property within the flow</p>.\r
+</script>\r
+\r
+<script type="text/javascript">\r
+    RED.nodes.registerType('websocket out',{\r
+        category: 'output',\r
+        defaults: {\r
+            name: {value:""},\r
+            server: {type:"websocket-listener", required:true}\r
+        },\r
+        color:"rgb(215, 215, 160)",\r
+        inputs:1,\r
+        outputs:0,\r
+        icon: "white-globe.png",\r
+        align: "right",\r
+        label: function() {\r
+            var wsNode = RED.nodes.node(this.server);\r
+            return this.name||(wsNode?"[ws] "+wsNode.label():"websocket");\r
+        },\r
+        labelStyle: function() {\r
+            return this.name?"node_label_italic":"";\r
+        }\r
+    });\r
+</script>\r
+\r
+<!-- WebSocket Server configuration node -->\r
+<script type="text/x-red" data-template-name="websocket-listener">\r
+    <div class="form-row">\r
+        <label for="node-config-input-path"><i class="fa fa-bookmark"></i> Path</label>\r
+        <input type="text" id="node-config-input-path" placeholder="/ws/example">\r
+    </div>\r
+    <div class="form-row">\r
+        <label for="node-config-input-wholemsg">&nbsp;</label>\r
+        <select type="text" id="node-config-input-wholemsg" style="width: 70%;">\r
+            <option value="false">Send/Receive payload</option>\r
+            <option value="true">Send/Receive entire message</option>\r
+        </select>\r
+    </div>\r
+    <div class="form-tips">\r
+    Be default, <code>payload</code> will contain the data to be sent over, or received from a websocket.\r
+    The listener can be configured to send or receive the entire message object as a JSON formatted string.\r
+    <p id="node-config-ws-tip">This path will be relative to <code><span id="node-config-ws-path"></span></code>.</p>\r
+    </div>\r
+</script>\r
+\r
+<script type="text/x-red" data-help-name="websocket-listener">\r
+   <p>This configuration node creates a WebSocket Server using the specified path</p>\r
+</script>\r
+\r
+<script type="text/javascript">\r
+    RED.nodes.registerType('websocket-listener',{\r
+        category: 'config',\r
+        defaults: {\r
+            path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },\r
+            wholemsg: {value:"false"}\r
+        },\r
+        inputs:0,\r
+        outputs:0,\r
+        label: function() {\r
+            var root = RED.settings.httpNodeRoot;\r
+            if (root.slice(-1) != "/") { \r
+                root = root+"/";\r
+            }\r
+            if (this.path.charAt(0) == "/") {\r
+                root += this.path.slice(1);\r
+            } else {\r
+                root += this.path;\r
+            }\r
+            return root;\r
+        },\r
+        oneditprepare: function() {\r
+            var root = RED.settings.httpNodeRoot;\r
+            if (root.slice(-1) == "/") { \r
+                root = root.slice(0,-1);\r
+            }\r
+            if (root == "") {\r
+                $("#node-config-ws-tip").hide();\r
+            } else {\r
+                $("#node-config-ws-path").html(root);\r
+                $("#node-config-ws-tip").show();\r
+            }\r
+            //document.getElementById("node-config-wsdocpath").innerHTML=\r
+        }\r
+    });\r
+</script>\r
diff --git a/dgbuilder/core_nodes/io/22-websocket.js b/dgbuilder/core_nodes/io/22-websocket.js
new file mode 100644 (file)
index 0000000..72eda50
--- /dev/null
@@ -0,0 +1,185 @@
+/**\r
+ * Copyright 2013 IBM Corp.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ **/\r
+\r
+module.exports = function(RED) {\r
+    "use strict";\r
+    var ws = require("ws"),\r
+        inspect = require("sys").inspect;\r
+\r
+    // A node red node that sets up a local websocket server\r
+    function WebSocketListenerNode(n) {\r
+        // Create a RED node\r
+        RED.nodes.createNode(this,n);\r
+\r
+        var node = this;\r
+\r
+        // Store local copies of the node configuration (as defined in the .html)\r
+        node.path = n.path;\r
+        node.wholemsg = (n.wholemsg === "true");\r
+\r
+        node._inputNodes = [];    // collection of nodes that want to receive events\r
+\r
+        var path = RED.settings.httpNodeRoot || "/";\r
+        path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);\r
+\r
+        // Workaround https://github.com/einaros/ws/pull/253\r
+        // Listen for 'newListener' events from RED.server\r
+        node._serverListeners = {};\r
+\r
+        var storeListener = function(/*String*/event,/*function*/listener){\r
+            if(event == "error" || event == "upgrade" || event == "listening"){\r
+                node._serverListeners[event] = listener;\r
+            }\r
+        }\r
+\r
+        node._clients = {};\r
+\r
+        RED.server.addListener('newListener',storeListener);\r
+\r
+        // Create a WebSocket Server\r
+        node.server = new ws.Server({server:RED.server,path:path});\r
+\r
+        // Workaround https://github.com/einaros/ws/pull/253\r
+        // Stop listening for new listener events\r
+        RED.server.removeListener('newListener',storeListener);\r
+\r
+        node.server.on('connection', function(socket){\r
+            var id = (1+Math.random()*4294967295).toString(16);\r
+            node._clients[id] = socket;\r
+            socket.on('close',function() {\r
+                delete node._clients[id];\r
+            });\r
+            socket.on('message',function(data,flags){\r
+                node.handleEvent(id,socket,'message',data,flags);\r
+            });\r
+            socket.on('error', function(err) {\r
+                node.warn("An error occured on the ws connection: "+inspect(err));\r
+            });\r
+        });\r
+\r
+        node.on("close", function() {\r
+            // Workaround https://github.com/einaros/ws/pull/253\r
+            // Remove listeners from RED.server\r
+            var listener = null;\r
+            for(var event in node._serverListeners) {\r
+                if (node._serverListeners.hasOwnProperty(event)) {\r
+                    listener = node._serverListeners[event];\r
+                    if(typeof listener === "function"){\r
+                        RED.server.removeListener(event,listener);\r
+                    }\r
+                }\r
+            }\r
+            node._serverListeners = {};\r
+            node.server.close();\r
+            node._inputNodes = [];\r
+        });\r
+    }\r
+    RED.nodes.registerType("websocket-listener",WebSocketListenerNode);\r
+\r
+    WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler){\r
+        this._inputNodes.push(handler);\r
+    }\r
+\r
+    WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){\r
+        var msg;\r
+        if (this.wholemsg) {\r
+            try {\r
+                msg = JSON.parse(data);\r
+            }\r
+            catch(err) {\r
+                msg = { payload:data };\r
+            }\r
+        } else {\r
+            msg = {\r
+                payload:data\r
+            };\r
+        }\r
+        msg._session = {type:"websocket",id:id};\r
+\r
+        for (var i = 0; i < this._inputNodes.length; i++) {\r
+            this._inputNodes[i].send(msg);\r
+        }\r
+    }\r
+\r
+    WebSocketListenerNode.prototype.broadcast = function(data){\r
+        try {\r
+            for (var i = 0; i < this.server.clients.length; i++) {\r
+                this.server.clients[i].send(data);\r
+            }\r
+        }\r
+        catch(e) { // swallow any errors\r
+            this.warn("ws:"+i+" : "+e);\r
+        }\r
+    }\r
+\r
+    WebSocketListenerNode.prototype.send = function(id,data) {\r
+        var session = this._clients[id];\r
+        if (session) {\r
+            try {\r
+                session.send(data);\r
+            }\r
+            catch(e) { // swallow any errors\r
+            }\r
+        }\r
+    }\r
+\r
+    function WebSocketInNode(n) {\r
+        RED.nodes.createNode(this,n);\r
+        this.server = n.server;\r
+        var node = this;\r
+        this.serverConfig = RED.nodes.getNode(this.server);\r
+        if (this.serverConfig) {\r
+            this.serverConfig.registerInputNode(this);\r
+        } else {\r
+            this.error("Missing server configuration");\r
+        }\r
+    }\r
+    RED.nodes.registerType("websocket in",WebSocketInNode);\r
+\r
+    function WebSocketOutNode(n) {\r
+        RED.nodes.createNode(this,n);\r
+        var node = this;\r
+        this.server = n.server;\r
+        this.serverConfig = RED.nodes.getNode(this.server);\r
+        if (!this.serverConfig) {\r
+            this.error("Missing server configuration");\r
+        }\r
+        this.on("input", function(msg) {\r
+            var payload;\r
+            if (this.serverConfig.wholemsg) {\r
+                delete msg._session;\r
+                payload = JSON.stringify(msg);\r
+            } else {\r
+                if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string.\r
+                    payload = RED.util.ensureString(msg.payload);\r
+                }\r
+                else {\r
+                    payload = msg.payload;\r
+                }\r
+            }\r
+            if (msg._session && msg._session.type == "websocket") {\r
+                node.serverConfig.send(msg._session.id,payload);\r
+            } else {\r
+                node.serverConfig.broadcast(payload,function(error){\r
+                    if (!!error) {\r
+                        node.warn("An error occurred while sending:" + inspect(error));\r
+                    }\r
+                });\r
+            }\r
+        });\r
+    }\r
+    RED.nodes.registerType("websocket out",WebSocketOutNode);\r
+}\r
diff --git a/dgbuilder/core_nodes/io/23-watch.html b/dgbuilder/core_nodes/io/23-watch.html
new file mode 100644 (file)
index 0000000..8bf22be
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="watch">
+    <div class="form-row node-input-filename">
+         <label for="node-input-files"><i class="fa fa-file"></i> File(s)</label>
+         <input type="text" id="node-input-files" placeholder="File(s) or Directory">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+     <div id="node-input-tip" class="form-tips">On Windows you must use double slashes \\ in any directory names.</div>
+</script>
+
+<script type="text/x-red" data-help-name="watch">
+    <p>Watches a directory or file for any changes.</p>
+    <p>You can enter a list of comma separated directories or files if you like. You will need to put " around any that have spaces in.</p>
+    <p>On Windows you must use double slashes \\ in any directory names.</p>
+    <p>The full filename of the file that actually changed is put into <b>msg.payload</b>, while a stringified version of the watched criteria is returned in <b>msg.topic</b>.</p>
+    <p><b>msg.file</b> contains just the short filename of the file that changed.</p>
+    <p>Of course in Linux, <i>everything</i> could be a file and thus watched...</p>
+    <p><b>Note: </b>The directory or file must exist in order to be watched. If the file or directory gets deleted it may no longer be monitored even if it gets re-created.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('watch',{
+        category: 'advanced-input',
+        defaults: {
+            name: {value:""},
+            files: {value:"",required:true}
+        },
+        color:"BurlyWood",
+        inputs:0,
+        outputs:1,
+        icon: "watch.png",
+        label: function() {
+            return this.name||this.files;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/23-watch.js b/dgbuilder/core_nodes/io/23-watch.js
new file mode 100644 (file)
index 0000000..8a17f5a
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var Notify = require("fs.notify");
+    var fs = require("fs");
+    var sep = require("path").sep;
+
+    function WatchNode(n) {
+        RED.nodes.createNode(this,n);
+
+        this.files = n.files.split(",");
+        for (var f =0; f < this.files.length; f++) {
+            this.files[f] = this.files[f].trim();
+        }
+        this.p = (this.files.length == 1) ? this.files[0] : JSON.stringify(this.files);
+        var node = this;
+
+        var notifications = new Notify(node.files);
+        notifications.on('change', function (file, event, path) {
+            try {
+                if (fs.statSync(path).isDirectory()) { path = path + sep + file; }
+            } catch(e) { }
+            var msg = { payload: path, topic: node.p, file: file };
+            node.send(msg);
+        });
+
+        notifications.on('error', function (error, path) {
+            node.warn(error);
+        });
+
+        this.close = function() {
+            notifications.close();
+        }
+    }
+    RED.nodes.registerType("watch",WatchNode);
+}
diff --git a/dgbuilder/core_nodes/io/25-serial.html b/dgbuilder/core_nodes/io/25-serial.html
new file mode 100644 (file)
index 0000000..225e4dc
--- /dev/null
@@ -0,0 +1,265 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="serial in">
+    <div class="form-row node-input-serial">
+        <label for="node-input-serial"><i class="fa fa-random"></i> Serial Port</label>
+        <input type="text" id="node-input-serial">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="serial in">
+    <p>Reads data from a local serial port.</p>
+    <p>Can either <ul><li>wait for a "split" character (default \n). Also accepts hex notation (0x0a).</li>
+    <li>Wait for a timeout in milliseconds for the first character received</li>
+    <li>Wait to fill a fixed sized buffer</li></ul></p>
+    <p>It then outputs <b>msg.payload</b> as either a UTF8 ascii string or a binary Buffer object.</p>
+    <p>If no split character is specified, or a timeout or buffer size of 0, then a stream of single characters is sent - again either as ascii chars or size 1 binary buffers.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('serial in',{
+        category: 'input',
+        defaults: {
+            name: {name:""},
+            serial: {type:"serial-port",required:true}
+        },
+        color:"BurlyWood",
+        inputs:0,
+        outputs:1,
+        icon: "serial.png",
+        label: function() {
+            var serialNode = RED.nodes.node(this.serial);
+            return this.name||(serialNode?serialNode.label().split(":")[0]:"serial");
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+<script type="text/x-red" data-template-name="serial out">
+    <div class="form-row node-input-serial">
+        <label for="node-input-serial"><i class="fa fa-random"></i> Serial Port</label>
+        <input type="text" id="node-input-serial">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="serial out">
+    <p>Provides a connection to an outbound serial port.</p>
+    <p>Only the <b>msg.payload</b> is sent.</p>
+    <p>Optionally the new line character used to split the input can be appended to every message sent out to the serial port.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('serial out',{
+        category: 'output',
+        defaults: {
+            name: {name:""},
+            serial: {type:"serial-port",required:true}
+        },
+        color:"BurlyWood",
+        inputs:1,
+        outputs:0,
+        icon: "serial.png",
+        align: "right",
+        label: function() {
+            var serialNode = RED.nodes.node(this.serial);
+            return this.name||(serialNode?serialNode.label().split(":")[0]:"serial");
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="serial-port">
+    <div class="form-row">
+        <label for="node-config-input-serialport"><i class="fa fa-random"></i> Serial Port</label>
+        <input type="text" id="node-config-input-serialport" style="width:60%;" placeholder="/dev/ttyUSB0"/>
+        <a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
+    </div>
+    <div class="form-row">
+        <table><tr>
+            <td width = "102px"><i class="fa fa-wrench"></i> Settings</td>
+            <td width = "100px">Baud Rate</td>
+            <td width = "80px">Data Bits</td>
+            <td width = "80px">Parity</td>
+            <td width = "80px">Stop Bits</td>
+        </tr><tr><td>&nbsp;</td>
+        <td>
+        <select type="text" id="node-config-input-serialbaud" style="width: 100px;">
+            <option value="115200">115200</option>
+            <option value="57600">57600</option>
+            <option value="38400">38400</option>
+            <option value="19200">19200</option>
+            <option value="9600">9600</option>
+            <option value="4800">4800</option>
+            <option value="2400">2400</option>
+            <option value="1800">1800</option>
+            <option value="1200">1200</option>
+            <option value="600">600</option>
+            <option value="300">300</option>
+            <option value="200">200</option>
+            <option value="150">150</option>
+            <option value="134">134</option>
+            <option value="110">110</option>
+            <option value="75">75</option>
+            <option value="50">50</option>
+        </select>
+        </td><td>
+        <select type="text" id="node-config-input-databits" style="width: 80px;">
+            <option value="8">8</option>
+            <option value="7">7</option>
+            <option value="6">6</option>
+            <option value="5">5</option>
+        </select>
+        </td><td>
+        <select type="text" id="node-config-input-parity" style="width: 80px;">
+            <option value="none">None</option>
+            <option value="even">Even</option>
+            <option value="mark">Mark</option>
+            <option value="odd">Odd</option>
+            <option value="space">Space</option>
+        </select>
+        </td><td>
+        <select type="text" id="node-config-input-stopbits" style="width: 80px;">
+            <option value="2">2</option>
+            <option value="1">1</option>
+        </select>
+    </td>
+    </tr></table><br/>
+
+    <div class="form-row">
+        <label for="node-config-input-out"><i class="fa fa-cut"></i> Split input</label>
+        <select type="text" id="node-config-input-out" style="width:52%;">
+            <option value="char">when character received is</option>
+            <option value="time">after a fixed timeout of</option>
+            <option value="count">a fixed number of characters</option>
+        </select>
+        <input type="text" id="node-config-input-newline"  style="width:50px;">
+        <span id="node-units"></span>
+    </div>
+
+    <div class="form-row">
+        <label for="node-config-input-bin"><i class="fa fa-sign-in"></i> and deliver</label>
+        <select type="text" id="node-config-input-bin" style="width: 77%;">
+            <option value="false">ascii strings</option>
+            <option value="bin">binary buffers</option>
+        </select>
+    </div>
+    <br/>
+    <div class="form-row" id="node-config-addchar">
+        <label for="node-config-input-addchar"><i class="fa fa-sign-out"></i> On output</label>
+        <select type="text" id="node-config-input-addchar" style="width: 77%;">
+            <option value="false">don't add 'split' character to output messages</option>
+            <option value="true">add 'split' character to output messages</option>
+        </select>
+    </div>
+    <div class="form-tips" id="tip-split">Tip: the "Split on" character is used to split the input into separate messages. It can also be added to every message sent out to the serial port.</div>
+    <div class="form-tips" id="tip-bin" hidden>Tip: In timeout mode timeout starts from arrival of first character.</div>
+    <script>
+        var previous = null;
+        $("#node-config-input-out").on('focus', function () { previous = this.value; }).change(function() {
+            if (previous == null) { previous = $("#node-config-input-out").val(); }
+            if ($("#node-config-input-out").val() == "char") {
+                if (previous != "char") { $("#node-config-input-newline").val("\\n"); }
+                $("#node-units").text("");
+                $("#node-config-addchar").show();
+                $("#tip-split").show();
+                $("#tip-bin").hide();
+            }
+            else if ($("#node-config-input-out").val() == "time") {
+                if (previous != "time") { $("#node-config-input-newline").val("0"); }
+                $("#node-units").text("ms");
+                $("#node-config-addchar").hide();
+                $("#node-config-input-addchar").val("false");
+                $("#tip-split").hide();
+                $("#tip-bin").show();
+            }
+            else {
+                if (previous != "count") { $("#node-config-input-newline").val("12"); }
+                $("#node-units").text("chars");
+                $("#node-config-addchar").hide();
+                $("#node-config-input-addchar").val("false");
+                $("#tip-split").hide();
+                $("#tip-bin").hide();
+            }
+        });
+
+    </script>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('serial-port',{
+        category: 'config',
+        defaults: {
+            //name: {value:""},
+            serialport: {value:"",required:true},
+            serialbaud: {value:57600,required:true},
+            databits: {value:8,required:true},
+            parity: {value:"none",required:true},
+            stopbits: {value:1,required:true},
+            newline: {value:"\\n"},
+            bin: {value:""},
+            out: {value:""},
+            addchar: {value:false}
+        },
+        label: function() {
+            this.serialbaud = this.serialbaud || 57600;
+            this.databits = this.databits || 8;
+            this.parity = this.parity || 'none';
+            this.stopbits = this.stopbits || 1;
+            return this.serialport+":"+this.serialbaud+"-"+this.databits+this.parity.charAt(0).toUpperCase()+this.stopbits;
+        },
+        oneditprepare: function() {
+            try {
+                $("#node-config-input-serialport").autocomplete( "destroy" );
+            } catch(err) {
+            }
+            $("#node-config-lookup-serial").click(function() {
+                //$("#node-config-lookup-serial-icon").removeClass('fa fa-search');
+                //$("#node-config-lookup-serial-icon").addClass('fa fa-spinner');
+                $("#node-config-lookup-serial").addClass('disabled');
+                $.getJSON('serialports',function(data) {
+                    //$("#node-config-lookup-serial-icon").addClass('fa fa-search');
+                    //$("#node-config-lookup-serial-icon").removeClass('fa fa-spinner');
+                    $("#node-config-lookup-serial").removeClass('disabled');
+                    var ports = [];
+                    $.each(data, function(i, port){
+                        ports.push(port.comName);
+                    });
+                    $("#node-config-input-serialport").autocomplete({
+                        source:ports,
+                        minLength:0,
+                        close: function( event, ui ) {
+                            $("#node-config-input-serialport").autocomplete( "destroy" );
+                        }
+                    }).autocomplete("search","");
+                });
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/25-serial.js b/dgbuilder/core_nodes/io/25-serial.js
new file mode 100644 (file)
index 0000000..96e4aca
--- /dev/null
@@ -0,0 +1,310 @@
+/**
+* Copyright 2013,2014 IBM Corp.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
+module.exports = function(RED) {
+    "use strict";
+    var settings = RED.settings;
+    var events = require("events");
+    var util = require("util");
+    var serialp = require("serialport");
+    var bufMaxSize = 32768;  // Max serial buffer size, for inputs...
+
+    // TODO: 'serialPool' should be encapsulated in SerialPortNode
+
+    function SerialPortNode(n) {
+        RED.nodes.createNode(this,n);
+        this.serialport = n.serialport;
+        this.newline = n.newline;
+        this.addchar = n.addchar || "false";
+        this.serialbaud = parseInt(n.serialbaud) || 57600;
+        this.databits = parseInt(n.databits) || 8;
+        this.parity = n.parity || "none";
+        this.stopbits = parseInt(n.stopbits) || 1;
+        this.bin = n.bin || "false";
+        this.out = n.out || "char";
+    }
+    RED.nodes.registerType("serial-port",SerialPortNode);
+
+    function SerialOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.serial = n.serial;
+        this.serialConfig = RED.nodes.getNode(this.serial);
+
+        if (this.serialConfig) {
+            var node = this;
+            node.port = serialPool.get(this.serialConfig.serialport,
+                this.serialConfig.serialbaud,
+                this.serialConfig.databits,
+                this.serialConfig.parity,
+                this.serialConfig.stopbits,
+                this.serialConfig.newline);
+            node.addCh = "";
+            if (node.serialConfig.addchar == "true") {
+                node.addCh = this.serialConfig.newline.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0");
+            }
+            node.on("input",function(msg) {
+                var payload = msg.payload;
+                if (!Buffer.isBuffer(payload)) {
+                    if (typeof payload === "object") {
+                        payload = JSON.stringify(payload);
+                    } else {
+                        payload = payload.toString();
+                    }
+                    payload += node.addCh;
+                } else if (node.addCh !== "") {
+                    payload = Buffer.concat([payload,new Buffer(node.addCh)]);
+                }
+                node.port.write(payload,function(err,res) {
+                    if (err) {
+                        node.error(err);
+                    }
+                });
+            });
+            node.port.on('ready', function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+            });
+            node.port.on('closed', function() {
+                node.status({fill:"red",shape:"ring",text:"not connected"});
+            });
+        } else {
+            this.error("missing serial config");
+        }
+
+        this.on("close", function(done) {
+            if (this.serialConfig) {
+                serialPool.close(this.serialConfig.serialport,done);
+            } else {
+                done();
+            }
+        });
+    }
+    RED.nodes.registerType("serial out",SerialOutNode);
+
+
+    function SerialInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.serial = n.serial;
+        this.serialConfig = RED.nodes.getNode(this.serial);
+
+        if (this.serialConfig) {
+            var node = this;
+            node.tout = null;
+            var buf;
+            if (node.serialConfig.out != "count") { buf = new Buffer(bufMaxSize); }
+            else { buf = new Buffer(Number(node.serialConfig.newline)); }
+            var i = 0;
+            node.status({fill:"grey",shape:"dot",text:"unknown"});
+            node.port = serialPool.get(this.serialConfig.serialport,
+                this.serialConfig.serialbaud,
+                this.serialConfig.databits,
+                this.serialConfig.parity,
+                this.serialConfig.stopbits,
+                this.serialConfig.newline
+            );
+
+            var splitc;
+            if (node.serialConfig.newline.substr(0,2) == "0x") {
+                splitc = new Buffer([parseInt(node.serialConfig.newline)]);
+            } else {
+                splitc = new Buffer(node.serialConfig.newline.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0"));
+            }
+
+            this.port.on('data', function(msg) {
+                // single char buffer
+                if ((node.serialConfig.newline === 0)||(node.serialConfig.newline === "")) {
+                    if (node.serialConfig.bin !== "bin") { node.send({"payload": String.fromCharCode(msg)}); }
+                    else { node.send({"payload": new Buffer([msg])}); }
+                }
+                else {
+                    // do the timer thing
+                    if (node.serialConfig.out === "time")  {
+                        if (node.tout) {
+                            i += 1;
+                            buf[i] = msg;
+                        }
+                        else {
+                            node.tout = setTimeout(function () {
+                                node.tout = null;
+                                var m = new Buffer(i+1);
+                                buf.copy(m,0,0,i+1);
+                                if (node.serialConfig.bin !== "bin") { m = m.toString(); }
+                                node.send({"payload": m});
+                                m = null;
+                            }, node.serialConfig.newline);
+                            i = 0;
+                            buf[0] = msg;
+                        }
+                    }
+                    // count bytes into a buffer...
+                    else if (node.serialConfig.out === "count") {
+                        buf[i] = msg;
+                        i += 1;
+                        if ( i >= parseInt(node.serialConfig.newline)) {
+                            var m = new Buffer(i);
+                            buf.copy(m,0,0,i);
+                            if (node.serialConfig.bin !== "bin") { m = m.toString(); }
+                            node.send({"payload":m});
+                            m = null;
+                            i = 0;
+                        }
+                    }
+                    // look to match char...
+                    else if (node.serialConfig.out === "char") {
+                        buf[i] = msg;
+                        i += 1;
+                        if ((msg === splitc[0]) || (i === bufMaxSize)) {
+                            var m = new Buffer(i);
+                            buf.copy(m,0,0,i);
+                            if (node.serialConfig.bin !== "bin") { m = m.toString(); }
+                            node.send({"payload":m});
+                            m = null;
+                            i = 0;
+                        }
+                    }
+                    else { console.log("Should never get here"); }
+                }
+            });
+            this.port.on('ready', function() {
+                node.status({fill:"green",shape:"dot",text:"connected"});
+            });
+            this.port.on('closed', function() {
+                node.status({fill:"red",shape:"ring",text:"not connected"});
+            });
+        } else {
+            this.error("missing serial config");
+        }
+
+        this.on("close", function(done) {
+            if (this.serialConfig) {
+                serialPool.close(this.serialConfig.serialport,done);
+            } else {
+                done();
+            }
+        });
+    }
+    RED.nodes.registerType("serial in",SerialInNode);
+
+
+    var serialPool = function() {
+        var connections = {};
+        return {
+            get:function(port,baud,databits,parity,stopbits,newline,callback) {
+                var id = port;
+                if (!connections[id]) {
+                    connections[id] = function() {
+                        var obj = {
+                            _emitter: new events.EventEmitter(),
+                            serial: null,
+                            _closing: false,
+                            tout: null,
+                            on: function(a,b) { this._emitter.on(a,b); },
+                            close: function(cb) { this.serial.close(cb); },
+                            write: function(m,cb) { this.serial.write(m,cb); },
+                        }
+                        //newline = newline.replace("\\n","\n").replace("\\r","\r");
+                        var setupSerial = function() {
+                            //if (newline == "") {
+                                obj.serial = new serialp.SerialPort(port,{
+                                    baudrate: baud,
+                                    databits: databits,
+                                    parity: parity,
+                                    stopbits: stopbits,
+                                    parser: serialp.parsers.raw
+                                },true, function(err, results) { if (err) { obj.serial.emit('error',err); } });
+                            //}
+                            //else {
+                            //    obj.serial = new serialp.SerialPort(port,{
+                            //        baudrate: baud,
+                            //        databits: databits,
+                            //        parity: parity,
+                            //        stopbits: stopbits,
+                            //        parser: serialp.parsers.readline(newline)
+                            //    },true, function(err, results) { if (err) obj.serial.emit('error',err); });
+                            //}
+                            obj.serial.on('error', function(err) {
+                                util.log("[serial] serial port "+port+" error "+err);
+                                obj._emitter.emit('closed');
+                                obj.tout = setTimeout(function() {
+                                    setupSerial();
+                                }, settings.serialReconnectTime);
+                            });
+                            obj.serial.on('close', function() {
+                                if (!obj._closing) {
+                                    util.log("[serial] serial port "+port+" closed unexpectedly");
+                                    obj._emitter.emit('closed');
+                                    obj.tout = setTimeout(function() {
+                                        setupSerial();
+                                    }, settings.serialReconnectTime);
+                                }
+                            });
+                            obj.serial.on('open',function() {
+                                util.log("[serial] serial port "+port+" opened at "+baud+" baud "+databits+""+parity.charAt(0).toUpperCase()+stopbits);
+                                if (obj.tout) { clearTimeout(obj.tout); }
+                                //obj.serial.flush();
+                                obj._emitter.emit('ready');
+                            });
+                            obj.serial.on('data',function(d) {
+                                //console.log(Buffer.isBuffer(d),d.length,d);
+                                //if (typeof d !== "string") {
+                                //    //d = d.toString();
+                                    for (var z=0; z<d.length; z++) {
+                                        obj._emitter.emit('data',d[z]);
+                                    }
+                                //}
+                                //else {
+                                //    obj._emitter.emit('data',d);
+                                //}
+                            });
+                            obj.serial.on("disconnect",function() {
+                                util.log("[serial] serial port "+port+" gone away");
+                            });
+                        }
+                        setupSerial();
+                        return obj;
+                    }();
+                }
+                return connections[id];
+            },
+            close: function(port,done) {
+                if (connections[port]) {
+                    if (connections[port].tout != null) {
+                        clearTimeout(connections[port].tout);
+                    }
+                    connections[port]._closing = true;
+                    try {
+                        connections[port].close(function() {
+                            util.log("[serial] serial port closed");
+                            done();
+                        });
+                    }
+                    catch(err) { }
+                    delete connections[port];
+                } else {
+                    done();
+                }
+            }
+        }
+    }();
+
+    RED.httpAdmin.get("/serialports",function(req,res) {
+        serialp.list(function (err, ports) {
+            //console.log(JSON.stringify(ports));
+            res.writeHead(200, {'Content-Type': 'text/plain'});
+            res.write(JSON.stringify(ports));
+            res.end();
+        });
+    });
+}
diff --git a/dgbuilder/core_nodes/io/31-tcpin.html b/dgbuilder/core_nodes/io/31-tcpin.html
new file mode 100644 (file)
index 0000000..c8cec59
--- /dev/null
@@ -0,0 +1,299 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="tcp in">
+    <div class="form-row">
+        <label for="node-input-server"><i class="fa fa-dot-circle-o"></i> Type</label>
+        <select id="node-input-server" style="width:120px; margin-right:5px;">
+            <option value="server">Listen on</option>
+            <option value="client">Connect to</option>
+        </select>
+        port <input type="text" id="node-input-port" style="width: 50px">
+    </div>
+    <div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
+        at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
+    </div>
+
+    <div class="form-row">
+        <label><i class="fa fa-sign-out"></i> Output</label>
+        a
+        <select id="node-input-datamode" style="width:110px;">
+            <option value="stream">stream of</option>
+            <option value="single">single</option>
+        </select>
+        <select id="node-input-datatype" style="width:140px;">
+            <option value="buffer">Buffer</option>
+            <option value="utf8">String</option>
+            <option value="base64">Base64 String</option>
+        </select>
+        payload<span id="node-input-datamode-plural">s</span>
+    </div>
+
+    <div id="node-row-newline" class="form-row hidden" style="padding-left: 110px;">
+        delimited by <input type="text" id="node-input-newline" style="width: 110px;">
+    </div>
+
+    <div class="form-row">
+        <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
+        <input type="text" id="node-input-topic" placeholder="Topic">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="tcp in">
+    <p>Provides a choice of tcp inputs. Can either connect to a remote tcp port,
+       or accept incoming connections.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('tcp in',{
+        category: 'input',
+        color:"Silver",
+        defaults: {
+            server: {value:"server",required:true},
+            host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
+            port: {value:"",required:true,validate:RED.validators.number()},
+            datamode:{value:"stream"},
+            datatype:{value:"buffer"},
+            newline:{value:""},
+            topic: {value:""},
+            name: {value:""},
+            base64: {/*deprecated*/ value:false,required:true}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "bridge-dash.png",
+        label: function() {
+            return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            var updateOptions = function() {
+                var sockettype = $("#node-input-server option:selected").val();
+                if (sockettype == "client") {
+                    $("#node-input-host-row").show();
+                } else {
+                    $("#node-input-host-row").hide();
+                }
+                var datamode = $("#node-input-datamode option:selected").val();
+                var datatype = $("#node-input-datatype option:selected").val();
+                if (datamode == "stream") {
+                    $("#node-input-datamode-plural").show();
+                    if (datatype == "utf8") {
+                        $("#node-row-newline").show();
+                    } else {
+                        $("#node-row-newline").hide();
+                    }
+                } else {
+                    $("#node-input-datamode-plural").hide();
+                    $("#node-row-newline").hide();
+                }
+            };
+            updateOptions();
+            $("#node-input-server").change(updateOptions);
+            $("#node-input-datatype").change(updateOptions);
+            $("#node-input-datamode").change(updateOptions);
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="tcp out">
+    <div class="form-row">
+        <label for="node-input-beserver"><i class="fa fa-dot-circle-o"></i> Type</label>
+        <select id="node-input-beserver" style="width:150px; margin-right:5px;">
+            <option value="server">Listen on</option>
+            <option value="client">Connect to</option>
+            <option value="reply">Reply to TCP</option>
+        </select>
+        <span id="node-input-port-row">port <input type="text" id="node-input-port" style="width: 50px"></span>
+    </div>
+
+    <div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
+        at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
+    </div>
+
+    <div class="form-row hidden" id="node-input-end-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-end" style="width: 70%;">Close connection after each message is sent ?</label>
+    </div>
+
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-base64" style="width: 70%;">Decode Base64 message ?</label>
+    </div>
+
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+
+    <div class="form-tips hidden" id="fin-tip">
+        <b>Note:</b> Closing the connection after each message is generally not a good thing - but is useful to indicate an end-of-file for example.
+    </div>
+    <div class="form-tips hidden" id="fin-tip2">
+        <b>Note:</b> Closing the connection after each message is generally not a good thing - but is useful to indicate an end-of-file for example. The receiving client will need to reconnect.
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="tcp out">
+    <p>Provides a choice of tcp outputs. Can either connect to a remote tcp port,
+    accept incoming connections, or reply to messages received from a TCP In node.</p>
+    <p>Only <b>msg.payload</b> is sent.</p>
+    <p>If <b>msg.payload</b> is a string containing a Base64 encoding of binary
+    data, the Base64 decoding option will cause it to be converted back to binary
+    before being sent.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('tcp out',{
+        category: 'output',
+        color:"Silver",
+        defaults: {
+            host: {value:"",validate:function(v) { return (this.beserver != "client")||v.length > 0;} },
+            port: {value:"",validate:function(v) { return (this.beserver == "reply")||RED.validators.number()(v) } },
+            beserver: {value:"client",required:true},
+            base64: {value:false,required:true},
+            end: {value:false,required:true},
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:0,
+        icon: "bridge-dash.png",
+        align: "right",
+        label: function() {
+            return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
+        },
+        labelStyle: function() {
+            return (this.name)?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            var updateOptions = function() {
+                var sockettype = $("#node-input-beserver option:selected").val();
+                if (sockettype == "reply") {
+                    $("#node-input-port-row").hide();
+                    $("#node-input-host-row").hide();
+                    $("#node-input-end-row").hide();
+                } else {
+                    $("#node-input-port-row").show();
+                    $("#node-input-end-row").show();
+                }
+
+                if (sockettype == "client") {
+                    $("#node-input-host-row").show();
+                    $("#fin-tip").show();
+                } else {
+                    $("#node-input-host-row").hide();
+                    $("#fin-tip").hide();
+                }
+
+                if (sockettype == "server") {
+                    $("#fin-tip2").show();
+                }
+                else {
+                    $("#fin-tip2").hide();
+                }
+
+            };
+            updateOptions();
+            $("#node-input-beserver").change(updateOptions);
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="tcp request">
+    <div class="form-row">
+        <label for="node-input-server"><i class="fa fa-globe"></i> Server</label>
+        <input type="text" id="node-input-server" placeholder="ip.address" style="width:50%">
+        &nbsp;port <input type="text" id="node-input-port" style="width:50px">
+    </div>
+    <div class="form-row">
+        <label for="node-input-out"><i class="fa fa-sign-out"></i> Return</label>
+        <select type="text" id="node-input-out" style="width:52%;">
+            <option value="time">after a fixed timeout of</option>
+            <option value="char">when character received is</option>
+            <option value="count">a fixed number of characters</option>
+            <option value="sit">never. Keep connection open</option>
+        </select>
+        <input type="text" id="node-input-splitc"  style="width:50px;">
+        <span id="node-units"></span>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips"><b>Tip:</b> outputs a binary <b>Buffer</b>, so you may want to .toString() it.</div>
+    <script>
+        var previous = null;
+        $("#node-input-out").on('focus', function () { previous = this.value; }).change(function() {
+            if (previous == null) { previous = $("#node-input-out").val(); }
+            if ($("#node-input-out").val() == "char") {
+                if (previous != "char") $("#node-input-splitc").val("\\n");
+                $("#node-units").text("");
+            }
+            else if ($("#node-input-out").val() == "time") {
+                if (previous != "time") $("#node-input-splitc").val("0");
+                $("#node-units").text("ms");
+            }
+            else if ($("#node-input-out").val() == "count") {
+                if (previous != "count") $("#node-input-splitc").val("12");
+                $("#node-units").text("chars");
+            }
+            else {
+                if (previous != "sit") $("#node-input-splitc").val("0");
+                $("#node-units").text("");
+            }
+        });
+</script>
+
+<script type="text/x-red" data-help-name="tcp request">
+    <p>A simple TCP request node - sends the <b>msg.payload</b> to a server tcp port and expects a response.</p>
+    <p>Connects, sends the "request", reads the "response". It can either count a number of
+    returned characters into a fixed buffer, match a specified character before returning,
+    wait a fixed timeout from first reply and then return, or just sit and wait for data.</p>
+    <p>The response will be output in <b>msg.payload</b> as a buffer, so you may want to .toString() it.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('tcp request',{
+        category: 'function',
+        color:"Silver",
+        defaults: {
+            server: {value:"",required:true},
+            port: {value:"",required:true,validate:RED.validators.number()},
+            out: {value:"time",required:true},
+            splitc: {value:"0",required:true},
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "bridge-dash.png",
+        label: function() {
+            return this.name || "tcp:"+(this.server?this.server+":":"")+this.port;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/31-tcpin.js b/dgbuilder/core_nodes/io/31-tcpin.js
new file mode 100644 (file)
index 0000000..2e4e5e7
--- /dev/null
@@ -0,0 +1,472 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var reconnectTime = RED.settings.socketReconnectTime||10000;
+    var socketTimeout = RED.settings.socketTimeout||null;
+    var net = require('net');
+
+    var connectionPool = {};
+
+    function TcpIn(n) {
+        RED.nodes.createNode(this,n);
+        this.host = n.host;
+        this.port = n.port * 1;
+        this.topic = n.topic;
+        this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
+        this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
+        this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
+        this.base64 = n.base64;
+        this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
+        this.closing = false;
+        var node = this;
+        var count = 0;
+
+        if (!node.server) {
+            var buffer = null;
+            var client;
+            var reconnectTimeout;
+            var end = false;
+            var setupTcpClient = function() {
+                node.log("connecting to "+node.host+":"+node.port);
+                node.status({fill:"grey",shape:"dot",text:"connecting"});
+                var id = (1+Math.random()*4294967295).toString(16);
+                client = net.connect(node.port, node.host, function() {
+                    buffer = (node.datatype == 'buffer')? new Buffer(0):"";
+                    node.log("connected to "+node.host+":"+node.port);
+                    node.status({fill:"green",shape:"dot",text:"connected"});
+                });
+                connectionPool[id] = client;
+
+                client.on('data', function (data) {
+                    if (node.datatype != 'buffer') {
+                        data = data.toString(node.datatype);
+                    }
+                    if (node.stream) {
+                        if ((node.datatype) === "utf8" && node.newline != "") {
+                            buffer = buffer+data;
+                            var parts = buffer.split(node.newline);
+                            for (var i = 0;i<parts.length-1;i+=1) {
+                                var msg = {topic:node.topic, payload:parts[i]};
+                                msg._session = {type:"tcp",id:id};
+                                node.send(msg);
+                            }
+                            buffer = parts[parts.length-1];
+                        } else {
+                            var msg = {topic:node.topic, payload:data};
+                            msg._session = {type:"tcp",id:id};
+                            node.send(msg);
+                        }
+                    } else {
+                        if ((typeof data) === "string") {
+                            buffer = buffer+data;
+                        } else {
+                            buffer = Buffer.concat([buffer,data],buffer.length+data.length);
+                        }
+                    }
+                });
+                client.on('end', function() {
+                    if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
+                        var msg = {topic:node.topic,payload:buffer};
+                        msg._session = {type:"tcp",id:id};
+                        if (buffer.length !== 0) {
+                            end = true; // only ask for fast re-connect if we actually got something
+                            node.send(msg);
+                        }
+                        buffer = null;
+                    }
+                });
+                client.on('close', function() {
+                    delete connectionPool[id];
+                    node.status({fill:"red",shape:"ring",text:"disconnected"});
+                    if (!node.closing) {
+                        if (end) { // if we were asked to close then try to reconnect once very quick.
+                            end = false;
+                            reconnectTimeout = setTimeout(setupTcpClient, 20);
+                        }
+                        else {
+                            node.log("connection lost to "+node.host+":"+node.port);
+                            reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
+                        }
+                    }
+                });
+                client.on('error', function(err) {
+                    node.log(err);
+                });
+            }
+            setupTcpClient();
+
+            this.on('close', function() {
+                this.closing = true;
+                client.end();
+                clearTimeout(reconnectTimeout);
+            });
+        } else {
+            var server = net.createServer(function (socket) {
+                if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
+                var id = (1+Math.random()*4294967295).toString(16);
+                connectionPool[id] = socket;
+                node.status({text:++count+" connections"});
+
+                var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
+                socket.on('data', function (data) {
+                    if (node.datatype != 'buffer') {
+                        data = data.toString(node.datatype);
+                    }
+                    if (node.stream) {
+                        if ((typeof data) === "string" && node.newline != "") {
+                            buffer = buffer+data;
+                            var parts = buffer.split(node.newline);
+                            for (var i = 0;i<parts.length-1;i+=1) {
+                                var msg = {topic:node.topic, payload:parts[i],ip:socket.remoteAddress,port:socket.remotePort};
+                                msg._session = {type:"tcp",id:id};
+                                node.send(msg);
+                            }
+                            buffer = parts[parts.length-1];
+                        } else {
+                            var msg = {topic:node.topic, payload:data};
+                            msg._session = {type:"tcp",id:id};
+                            node.send(msg);
+                        }
+                    } else {
+                        if ((typeof data) === "string") {
+                            buffer = buffer+data;
+                        } else {
+                            buffer = Buffer.concat([buffer,data],buffer.length+data.length);
+                        }
+                    }
+                });
+                socket.on('end', function() {
+                    if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
+                        if (buffer.length > 0) {
+                            var msg = {topic:node.topic,payload:buffer};
+                            msg._session = {type:"tcp",id:id};
+                            node.send(msg);
+                        }
+                        buffer = null;
+                    }
+                });
+                socket.on('timeout', function() {
+                    node.log('timeout closed socket port '+node.port);
+                    socket.end();
+                });
+                socket.on('close', function() {
+                    delete connectionPool[id];
+                    node.status({text:--count+" connections"});
+                });
+                socket.on('error',function(err) {
+                    node.log(err);
+                });
+            });
+            server.on('error', function(err) {
+                if (err) {
+                    node.error('unable to listen on port '+node.port+' : '+err);
+                }
+            });
+            server.listen(node.port, function(err) {
+                if (err) {
+                    node.error('unable to listen on port '+node.port+' : '+err);
+                } else {
+                    node.log('listening on port '+node.port);
+
+                    node.on('close', function() {
+                        node.closing = true;
+                        server.close();
+                        node.log('stopped listening on port '+node.port);
+                    });
+                }
+            });
+        }
+
+    }
+    RED.nodes.registerType("tcp in",TcpIn);
+
+    function TcpOut(n) {
+        RED.nodes.createNode(this,n);
+        this.host = n.host;
+        this.port = n.port * 1;
+        this.base64 = n.base64;
+        this.doend = n.end || false;
+        this.beserver = n.beserver;
+        this.name = n.name;
+        this.closing = false;
+        var node = this;
+
+        if (!node.beserver||node.beserver=="client") {
+            var reconnectTimeout;
+            var client = null;
+            var connected = false;
+            var end = false;
+
+            var setupTcpClient = function() {
+                node.log("connecting to "+node.host+":"+node.port);
+                node.status({fill:"grey",shape:"dot",text:"connecting"});
+                client = net.connect(node.port, node.host, function() {
+                    connected = true;
+                    node.log("connected to "+node.host+":"+node.port);
+                    node.status({fill:"green",shape:"dot",text:"connected"});
+                });
+                client.on('error', function (err) {
+                    node.log('error : '+err);
+                });
+                client.on('end', function (err) {
+                });
+                client.on('close', function() {
+                    node.status({fill:"red",shape:"ring",text:"disconnected"});
+                    connected = false;
+                    client.destroy();
+                    if (!node.closing) {
+                        if (end) {
+                            end = false;
+                            reconnectTimeout = setTimeout(setupTcpClient,20);
+                        }
+                        else {
+                            node.log("connection lost to "+node.host+":"+node.port);
+                            reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
+                        }
+                    }
+                });
+            }
+            setupTcpClient();
+
+            node.on("input", function(msg) {
+                if (connected && msg.payload != null) {
+                    if (Buffer.isBuffer(msg.payload)) {
+                        client.write(msg.payload);
+                    } else if (typeof msg.payload === "string" && node.base64) {
+                        client.write(new Buffer(msg.payload,'base64'));
+                    } else {
+                        client.write(new Buffer(""+msg.payload));
+                    }
+                    if (node.doend === true) {
+                        end = true;
+                        client.end();
+                    }
+                }
+            });
+
+            node.on("close", function() {
+                this.closing = true;
+                client.end();
+                clearTimeout(reconnectTimeout);
+            });
+
+        } else if (node.beserver == "reply") {
+            node.on("input",function(msg) {
+                if (msg._session && msg._session.type == "tcp") {
+                    var client = connectionPool[msg._session.id];
+                    if (client) {
+                        if (Buffer.isBuffer(msg.payload)) {
+                            client.write(msg.payload);
+                        } else if (typeof msg.payload === "string" && node.base64) {
+                            client.write(new Buffer(msg.payload,'base64'));
+                        } else {
+                            client.write(new Buffer(""+msg.payload));
+                        }
+                    }
+                }
+            });
+        } else {
+            var connectedSockets = [];
+            node.status({text:"0 connections"});
+            var server = net.createServer(function (socket) {
+                if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
+                var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
+                node.log("connection from "+remoteDetails);
+                connectedSockets.push(socket);
+                node.status({text:connectedSockets.length+" connections"});
+                socket.on('timeout', function() {
+                    node.log('timeout closed socket port '+node.port);
+                    socket.end();
+                });
+                socket.on('close',function() {
+                    node.log("connection closed from "+remoteDetails);
+                    connectedSockets.splice(connectedSockets.indexOf(socket),1);
+                    node.status({text:connectedSockets.length+" connections"});
+                });
+                socket.on('error',function() {
+                    node.log("socket error from "+remoteDetails);
+                    connectedSockets.splice(connectedSockets.indexOf(socket),1);
+                    node.status({text:connectedSockets.length+" connections"});
+                });
+            });
+
+            node.on("input", function(msg) {
+                if (msg.payload != null) {
+                    var buffer;
+                    if (Buffer.isBuffer(msg.payload)) {
+                        buffer = msg.payload;
+                    } else if (typeof msg.payload === "string" && node.base64) {
+                        buffer = new Buffer(msg.payload,'base64');
+                    } else {
+                        buffer = new Buffer(""+msg.payload);
+                    }
+                    for (var i = 0; i<connectedSockets.length;i+=1) {
+                        if (node.doend === true) { connectedSockets[i].end(buffer); }
+                        else { connectedSockets[i].write(buffer); }
+                    }
+                }
+            });
+
+            server.on('error', function(err) {
+                if (err) {
+                    node.error('unable to listen on port '+node.port+' : '+err);
+                }
+            });
+
+            server.listen(node.port, function(err) {
+                if (err) {
+                    node.error('unable to listen on port '+node.port+' : '+err);
+                } else {
+                    node.log('listening on port '+node.port);
+                    node.on('close', function() {
+                        server.close();
+                        node.log('stopped listening on port '+node.port);
+                    });
+                }
+            });
+        }
+    }
+    RED.nodes.registerType("tcp out",TcpOut);
+
+    function TcpGet(n) {
+        RED.nodes.createNode(this,n);
+        this.server = n.server;
+        this.port = Number(n.port);
+        this.out = n.out;
+        this.splitc = n.splitc;
+
+        if (this.out != "char") { this.splitc = Number(this.splitc); }
+        else { this.splitc.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0"); }
+
+        var buf;
+        if (this.out == "count") { buf = new Buffer(this.splitc); }
+        else { buf = new Buffer(32768); } // set it to 32k... hopefully big enough for most.... but only hopefully
+
+        this.connected = false;
+        var node = this;
+        var client;
+
+        this.on("input", function(msg) {
+            var i = 0;
+            if ((!Buffer.isBuffer(msg.payload)) && (typeof msg.payload !== "string")) {
+                msg.payload = msg.payload.toString();
+            }
+            if (!node.connected) {
+                client = net.Socket();
+                client.setTimeout(socketTimeout);
+                node.status({});
+                client.connect(node.port, node.server, function() {
+                    //node.log('client connected');
+                    node.status({fill:"green",shape:"dot",text:"connected"});
+                    node.connected = true;
+                    client.write(msg.payload);
+                });
+
+                client.on('data', function(data) {
+                    //node.log("data:"+ data.length+":"+ data);
+                    if (node.splitc === 0) {
+                        node.send({"payload": data});
+                    }
+                    else if (node.out === "sit") { // if we are staying connected just send the buffer
+                        node.send({"payload": data});
+                    }
+                    else {
+                        for (var j = 0; j < data.length; j++ ) {
+                            if (node.out === "time")  {
+                                // do the timer thing
+                                if (node.tout) {
+                                    i += 1;
+                                    buf[i] = data[j];
+                                }
+                                else {
+                                    node.tout = setTimeout(function () {
+                                        node.tout = null;
+                                        var m = new Buffer(i+1);
+                                        buf.copy(m,0,0,i+1);
+                                        node.send({"payload": m});
+                                        client.end();
+                                        m = null;
+                                    }, node.splitc);
+                                    i = 0;
+                                    buf[0] = data[j];
+                                }
+                            }
+                            // count bytes into a buffer...
+                            else if (node.out == "count") {
+                                buf[i] = data[j];
+                                i += 1;
+                                if ( i >= node.serialConfig.count) {
+                                    node.send({"payload": buf});
+                                    client.end();
+                                    i = 0;
+                                }
+                            }
+                            // look for a char
+                            else {
+                                buf[i] = data[j];
+                                i += 1;
+                                if (data[j] == node.splitc) {
+                                    var m = new Buffer(i);
+                                    buf.copy(m,0,0,i);
+                                    node.send({"payload": m});
+                                    client.end();
+                                    m = null;
+                                    i = 0;
+                                }
+                            }
+                        }
+                    }
+                });
+
+                client.on('end', function() {
+                    //node.log('client disconnected');
+                    node.connected = false;
+                    node.status({});
+                    client = null;
+                });
+
+                client.on('error', function() {
+                    node.log('connect failed');
+                    node.status({fill:"red",shape:"ring",text:"error"});
+                    if (client) { client.end(); }
+                });
+
+                client.on('timeout',function() {
+                    node.log('connect timeout');
+                    if (client) {
+                        client.end();
+                        setTimeout(function() {
+                            client.connect(node.port, node.server, function() {
+                                //node.log('client connected');
+                                node.connected = true;
+                                client.write(msg.payload);
+                            });
+                        },reconnectTime);
+                    }
+                });
+            }
+            else { client.write(msg.payload); }
+        });
+
+        this.on("close", function() {
+            if (client) { buf = null; client.end(); }
+        });
+
+    }
+    RED.nodes.registerType("tcp request",TcpGet);
+}
diff --git a/dgbuilder/core_nodes/io/32-udp.html b/dgbuilder/core_nodes/io/32-udp.html
new file mode 100644 (file)
index 0000000..1c2eed5
--- /dev/null
@@ -0,0 +1,212 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--  The Input Node  -->
+<script type="text/x-red" data-template-name="udp in">
+    <div class="form-row">
+        <label for="node-input-port"><i class="fa fa-sign-in"></i> Listen</label>
+        on port <input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
+        for <select id="node-input-multicast" style='width:40%'>
+          <option value="false">udp messages</option>
+          <option value="true">multicast messages</option>
+        </select>
+    </div>
+    <div class="form-row node-input-group">
+        <label for="node-input-group"><i class="fa fa-list"></i> Group</label>
+        <input type="text" id="node-input-group" placeholder="225.0.18.83">
+    </div>
+    <div class="form-row node-input-iface">
+        <label for="node-input-iface"><i class="fa fa-random"></i> Interface</label>
+        <input type="text" id="node-input-iface" placeholder="(optional) ip address of eth0">
+    </div>
+    <div class="form-row">
+        <label for="node-input-datatype"><i class="fa fa-sign-out"></i> Output</label>
+        <select id="node-input-datatype" style="width: 70%;">
+            <option value="buffer">a Buffer</option>
+            <option value="utf8">a String</option>
+            <option value="base64">a Base64 encoded string</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: Make sure your firewall will allow the data in.</div>
+    <script>
+        $("#node-input-multicast").change(function() {
+            var id = $("#node-input-multicast option:selected").val();
+            if (id == "false") {
+                $(".node-input-group").hide();
+                $(".node-input-iface").hide();
+            }
+            else {
+                $(".node-input-group").show();
+                $(".node-input-iface").show();
+            }
+        });
+    </script>
+</script>
+
+<script type="text/x-red" data-help-name="udp in">
+    <p>A udp input node, that produces a <b>msg.payload</b> containing a <i>BUFFER</i>, string, or base64 encoded string. Supports multicast.</p>
+    <p>It also provides <b>msg.ip</b> and <b>msg.port</b> to the ip address and port from which the message was received.</p>
+    <p>On some systems you may need to be root to use ports below 1024 and/or broadcast.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('udp in',{
+        category: 'input',
+        color:"Silver",
+        defaults: {
+            name: {value:""},
+            iface: {value:""},
+            port: {value:"",required:true,validate:RED.validators.number()},
+            datatype: {value:"buffer",required:true},
+            multicast: {value:"false"},
+            group: {value:"",validate:function(v) { return (this.multicast !== "true")||v.length > 0;} }
+        },
+        inputs:0,
+        outputs:1,
+        icon: "bridge-dash.png",
+        label: function() {
+            if (this.multicast=="false") {
+                return this.name||"udp "+this.port;
+            }
+            else return this.name||"udp "+(this.group+":"+this.port);
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
+
+
+<!--  The Output Node  -->
+<script type="text/x-red" data-template-name="udp out">
+    <div class="form-row">
+        <label for="node-input-port"><i class="fa fa-envelope"></i> Send a</label>
+        <select id="node-input-multicast" style='width:40%'>
+          <option value="false">udp message</option>
+          <option value="broad">broadcast message</option>
+          <option value="multi">multicast message</option>
+        </select>
+        to port <input type="text" id="node-input-port" placeholder="port" style="width: 70px">
+    </div>
+    <div class="form-row node-input-addr">
+        <label for="node-input-addr" id="node-input-addr-label"><i class="fa fa-list"></i> Address</label>
+        <input type="text" id="node-input-addr" placeholder="destination ip" style="width: 70%;">
+    </div>
+    <div class="form-row node-input-iface">
+        <label for="node-input-iface"><i class="fa fa-random"></i> Interface</label>
+        <input type="text" id="node-input-iface" placeholder="(optional) ip address of eth0">
+    </div>
+    <div class="form-row">
+        <label for="node-input-outport-type">&nbsp;</label>
+        <select id="node-input-outport-type">
+          <option id="node-input-outport-type-random" value="random">use random local port</option>
+          <option value="fixed">bind to local port</option>
+        </select>
+        <input type="text" id="node-input-outport"  style="width: 70px;" placeholder="port">
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-base64" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-base64" style="width: 70%;">Decode Base64 encoded payload ?</label>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: leave address and port blank if you want to set using <b>msg.ip</b> and <b>msg.port</b>.</div>
+    <script>
+        $("#node-input-multicast").change(function() {
+            var id = $("#node-input-multicast option:selected").val();
+            if (id !== "multi") {
+                $(".node-input-iface").hide();
+                $("#node-input-addr-label").html('<i class="fa fa-list"></i> Address');
+                $("#node-input-addr")[0].placeholder = 'destination ip';
+            }
+            else {
+                $(".node-input-iface").show();
+                $("#node-input-addr-label").html('<i class="fa fa-list"></i> Group');
+                $("#node-input-addr")[0].placeholder = '225.0.18.83';
+            }
+            if (id === "broad") {
+                $("#node-input-addr")[0].placeholder = '255.255.255.255';
+            }
+        });
+    </script>
+</script>
+
+<script type="text/x-red" data-help-name="udp out">
+    <p>This node sends <b>msg.payload</b> to the designated udp host and port. Supports multicast.</p>
+    <p>You may also use <b>msg.ip</b> and <b>msg.port</b> to set the destination values.<br/><b>Note</b>: the statically configured values have precedence.</p>
+    <p>If you select broadcast either set the address to the local broadcast ip address, or maybe try 255.255.255.255, which is the global broadcast address.</p>
+    <p>On some systems you may need to be root to use ports below 1024 and/or broadcast.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('udp out',{
+        category: 'output',
+        color:"Silver",
+        defaults: {
+            name: {value:""},
+            addr: {value:""},
+            iface: {value:""},
+            port: {value:""},
+            outport: {value:""},
+            base64: {value:false,required:true},
+            multicast: {value:"false"}
+        },
+        inputs:1,
+        outputs:0,
+        icon: "bridge-dash.png",
+        align: "right",
+        label: function() {
+            return this.name||"udp "+(this.addr+":"+this.port);
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            var type = this.outport==""?"random":"fixed";
+            $("#node-input-outport-type option").filter(function() {
+                return $(this).val() == type;
+            }).attr('selected',true);
+
+            $("#node-input-outport-type").change(function() {
+                var type = $(this).children("option:selected").val();
+                if (type == "random") {
+                    $("#node-input-outport").val("").hide();
+                } else {
+                    $("#node-input-outport").show();
+                }
+            });
+
+            $("#node-input-outport-type").change();
+
+            $("#node-input-multicast").change(function() {
+                var type = $(this).children("option:selected").val();
+                if (type == "false") {
+                    $("#node-input-outport-type-random").html("bind to random local port");
+                } else {
+                    $("#node-input-outport-type-random").html("bind to target port");
+                }
+            });
+            $("#node-input-multicast").change();
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/io/32-udp.js b/dgbuilder/core_nodes/io/32-udp.js
new file mode 100644 (file)
index 0000000..a7968e3
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var dgram = require('dgram');
+
+    // The Input Node
+    function UDPin(n) {
+        RED.nodes.createNode(this,n);
+        this.group = n.group;
+        this.port = n.port;
+        this.datatype = n.datatype;
+        this.iface = n.iface || null;
+        this.multicast = n.multicast;
+        var node = this;
+
+        var server = dgram.createSocket('udp4');
+
+        server.on("error", function (err) {
+            if ((err.code == "EACCES") && (node.port < 1024)) {
+                node.error("UDP access error, you may need root access for ports below 1024");
+            } else {
+                node.error("UDP error : "+err.code);
+            }
+            server.close();
+        });
+
+        server.on('message', function (message, remote) {
+            var msg;
+            if (node.datatype =="base64") {
+                msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port };
+            } else if (node.datatype =="utf8") {
+                msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port };
+            } else {
+                msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
+            }
+            node.send(msg);
+        });
+
+        server.on('listening', function () {
+            var address = server.address();
+            node.log('udp listener at ' + address.address + ":" + address.port);
+            if (node.multicast == "true") {
+                server.setBroadcast(true);
+                try {
+                    server.setMulticastTTL(128);
+                    server.addMembership(node.group,node.iface);
+                    node.log("udp multicast group "+node.group);
+                } catch (e) {
+                    if (e.errno == "EINVAL") {
+                        node.error("Bad Multicast Address");
+                    } else if (e.errno == "ENODEV") {
+                        node.error("Must be ip address of the required interface");
+                    } else {
+                        node.error("Error :"+e.errno);
+                    }
+                }
+            }
+        });
+
+        node.on("close", function() {
+            try {
+                server.close();
+                node.log('udp listener stopped');
+            } catch (err) {
+                node.error(err);
+            }
+        });
+
+        server.bind(node.port,node.iface);
+    }
+    RED.nodes.registerType("udp in",UDPin);
+
+
+    // The Output Node
+    function UDPout(n) {
+        RED.nodes.createNode(this,n);
+        //this.group = n.group;
+        this.port = n.port;
+        this.outport = n.outport||"";
+        this.base64 = n.base64;
+        this.addr = n.addr;
+        this.iface = n.iface || null;
+        this.multicast = n.multicast;
+        var node = this;
+
+        var sock = dgram.createSocket('udp4');  // only use ipv4 for now
+
+        if (node.multicast != "false") {
+            if (node.outport == "") { node.outport = node.port; }
+            sock.bind(node.outport, function() {    // have to bind before you can enable broadcast...
+                sock.setBroadcast(true);            // turn on broadcast
+                if (node.multicast == "multi") {
+                    try {
+                        sock.setMulticastTTL(128);
+                        sock.addMembership(node.addr,node.iface);   // Add to the multicast group
+                        node.log('udp multicast ready : '+node.outport+' -> '+node.addr+":"+node.port);
+                    } catch (e) {
+                        if (e.errno == "EINVAL") {
+                            node.error("Bad Multicast Address");
+                        } else if (e.errno == "ENODEV") {
+                            node.error("Must be ip address of the required interface");
+                        } else {
+                            node.error("Error :"+e.errno);
+                        }
+                    }
+                } else {
+                    node.log('udp broadcast ready : '+node.outport+' -> '+node.addr+":"+node.port);
+                }
+            });
+        } else if (node.outport != "") {
+            sock.bind(node.outport);
+            node.log('udp ready : '+node.outport+' -> '+node.addr+":"+node.port);
+        } else {
+            node.log('udp ready : '+node.addr+":"+node.port);
+        }
+
+        node.on("input", function(msg) {
+            if (msg.payload != null) {
+                var add = node.addr || msg.ip || "";
+                var por = node.port || msg.port || 0;
+                if (add == "") {
+                    node.warn("udp: ip address not set");
+                } else if (por == 0) {
+                    node.warn("udp: port not set");
+                } else if (isNaN(por) || (por < 1) || (por > 65535)) {
+                    node.warn("udp: port number not valid");
+                } else {
+                    var message;
+                    if (node.base64) {
+                        message = new Buffer(msg.payload, 'base64');
+                    } else if (msg.payload instanceof Buffer) {
+                        message = msg.payload;
+                    } else {
+                        message = new Buffer(""+msg.payload);
+                    }
+                    sock.send(message, 0, message.length, por, add, function(err, bytes) {
+                        if (err) {
+                            node.error("udp : "+err);
+                        }
+                        message = null;
+                    });
+                }
+            }
+        });
+
+        node.on("close", function() {
+            try {
+                sock.close();
+                node.log('udp output stopped');
+            } catch (err) {
+                node.error(err);
+            }
+        });
+    }
+    RED.nodes.registerType("udp out",UDPout);
+}
diff --git a/dgbuilder/core_nodes/io/lib/mqtt.js b/dgbuilder/core_nodes/io/lib/mqtt.js
new file mode 100644 (file)
index 0000000..141a888
--- /dev/null
@@ -0,0 +1,254 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var util = require("util");
+var mqtt = require("mqtt");
+var events = require("events");
+//var inspect = require("sys").inspect;
+
+//var Client = module.exports.Client = function(
+   
+var port = 1883;
+var host = "localhost";
+
+function MQTTClient(port,host) {
+   this.port = port||1883;
+   this.host = host||"localhost";
+   this.messageId = 1;
+   this.pendingSubscriptions = {};
+   this.inboundMessages = {};
+   this.lastOutbound = (new Date()).getTime();
+   this.lastInbound = (new Date()).getTime();
+   this.connected = false;
+   
+   this._nextMessageId = function() {
+      this.messageId += 1;
+      if (this.messageId > 0xFFFF) {
+         this.messageId = 1;
+      }
+      return this.messageId;
+   }
+   events.EventEmitter.call(this);
+}
+util.inherits(MQTTClient, events.EventEmitter);
+
+MQTTClient.prototype.connect = function(options) {
+   if (!this.connected) {
+       var self = this;
+       options = options||{};
+       self.options = options;
+       self.options.keepalive = options.keepalive||15;
+       self.options.clean = self.options.clean||true;
+       self.options.protocolId = 'MQIsdp';
+       self.options.protocolVersion = 3;
+       
+       self.client = mqtt.createConnection(this.port,this.host,function(err,client) {
+             if (err) {
+                self.connected = false;
+                clearInterval(self.watchdog);
+                self.connectionError = true;
+                //util.log('[mqtt] ['+self.uid+'] connection error 1 : '+inspect(err));
+                self.emit('connectionlost',err);
+                return;
+             }
+             client.on('close',function(e) {
+                   //util.log('[mqtt] ['+self.uid+'] on close');
+                   clearInterval(self.watchdog);
+                   if (!self.connectionError) {
+                       if (self.connected) {
+                          self.connected = false;
+                          self.emit('connectionlost',e);
+                       } else {
+                          self.emit('disconnect');
+                       }
+                   }
+             });
+             client.on('error',function(e) {
+                   //util.log('[mqtt] ['+self.uid+'] on error : '+inspect(e));
+                   clearInterval(self.watchdog);
+                   if (self.connected) {
+                      self.connected = false;
+                      self.emit('connectionlost',e);
+                   }
+             });
+             client.on('connack',function(packet) {
+                   if (packet.returnCode == 0) {
+                      self.watchdog = setInterval(function(self) {
+                            var now = (new Date()).getTime();
+                            
+                            //util.log('[mqtt] ['+self.uid+'] watchdog '+inspect({connected:self.connected,connectionError:self.connectionError,pingOutstanding:self.pingOutstanding,now:now,lastOutbound:self.lastOutbound,lastInbound:self.lastInbound}));
+    
+                            if (now - self.lastOutbound > self.options.keepalive*500 || now - self.lastInbound > self.options.keepalive*500) {
+                               if (self.pingOutstanding) {
+                                  //util.log('[mqtt] ['+self.uid+'] watchdog pingOustanding - disconnect');
+                                  try {
+                                     self.client.disconnect();
+                                  } catch (err) {
+                                  }
+                               } else {
+                                  //util.log('[mqtt] ['+self.uid+'] watchdog pinging');
+                                  self.lastOutbound = (new Date()).getTime();
+                                  self.lastInbound = (new Date()).getTime();
+                                  self.pingOutstanding = true;
+                                  self.client.pingreq();
+                               }
+                            }
+                            
+                      },self.options.keepalive*500,self);
+                      self.pingOutstanding = false;
+                      self.lastInbound = (new Date()).getTime()
+                      self.lastOutbound = (new Date()).getTime()
+                      self.connected = true;
+                      self.connectionError = false;
+                      self.emit('connect');
+                   } else {
+                      self.connected = false;
+                      self.emit('connectionlost');
+                   }
+             });
+             client.on('suback',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   var topic = self.pendingSubscriptions[packet.messageId];
+                   self.emit('subscribe',topic,packet.granted[0]);
+                   delete self.pendingSubscriptions[packet.messageId];
+             });
+             client.on('unsuback',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   var topic = self.pendingSubscriptions[packet.messageId];
+                   self.emit('unsubscribe',topic,packet.granted[0]);
+                   delete self.pendingSubscriptions[packet.messageId];
+             });
+             client.on('publish',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   if (packet.qos < 2) {
+                      var p = packet;
+                      self.emit('message',p.topic,p.payload,p.qos,p.retain);
+                   } else {
+                      self.inboundMessages[packet.messageId] = packet;
+                      this.lastOutbound = (new Date()).getTime()
+                      self.client.pubrec(packet);
+                   }
+                   if (packet.qos == 1) {
+                      this.lastOutbound = (new Date()).getTime()
+                      self.client.puback(packet);
+                   }
+             });
+             
+             client.on('pubrel',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   var p = self.inboundMessages[packet.messageId];
+                   if (p) {
+                       self.emit('message',p.topic,p.payload,p.qos,p.retain);
+                       delete self.inboundMessages[packet.messageId];
+                   }
+                   self.lastOutbound = (new Date()).getTime()
+                   self.client.pubcomp(packet);
+             });
+             
+             client.on('puback',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   // outbound qos-1 complete
+             });
+             
+             client.on('pubrec',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   self.lastOutbound = (new Date()).getTime()
+                   self.client.pubrel(packet);
+             });
+             client.on('pubcomp',function(packet) {
+                   self.lastInbound = (new Date()).getTime()
+                   // outbound qos-2 complete
+             });
+             client.on('pingresp',function(packet) {
+                   //util.log('[mqtt] ['+self.uid+'] received pingresp');
+                   self.lastInbound = (new Date()).getTime()
+                   self.pingOutstanding = false;
+             });
+             
+             this.lastOutbound = (new Date()).getTime()
+             this.connectionError = false;
+             client.connect(self.options);
+       });
+   }
+}
+
+MQTTClient.prototype.subscribe = function(topic,qos) {
+   var self = this;
+   if (self.connected) {
+      var options = {
+         subscriptions:[{topic:topic,qos:qos}],
+         messageId: self._nextMessageId()
+      };
+      this.pendingSubscriptions[options.messageId] = topic;
+      this.lastOutbound = (new Date()).getTime()
+      self.client.subscribe(options);
+   }
+}
+MQTTClient.prototype.unsubscribe = function(topic) {
+   var self = this;
+   if (self.connected) {
+      var options = {
+         topic:topic,
+         messageId: self._nextMessageId()
+      };
+      this.pendingSubscriptions[options.messageId] = topic;
+      this.lastOutbound = (new Date()).getTime()
+      self.client.unsubscribe(options);
+   }
+}
+
+MQTTClient.prototype.publish = function(topic,payload,qos,retain) {
+   var self = this;
+   if (self.connected) {
+   
+      if (!Buffer.isBuffer(payload)) {
+         if (typeof payload === "object") {
+            payload = JSON.stringify(payload);
+         } else if (typeof payload !== "string") {
+            payload = ""+payload;
+         }
+      }
+      var options = {
+         topic: topic,
+         payload: payload,
+         qos: qos||0,
+         retain:retain||false
+      };
+      if (options.qos != 0) {
+         options.messageId = self._nextMessageId();
+      }
+      this.lastOutbound = (new Date()).getTime()
+      self.client.publish(options);
+   }
+}
+
+MQTTClient.prototype.disconnect = function() {
+   var self = this;
+   if (this.connected) {
+       this.connected = false;
+       try {
+           this.client.disconnect();
+       } catch(err) {
+       }
+   }
+}
+MQTTClient.prototype.isConnected = function() {
+    return this.connected;
+}
+module.exports.createClient = function(port,host) {
+   var mqtt_client = new MQTTClient(port,host);
+   return mqtt_client;
+}
+
diff --git a/dgbuilder/core_nodes/io/lib/mqttConnectionPool.js b/dgbuilder/core_nodes/io/lib/mqttConnectionPool.js
new file mode 100644 (file)
index 0000000..d15f0fc
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var util = require("util");
+var mqtt = require("./mqtt");
+var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
+
+var connections = {};
+
+function matchTopic(ts,t) {
+    if (ts == "#") {
+        return true;
+    }
+    var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
+    return re.test(t);
+}
+
+module.exports = {
+    get: function(broker,port,clientid,username,password,will) {
+        var id = "["+(username||"")+":"+(password||"")+"]["+(clientid||"")+"]@"+broker+":"+port;
+        if (!connections[id]) {
+            connections[id] = function() {
+                var uid = (1+Math.random()*4294967295).toString(16);
+                var client = mqtt.createClient(port,broker);
+                client.uid = uid;
+                client.setMaxListeners(0);
+                var options = {keepalive:15};
+                options.clientId = clientid || 'mqtt_' + (1+Math.random()*4294967295).toString(16);
+                options.username = username;
+                options.password = password;
+                options.will = will;
+                var queue = [];
+                var subscriptions = [];
+                var connecting = false;
+                var obj = {
+                    _instances: 0,
+                    publish: function(msg) {
+                        if (client.isConnected()) {
+                            client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
+                        } else {
+                            if (!connecting) {
+                                connecting = true;
+                                client.connect(options);
+                            }
+                            queue.push(msg);
+                        }
+                    },
+                    subscribe: function(topic,qos,callback) {
+                        subscriptions.push({topic:topic,qos:qos,callback:callback});
+                        client.on('message',function(mtopic,mpayload,mqos,mretain) {
+                                if (matchTopic(topic,mtopic)) {
+                                    callback(mtopic,mpayload,mqos,mretain);
+                                }
+                        });
+                        if (client.isConnected()) {
+                            client.subscribe(topic,qos);
+                        }
+                    },
+                    on: function(a,b){
+                        client.on(a,b);
+                    },
+                    once: function(a,b){
+                        client.once(a,b);
+                    },
+                    connect: function() {
+                        if (client && !client.isConnected() && !connecting) {
+                            connecting = true;
+                            client.connect(options);
+                        }
+                    },
+                    disconnect: function() {
+                        this._instances -= 1;
+                        if (this._instances == 0) {
+                            client.disconnect();
+                            client = null;
+                            delete connections[id];
+                        }
+                    }
+                };
+                client.on('connect',function() {
+                        if (client) {
+                            util.log('[mqtt] ['+uid+'] connected to broker tcp://'+broker+':'+port);
+                            connecting = false;
+                            for (var s in subscriptions) {
+                                var topic = subscriptions[s].topic;
+                                var qos = subscriptions[s].qos;
+                                var callback = subscriptions[s].callback;
+                                client.subscribe(topic,qos);
+                            }
+                            //console.log("connected - publishing",queue.length,"messages");
+                            while(queue.length) {
+                                var msg = queue.shift();
+                                //console.log(msg);
+                                client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
+                            }
+                        }
+                });
+                client.on('connectionlost', function(err) {
+                        util.log('[mqtt] ['+uid+'] connection lost to broker tcp://'+broker+':'+port);
+                        connecting = false;
+                        setTimeout(function() {
+                            obj.connect();
+                        }, settings.mqttReconnectTime||5000);
+                });
+                client.on('disconnect', function() {
+                        connecting = false;
+                        util.log('[mqtt] ['+uid+'] disconnected from broker tcp://'+broker+':'+port);
+                });
+
+                return obj
+            }();
+        }
+        connections[id]._instances += 1;
+        return connections[id];
+    }
+};
diff --git a/dgbuilder/core_nodes/logic/10-switch.html b/dgbuilder/core_nodes/logic/10-switch.html
new file mode 100644 (file)
index 0000000..4e02f44
--- /dev/null
@@ -0,0 +1,198 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="switch">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row" style="padding-top:10px;">
+        If msg.<input type="text" id="node-input-property" style="width: 200px;"/>
+    </div>
+    <div class="form-row">
+        <div id="node-input-rule-container-div" style="border-radius: 5px; height: 310px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
+        <ol id="node-input-rule-container" style=" list-style-type:none; margin: 0;">
+        </ol>
+        </div>
+        <a href="#" class="btn btn-mini" id="node-input-add-rule" style="margin-top: 4px;"><i class="fa fa-plus"></i> Add</a>
+    </div>
+    <div>
+        <select id="node-input-checkall" style="width:100%; margin-right:5px;">
+            <option value="true">checking all rules</option>
+            <option value="false">stopping after first match</option>
+        </select>
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="switch">
+    <p>A simple function node to route messages based on its properties.</p>
+    <p>When a message arrives, the selected property is evaluated against each
+    of the defined rules. The message is then sent to the output of <i>all</i>
+    rules that pass.</p>
+    <p>Note: the <i>otherwise</i> rule applies as a "not any of" the rules preceding it.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('switch', {
+        color: "#E2D96E",
+        category: 'function',
+        defaults: {
+            name: {value:""},
+            property: {value:"payload", required:true},
+            rules: {value:[{t:"eq", v:""}]},
+            checkall: {value:"true", required:true},
+            outputs: {value:1}
+        },
+        inputs: 1,
+        outputs: 1,
+        icon: "switch.png",
+        label: function() {
+            return this.name||"switch";
+        },
+        oneditprepare: function() {
+
+            var operators = [
+                {v:"eq",t:"=="},
+                {v:"neq",t:"!="},
+                {v:"lt",t:"<"},
+                {v:"lte",t:"<="},
+                {v:"gt",t:">"},
+                {v:"gte",t:">="},
+                {v:"btwn",t:"is between"},
+                {v:"cont",t:"contains"},
+                {v:"regex",t:"matches regex"},
+                {v:"true",t:"is true"},
+                {v:"false",t:"is false"},
+                {v:"null",t:"is null"},
+                {v:"nnull",t:"is not null"},
+                {v:"else",t:"otherwise"}
+            ];
+
+            function generateRule(i,rule) {
+                var container = $('<li/>',{style:"margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"});
+                var row = $('<div/>').appendTo(container);
+                var row2 = $('<div/>',{style:"padding-top: 5px; text-align: right;"}).appendTo(container);
+
+                var selectField = $('<select/>',{style:"width:120px; margin-left: 5px; text-align: center;"}).appendTo(row);
+                for (var d in operators) {
+                    selectField.append($("<option></option>").val(operators[d].v).text(operators[d].t));
+                }
+
+                var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px; width: 145px;"}).appendTo(row);
+                var btwnField = $('<span/>').appendTo(row);
+                var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px; width: 50px;"}).appendTo(btwnField);
+                btwnField.append(" and ");
+                var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"width: 50px;margin-left:2px;"}).appendTo(btwnField);
+
+                var finalspan = $('<span/>',{style:"float: right; margin-top: 3px;margin-right: 10px;"}).appendTo(row);
+                finalspan.append(' send to <span class="node-input-rule-index">'+i+'</span> ');
+
+                selectField.change(function() {
+                    var type = selectField.children("option:selected").val();
+                    if (type.length < 4) {
+                        selectField.css({"width":"60px"});
+                    } else if (type === "regex") {
+                        selectField.css({"width":"147px"});
+                    } else {
+                        selectField.css({"width":"120px"});
+                    }
+                    if (type === "btwn") {
+                        valueField.hide();
+                        btwnField.show();
+                    } else {
+                        btwnField.hide();
+                        if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
+                            valueField.hide();
+                        } else {
+                            valueField.show();
+                        }
+                    }
+                });
+
+                var deleteButton = $('<a/>',{href:"#",class:"btn btn-mini", style:"margin-left: 5px;"}).appendTo(finalspan);
+                $('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
+
+                deleteButton.click(function() {
+                    container.css({"background":"#fee"});
+                    container.fadeOut(300, function() {
+                        $(this).remove();
+                        $("#node-input-rule-container").children().each(function(i) {
+                            $(this).find(".node-input-rule-index").html(i+1);
+                        });
+
+                    });
+                });
+
+                $("#node-input-rule-container").append(container);
+
+                selectField.find("option").filter(function() {return $(this).val() == rule.t;}).attr('selected',true);
+                if (rule.t == "btwn") {
+                    btwnValueField.val(rule.v);
+                    btwnValue2Field.val(rule.v2);
+                } else if (typeof rule.v != "undefined") {
+                    valueField.val(rule.v);
+                }
+                selectField.change();
+            }
+
+            $("#node-input-add-rule").click(function() {
+                generateRule($("#node-input-rule-container").children().length+1,{t:"",v:"",v2:""});
+                $("#node-input-rule-container-div").scrollTop($("#node-input-rule-container-div").get(0).scrollHeight);
+            });
+
+            for (var i=0;i<this.rules.length;i++) {
+                var rule = this.rules[i];
+                generateRule(i+1,rule);
+            }
+
+            function switchDialogResize(ev,ui) {
+                $("#node-input-rule-container-div").css("height",(ui.size.height-260)+"px");
+            };
+
+            $( "#dialog" ).on("dialogresize", switchDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-switch');
+                if (size) {
+                    switchDialogResize(null,{size:size});
+                }
+            });
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                $( "#dialog" ).off("dialogresize",switchDialogResize);
+            });
+        },
+        oneditsave: function() {
+            var rules = $("#node-input-rule-container").children();
+            var ruleset;
+            var node = this;
+            node.rules= [];
+            rules.each(function(i) {
+                var rule = $(this);
+                var type = rule.find("select option:selected").val();
+                var r = {t:type};
+                if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else")) {
+                    if (type === "btwn") {
+                        r.v = rule.find(".node-input-rule-btwn-value").val();
+                        r.v2 = rule.find(".node-input-rule-btwn-value2").val();
+                    } else {
+                        r.v = rule.find(".node-input-rule-value").val();
+                    }
+                }
+                node.rules.push(r);
+            });
+            node.outputs = node.rules.length;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/logic/10-switch.js b/dgbuilder/core_nodes/logic/10-switch.js
new file mode 100644 (file)
index 0000000..8bcb857
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var operators = {
+        'eq': function(a, b) { return a == b; },
+        'neq': function(a, b) { return a != b; },
+        'lt': function(a, b) { return a < b; },
+        'lte': function(a, b) { return a <= b; },
+        'gt': function(a, b) { return a > b; },
+        'gte': function(a, b) { return a >= b; },
+        'btwn': function(a, b, c) { return a >= b && a <= c; },
+        'cont': function(a, b) { return (a + "").indexOf(b) != -1; },
+        'regex': function(a, b) { return (a + "").match(new RegExp(b)); },
+        'true': function(a) { return a === true; },
+        'false': function(a) { return a === false; },
+        'null': function(a) { return typeof a == "undefined"; },
+        'nnull': function(a) { return typeof a != "undefined"; },
+        'else': function(a) { return a === true; }
+    };
+
+    function SwitchNode(n) {
+        RED.nodes.createNode(this, n);
+        this.rules = n.rules;
+        this.property = n.property;
+        this.checkall = n.checkall || "true";
+        var propertyParts = n.property.split(".");
+        var node = this;
+
+        for (var i=0; i<this.rules.length; i+=1) {
+            var rule = this.rules[i];
+            if (!isNaN(Number(rule.v))) {
+                rule.v = Number(rule.v);
+                rule.v2 = Number(rule.v2);
+            }
+        }
+
+        this.on('input', function (msg) {
+            var onward = [];
+            try {
+                var prop = propertyParts.reduce(function (obj, i) {
+                    return obj[i]
+                }, msg);
+                var elseflag = true;
+                for (var i=0; i<node.rules.length; i+=1) {
+                    var rule = node.rules[i];
+                    var test = prop;
+                    if (rule.t == "else") { test = elseflag; elseflag = true; }
+                    if (operators[rule.t](test,rule.v, rule.v2)) {
+                        onward.push(msg);
+                        elseflag = false;
+                        if (node.checkall == "false") { break; }
+                    } else {
+                        onward.push(null);
+                    }
+                }
+                this.send(onward);
+            } catch(err) {
+                node.warn(err);
+            }
+        });
+    }
+    RED.nodes.registerType("switch", SwitchNode);
+}
diff --git a/dgbuilder/core_nodes/logic/15-change.html b/dgbuilder/core_nodes/logic/15-change.html
new file mode 100644 (file)
index 0000000..702dd80
--- /dev/null
@@ -0,0 +1,139 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="change">
+    <div>
+        <select id="node-input-action" style="width:95%; margin-right:5px;">
+            <option value="replace">Set the value of the message property</option>
+            <option value="change">Search/replace the value of the message property</option>
+            <option value="delete">Delete the message property</option>
+        </select>
+    </div>
+    <div class="form-row" style="padding-top:10px;" id="node-prop1-row">
+        <label for="node-input-property">called</label> msg.<input type="text" id="node-input-property" style="width: 63%;"/>
+    </div>
+    <div class="form-row" id="node-from-row">
+        <label for="node-input-from" id="node-input-f"></label>
+        <input type="text" id="node-input-from" placeholder="this"/>
+    </div>
+    <div class="form-row" id="node-to-row">
+        <label for="node-input-to" id="node-input-t"></label>
+        <input type="text" id="node-input-to" placeholder="that"/>
+    </div>
+    <div class="form-row" id="node-reg-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-reg" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-reg" style="width: 70%;">Use regular expressions ?</label>
+    </div>
+    <div class="form-tips" id="node-tip"></div>
+    <br/>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="change">
+    <p>A simple function node to change, replace, add or delete properties of a message.</p>
+    <p>When a message arrives, the selected property is modified by the defined rules.
+    The message is then sent to the output.</p>
+    <p><b>Note:</b> Replace only operates on <b>strings</b>. Anything else will be passed straight through.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('change', {
+        color: "#E2D96E",
+        category: 'function',
+        defaults: {
+            action: {value:"replace",required:true},
+            property: {value:"payload",required:true},
+            from: {value:"",validate: function(v) {
+                if (this.action == "change" && this.reg) {
+                    try {
+                        var re = new RegExp(this.from, "g");
+                        return true;
+                    } catch(err) {
+                        return false;
+                    }
+                }
+                return true;
+            }},
+            to: {value:""},
+            reg: {value:false},
+            name: {value:""}
+        },
+        inputs: 1,
+        outputs: 1,
+        icon: "swap.png",
+        label: function() {
+            if (this.name) {
+                return this.name;
+            }
+            if (this.action == "replace") {
+                return "set msg."+this.property;
+            } else {
+                return this.action+" msg."+this.property
+            }
+        },
+        labelStyle: function() {
+            return this.name ? "node_label_italic" : "";
+        },
+        oneditprepare: function() {
+            if (this.reg === null) { $("#node-input-reg").prop('checked', true); }
+            $("#node-input-action").change( function() {
+                var a = $("#node-input-action").val();
+                if (a === "replace") {
+                    $("#node-input-todo").html("called");
+                    //$("#node-input-f").html("name");
+                    $("#node-input-t").html("to");
+                    $("#node-from-row").hide();
+                    $("#node-to-row").show();
+                    $("#node-reg-row").hide();
+                    $("#node-tip").show();
+                    $("#node-tip").html("Tip: expects a new property name and either a fixed value OR the full name of another message property eg: msg.sentiment.score");
+                }
+                if (a === "delete") {
+                    $("#node-input-todo").html("called");
+                    //$("#node-input-f").html("called");
+                    //$("#node-input-t").html("to");
+                    $("#node-from-row").hide();
+                    $("#node-to-row").hide();
+                    $("#node-reg-row").hide();
+                    $("#node-tip").hide();
+                }
+                if (a === "change") {
+                    $("#node-input-todo").html("called");
+                    $("#node-input-f").html("Search for");
+                    $("#node-input-t").html("replace with");
+                    $("#node-from-row").show();
+                    $("#node-to-row").show();
+                    $("#node-reg-row").show();
+                    $("#node-tip").show();
+                    $("#node-tip").html("Tip: only works on string properties. If regular expressions are used, the <i>replace with</i> field can contain capture results, eg $1.");
+                }
+                //if (a === "replace") {
+                 //   $("#node-input-todo").html("called");
+                 //   //$("#node-input-f").html("with");
+                 //   $("#node-input-t").html("with");
+                 //   $("#node-from-row").hide();
+                 //   $("#node-to-row").show();
+                 //   $("#node-tip").html("Tip: accepts either a fixed value OR the full name of another msg.property eg: msg.sentiment.score");
+                //}
+            });
+            $("#node-input-action").change();
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/logic/15-change.js b/dgbuilder/core_nodes/logic/15-change.js
new file mode 100644 (file)
index 0000000..b7ef62e
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function ChangeNode(n) {
+        RED.nodes.createNode(this, n);
+        this.action = n.action;
+        this.property = n.property || "";
+        this.from = n.from || " ";
+        this.to = n.to || " ";
+        this.reg = (n.reg === null || n.reg);
+        var node = this;
+        if (node.reg === false) {
+            this.from = this.from.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+        }
+        var makeNew = function( stem, path, value ) {
+            var lastPart = (arguments.length === 3) ? path.pop() : false;
+            for (var i = 0; i < path.length; i++) {
+                stem = stem[path[i]] = stem[path[i]] || {};
+            }
+            if (lastPart) { stem = stem[lastPart] = value; }
+            return stem;
+        };
+
+        this.on('input', function (msg) {
+            if (node.action == "change") {
+                try {
+                    node.re = new RegExp(this.from, "g");
+                } catch (e) {
+                    node.error(e.message);
+                }
+                if (typeof msg[node.property] === "string") {
+                    msg[node.property] = (msg[node.property]).replace(node.re, node.to);
+                }
+            }
+            //else if (node.action == "replace") {
+                //if (node.to.indexOf("msg.") == 0) {
+                    //msg[node.property] = eval(node.to);
+                //}
+                //else {
+                    //msg[node.property] = node.to;
+                //}
+            //}
+            else if (node.action == "replace") {
+                if (node.to.indexOf("msg.") === 0) {
+                    makeNew( msg, node.property.split("."), eval(node.to) );
+                }
+                else {
+                    makeNew( msg, node.property.split("."), node.to );
+                }
+                //makeNew( msg, node.property.split("."), node.to );
+            }
+            else if (node.action == "delete") {
+                delete(msg[node.property]);
+            }
+            node.send(msg);
+        });
+    }
+    RED.nodes.registerType("change", ChangeNode);
+}
diff --git a/dgbuilder/core_nodes/logic/16-range.html b/dgbuilder/core_nodes/logic/16-range.html
new file mode 100644 (file)
index 0000000..5f87128
--- /dev/null
@@ -0,0 +1,81 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="range">
+    <div class="form-row">
+        <label for="node-input-action"><i class="fa fa-dot-circle-o"></i> Action</label>
+        <select id="node-input-action" style="width:70%; margin-right:5px;">
+            <option value="scale">Scale msg.payload</option>
+            <option value="clamp">Scale and limit to the target range</option>
+            <option value="roll">Scale and wrap within the target range</option>
+        </select>
+    </div>
+    <br/>
+    <div class="form-row"><i class="fa fa-sign-in"></i> Map the input range:</div>
+    <div class="form-row"><label></label>
+        from: <input type="text" id="node-input-minin" placeholder="e.g. 0" style="width:100px;"/>
+        &nbsp;&nbsp;to: <input type="text" id="node-input-maxin" placeholder="e.g. 99" style="width:100px;"/>
+    </div>
+    <div class="form-row"><i class="fa fa-sign-out"></i> to the result range:</div>
+    <div class="form-row"><label></label>
+        from: <input type="text" id="node-input-minout" placeholder="e.g. 0" style="width:100px;"/>
+        &nbsp;&nbsp;to: <input type="text" id="node-input-maxout" placeholder="e.g. 255" style="width:100px;"/>
+    </div>
+    <br/>
+    <div class="form-row"><label></label>
+        <input type="checkbox" id="node-input-round" style="display: inline-block; width: auto; vertical-align: top;">
+        <label style="width: auto;" for="node-input-round">Round result to the nearest integer?</label></input>
+    </div>
+    <br/>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips" id="node-tip">Tip: This node ONLY works with numbers.</div>
+</script>
+
+<script type="text/x-red" data-help-name="range">
+    <p>A simple function node to remap numeric input values to another scale.</p>
+    <p>Currently only does a linear scaling.</p>
+    <p><b>Note:</b> This only operates on <b>numbers</b>. Anything else will try to be made into a number and rejected if that fails.</p>
+    <p><i>Scale and limit to target range</i> means that the result will never be outside the range specified within the result range.</p>
+    <p><i>Scale and wrap within the target range</i> means that the result will essentially be a "modulo-style" wrap-around within the result range.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('range', {
+        color: "#E2D96E",
+        category: 'function',
+        defaults: {
+            minin: {value:"",required:true,validate:RED.validators.number()},
+            maxin: {value:"",required:true,validate:RED.validators.number()},
+            minout: {value:"",required:true,validate:RED.validators.number()},
+            maxout: {value:"",required:true,validate:RED.validators.number()},
+            action: {value:"scale"},
+            round: {value:false},
+            name: {value:""}
+        },
+        inputs: 1,
+        outputs: 1,
+        icon: "range.png",
+        label: function() {
+            return this.name || "range";
+        },
+        labelStyle: function() {
+            return this.name ? "node_label_italic" : "";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/logic/16-range.js b/dgbuilder/core_nodes/logic/16-range.js
new file mode 100644 (file)
index 0000000..ec39342
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function RangeNode(n) {
+        RED.nodes.createNode(this, n);
+        this.action = n.action;
+        this.round = n.round || false;
+        this.minin = Number(n.minin);
+        this.maxin = Number(n.maxin);
+        this.minout = Number(n.minout);
+        this.maxout = Number(n.maxout);
+        var node = this;
+
+        this.on('input', function (msg) {
+            var n = Number(msg.payload);
+            if (!isNaN(n)) {
+                if (node.action == "clamp") {
+                    if (n < node.minin) { n = node.minin; }
+                    if (n > node.maxin) { n = node.maxin; }
+                }
+                if (node.action == "roll") {
+                    if (n >= node.maxin) { n = (n - node.minin) % (node.maxin - node.minin) + node.minin; }
+                    if (n <  node.minin) { n = (n - node.minin) % (node.maxin - node.minin) + node.maxin; }
+                }
+                msg.payload = ((n - node.minin) / (node.maxin - node.minin) * (node.maxout - node.minout)) + node.minout;
+                if (node.round) { msg.payload = Math.round(msg.payload); }
+                node.send(msg);
+            }
+            else { node.log("Not a number: "+msg.payload); }
+        });
+    }
+    RED.nodes.registerType("range", RangeNode);
+}
diff --git a/dgbuilder/core_nodes/parsers/70-CSV.html b/dgbuilder/core_nodes/parsers/70-CSV.html
new file mode 100644 (file)
index 0000000..5632246
--- /dev/null
@@ -0,0 +1,123 @@
+
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="csv">
+    <div class="form-row">
+        <label for="node-input-temp"><i class="fa fa-list"></i> Columns</label>
+        <input type="text" id="node-input-temp" placeholder="comma-separated column names">
+    </div>
+    <div class="form-row">
+        <label for="node-input-select-sep"><i class="fa fa-text-width"></i> Separator</label>
+            <select style="width: 150px" id="node-input-select-sep">
+                <option value=",">comma</option>
+                <option value="\t">tab</option>
+                <option value=" ">space</option>
+                <option value=";">semicolon</option>
+                <option value=":">colon</option>
+                <option value="">other...</option>
+           </select>
+           <input style="width: 40px;" type="text" id="node-input-sep" pattern=".">
+    </div>
+
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <hr align="middle"/>
+    <div class="form-row">
+        <label style="width: 100%;"><i class="fa fa-gears"></i> CSV-to-Object options</label>
+        <label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-in"></i> Input</label>
+        <input style="width: 30px" type="checkbox" id="node-input-hdrin"><label style="width: auto;" for="node-input-hdrin">first row contains column names</span>
+    </div>
+    <div class="form-row">
+        <label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-out"></i> Output</label>
+        <select type="text" id="node-input-multi" style="width: 250px;">
+            <option value="one">a message per row</option>
+            <option value="mult">a single message [array]</option>
+        </select>
+    </div>
+    <hr align="middle"/>
+    <div class="form-row">
+        <label style="width: 100%;"><i class="fa fa-gears"></i> Object-to-CSV options</label>
+        <label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-in"></i> Output</label>
+        <input style="width: 30px" type="checkbox" id="node-input-hdrout"><label style="width: auto;" for="node-input-hdrout">include column name row</span>
+    </div>
+    <div class="form-row">
+        <label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-align-left"></i> Newline</label>
+        <select style="width: 150px" id="node-input-ret">
+            <option value='\n'>Linux (\n)</option>
+            <option value='\r'>Mac (\r)</option>
+            <option value='\r\n'>Windows (\r\n)</option>
+       </select>
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="csv">
+    <p>A function that parses the <b>msg.payload</b> to convert csv to/from a javascript object.
+    Places the result in the payload.</p>
+    <p>If the input is a string it tries to parse it as CSV and creates a javascript object.</p>
+    <p>If the input is a javascript object it tries to build a CSV string.</p>
+    <p>The columns template should contain an ordered list of column headers. For csv input these become the property names.
+    For csv output these specify the properties to extract from the object and the order for the csv.</p>
+    <p><b>Note:</b> the columns should always be specified comma separated - even if another separator is chosen for the data.</p>
+    </script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('csv',{
+        category: 'function',
+        color:"#DEBD5C",
+        defaults: {
+            name: {value:""},
+            sep: {value:',',required:true,validate:RED.validators.regex(/^.{1,2}$/)},
+            //quo: {value:'"',required:true},
+            hdrin: {value:""},
+            hdrout: {value:""},
+            multi: {value:"one",required:true},
+            ret: {value:'\\n'},
+            temp: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name||"csv";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if (this.sep == "," || this.sep == "\\t" || this.sep == ";" || this.sep == ":" || this.sep == " ") {
+                $("#node-input-select-sep").val(this.sep);
+                $("#node-input-sep").hide();
+            } else {
+                $("#node-input-select-sep").val("");
+                $("#node-input-sep").val(this.sep);
+                $("#node-input-sep").show();
+            }
+            $("#node-input-select-sep").change(function() {
+                var v = $("#node-input-select-sep option:selected").val();
+                $("#node-input-sep").val(v);
+                if (v == "") {
+                    $("#node-input-sep").val("");
+                    $("#node-input-sep").show().focus();
+                } else {
+                    $("#node-input-sep").hide();
+                }
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/parsers/70-CSV.js b/dgbuilder/core_nodes/parsers/70-CSV.js
new file mode 100644 (file)
index 0000000..56aa7c7
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function CSVNode(n) {
+        RED.nodes.createNode(this,n);
+        this.template = n.temp.split(",");
+        this.sep = (n.sep || ',').replace("\\t","\t").replace("\\n","\n").replace("\\r","\r");
+        this.quo = '"';
+        this.ret = (n.ret || "\n").replace("\\n","\n").replace("\\r","\r");
+        this.winflag = (this.ret === "\r\n");
+        this.lineend = "\n";
+        this.multi = n.multi || "one";
+        this.hdrin = n.hdrin || false;
+        this.hdrout = n.hdrout || false;
+        this.goodtmpl = true;
+        var node = this;
+
+        // pass in an array of column names to be trimed, de-quoted and retrimed
+        var clean = function(col) {
+            for (var t = 0; t < col.length; t++) {
+                col[t] = col[t].trim(); // remove leading and trailing whitespace
+                if (col[t].charAt(0) === '"' && col[t].charAt(col[t].length -1) === '"') {
+                    // remove leading and trailing quotes (if they exist) - and remove whitepace again.
+                    col[t] = col[t].substr(1,col[t].length -2).trim();
+                }
+            }
+            if ((col.length === 1) && (col[0] === "")) { node.goodtmpl = false; }
+            else { node.goodtmpl = true; }
+            return col;
+        }
+        node.template = clean(node.template);
+
+        this.on("input", function(msg) {
+            if (msg.hasOwnProperty("payload")) {
+                if (typeof msg.payload == "object") { // convert object to CSV string
+                    try {
+                        var ou = "";
+                        if (node.hdrout) {
+                            ou += node.template.join(node.sep) + node.ret;
+                        }
+                        if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
+                        for (var s = 0; s < msg.payload.length; s++) {
+                            for (var t=0; t < node.template.length; t++) {
+
+                                // aaargh - resorting to eval here - but fairly contained front and back.
+                                var p = RED.util.ensureString(eval("msg.payload[s]."+node.template[t]));
+
+                                if (p === "undefined") { p = ""; }
+                                if (p.indexOf(node.sep) != -1) { // add quotes if any "commas"
+                                    ou += node.quo + p + node.quo + node.sep;
+                                }
+                                else if (p.indexOf(node.quo) != -1) { // add double quotes if any quotes
+                                    p = p.replace(/"/g, '""');
+                                    ou += node.quo + p + node.quo + node.sep;
+                                }
+                                else { ou += p + node.sep; } // otherwise just add
+                            }
+                            ou = ou.slice(0,-1) + node.ret; // remove final "comma" and add "newline"
+                        }
+                        node.send({payload:ou});
+                    }
+                    catch(e) { node.log(e); }
+                }
+                else if (typeof msg.payload == "string") { // convert CSV string to object
+                    try {
+                        var f = true; // flag to indicate if inside or outside a pair of quotes true = outside.
+                        var j = 0; // pointer into array of template items
+                        var k = [""]; // array of data for each of the template items
+                        var o = {}; // output object to build up
+                        var a = []; // output array is needed for multiline option
+                        var first = true; // is this the first line
+                        var tmp = "";
+
+                        // For now we are just going to assume that any \r or \n means an end of line...
+                        //   got to be a weird csv that has singleton \r \n in it for another reason...
+
+                        // Now process the whole file/line
+                        for (var i = 0; i < msg.payload.length; i++) {
+                            if ((node.hdrin === true) && first) { // if the template is in the first line
+                                if ((msg.payload[i] === "\n")||(msg.payload[i] === "\r")) { // look for first line break
+                                    node.template = clean(tmp.split(node.sep));
+                                    first = false;
+                                }
+                                else { tmp += msg.payload[i]; }
+                            }
+                            else {
+                                if (msg.payload[i] === node.quo) { // if it's a quote toggle inside or outside
+                                    f = !f;
+                                    if (msg.payload[i-1] === node.quo) { k[j] += '\"'; } // if it's a quotequote then it's actually a quote
+                                }
+                                else if ((msg.payload[i] === node.sep) && f) { // if we are outside of quote (ie valid separator
+                                    if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
+                                    if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "" ) ) {
+                                        if (!isNaN(Number(k[j]))) { k[j] = Number(k[j]); }
+                                        o[node.template[j]] = k[j];
+                                    }
+                                    j += 1;
+                                    k[j] = "";
+                                }
+                                else if (f && ((msg.payload[i] === "\n") || (msg.payload[i] === "\r"))) { // handle multiple lines
+                                    //console.log(j,k,o,k[j]);
+                                    if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
+                                        if (!isNaN(Number(k[j]))) { k[j] = Number(k[j]); }
+                                        else { k[j].replace(/\r$/,''); }
+                                        o[node.template[j]] = k[j];
+                                    }
+                                    if (JSON.stringify(o) !== "{}") { // don't send empty objects
+                                        if (node.multi === "one") { node.send({payload:o}); } // either send
+                                        else { a.push(o); } // or add to the array
+                                    }
+                                    j = 0;
+                                    k = [""];
+                                    o = {};
+                                }
+                                else { // just add to the part of the message
+                                    k[j] += msg.payload[i];
+                                }
+                            }
+                        }
+                        // Finished so finalize and send anything left
+                        //console.log(j,k,o,k[j]);
+                        if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
+                        if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
+                            if (!isNaN(Number(k[j]))) { k[j] = Number(k[j]); }
+                            else { k[j].replace(/\r$/,''); }
+                            o[node.template[j]] = k[j];
+                        }
+                        msg.payload = o;
+                        if (JSON.stringify(o) !== "{}") { // don't send empty objects
+                            if (node.multi === "one") { node.send({payload:o}); } // either send
+                            else { a.push(o); } // or add to the aray
+                        }
+                        if (node.multi !== "one") { node.send({payload:a}); } // finally send the array
+                    }
+                    catch(e) { node.log(e); }
+                }
+                else { node.log("This node only handles csv strings or js objects."); }
+            }
+        });
+    }
+    RED.nodes.registerType("csv",CSVNode);
+}
diff --git a/dgbuilder/core_nodes/parsers/70-HTML.html b/dgbuilder/core_nodes/parsers/70-HTML.html
new file mode 100644 (file)
index 0000000..2b73b49
--- /dev/null
@@ -0,0 +1,73 @@
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="html">
+    <div class="form-row">
+        <label for="node-input-tag"><i class="fa fa-filter"></i> Select</label>
+        <input type="text" id="node-input-tag" placeholder="h1">
+    </div>
+    <div class="form-row">
+        <label for="node-input-ret"><i class="fa fa-sign-out"></i> Output</label>
+        <select id="node-input-ret" style="width:73% !important">
+            <option value="html">the html content of the elements</option>
+            <option value="text">only the text content of the elements</option>
+            <!-- <option value="attr">an object of any attributes</option> -->
+            <!-- <option value="val">return the value from a form element</option> -->
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-as">&nbsp;</label>
+        <select id="node-input-as" style="width:73% !important">
+            <option value="single">as a single message containing an array</option>
+            <option value="multi">as multiple messages, one for each element</option>
+        </select>
+    </div>
+    <br/>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: The <b>Select</b> value is a <a href="http://api.jquery.com/category/selectors/" target="_new"><i><u>jQuery</u></i></a> style selector.</div>
+</script>
+
+<script type="text/x-red" data-help-name="html">
+    <p>Extracts elements from an html document held in <b>msg.payload</b> using a selector.</p>
+    <p>The selector uses the <a href="http://api.jquery.com/category/selectors/" target="_new">jQuery syntax</a>.</p>
+    <p>The result is either a single message with a payload containing an array of the matched elements, or multiple
+       messages that each contain a matched element.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('html',{
+        category: 'function',
+        color:"#DEBD5C",
+        defaults: {
+            tag: {value:""},
+            ret: {value:"html"},
+            as: {value:"single"},
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "jq.png",
+        label: function() {
+            return this.name||this.tag||"html";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/parsers/70-HTML.js b/dgbuilder/core_nodes/parsers/70-HTML.js
new file mode 100644 (file)
index 0000000..7a9450f
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var cheerio = require('cheerio');
+
+    function CheerioNode(n) {
+        RED.nodes.createNode(this,n);
+        this.tag = n.tag || "h1";
+        this.ret = n.ret || "html";
+        this.as = n.as || "single";
+        var node = this;
+        this.on("input", function(msg) {
+            try {
+                var $ = cheerio.load(msg.payload);
+                var pay = [];
+                $(node.tag).each(function() {
+                    if (node.as === "multi") {
+                        var pay2 = null;
+                        if (node.ret === "html") { pay2 = $(this).html(); }
+                        if (node.ret === "text") { pay2 = $(this).text(); }
+                        //if (node.ret === "attr") { pay2 = $(this)[0]["attribs"]; }
+                        //if (node.ret === "val")  { pay2 = $(this).val(); }
+                        if (pay2) {
+                            msg.payload = pay2;
+                            node.send(msg);
+                        }
+                    }
+                    if (node.as === "single") {
+                        if (node.ret === "html") { pay.push( $(this).html() ); }
+                        if (node.ret === "text") { pay.push( $(this).text() ); }
+                        //if (node.ret === "attr") { pay.push( $(this)[0]["attribs"] ); }
+                        //if (node.ret === "val")  { pay.push( $(this).val() ); }
+                    }
+                });
+                if ((node.as === "single") && (pay.length !== 0)) {
+                    msg.payload = pay;
+                    node.send(msg);
+                }
+            } catch (error) {
+                node.log('Error: '+error.message);
+            }
+        });
+    }
+    RED.nodes.registerType("html",CheerioNode);
+}
diff --git a/dgbuilder/core_nodes/parsers/70-JSON.html b/dgbuilder/core_nodes/parsers/70-JSON.html
new file mode 100644 (file)
index 0000000..864974a
--- /dev/null
@@ -0,0 +1,47 @@
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="json">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="json">
+    <p>A function that parses the <b>msg.payload</b> to convert a JSON string to/from a javascript object. Places the result back into the payload.</p>
+    <p>If the input is a JSON string it tries to parse it to a javascript object.</p>
+    <p>If the input is a javascript object it creates a JSON string.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('json',{
+        category: 'function',
+        color:"#DEBD5C",
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name||"json";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/parsers/70-JSON.js b/dgbuilder/core_nodes/parsers/70-JSON.js
new file mode 100644 (file)
index 0000000..e216bd4
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+
+    function JSONNode(n) {
+        RED.nodes.createNode(this,n);
+        var node = this;
+        this.on("input", function(msg) {
+            if (msg.hasOwnProperty("payload")) {
+                if (typeof msg.payload === "string") {
+                    try {
+                        msg.payload = JSON.parse(msg.payload);
+                        node.send(msg);
+                    }
+                    catch(e) { node.log(e+ "\n"+msg.payload); }
+                }
+                else if (typeof msg.payload === "object") {
+                    if (!Buffer.isBuffer(msg.payload) ) {
+                        if (!util.isArray(msg.payload)) {
+                            msg.payload = JSON.stringify(msg.payload);
+                            node.send(msg);
+                        }
+                    }
+                }
+                else { node.log("dropped: "+msg.payload); }
+            }
+        });
+    }
+    RED.nodes.registerType("json",JSONNode);
+}
diff --git a/dgbuilder/core_nodes/parsers/70-XML.html b/dgbuilder/core_nodes/parsers/70-XML.html
new file mode 100644 (file)
index 0000000..8b0a284
--- /dev/null
@@ -0,0 +1,48 @@
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="xml">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="xml">
+    <p>A function that parses the <b>msg.payload</b> to convert xml to/from a javascript object. Places the result in the payload.</p>
+    <p>If the input is a string it tries to parse it as XML and creates a javascript object.</p>
+    <p>If the input is a javascript object it tries to build an XML string.</p>
+    <p>See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md" target="_new">the xml2js docs <i>here</i></a> for more information.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('xml',{
+        category: 'function',
+        color:"#DEBD5C",
+        defaults: {
+            name: {value:""}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name||"xml";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/parsers/70-XML.js b/dgbuilder/core_nodes/parsers/70-XML.js
new file mode 100644 (file)
index 0000000..931de7f
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var xml2js = require('xml2js');
+    var parseString = xml2js.parseString;
+    var builder = new xml2js.Builder({renderOpts:{pretty:false}});
+
+    function XMLNode(n) {
+        RED.nodes.createNode(this,n);
+        var node = this;
+        this.on("input", function(msg) {
+            if (msg.hasOwnProperty("payload")) {
+                if (typeof msg.payload == "object") {
+                    msg.payload = builder.buildObject(msg.payload);
+                    node.send(msg);
+                }
+                else if (typeof msg.payload == "string") {
+                    parseString(msg.payload, {strict:true,async:true}, function (err, result) {
+                        if (err) { node.error(err); }
+                        else {
+                            msg.payload = result;
+                            node.send(msg);
+                        }
+                    });
+                }
+                else { node.log("This node only handles xml strings or js objects."); }
+            }
+        });
+    }
+    RED.nodes.registerType("xml",XMLNode);
+}
diff --git a/dgbuilder/core_nodes/social/27-twitter.html b/dgbuilder/core_nodes/social/27-twitter.html
new file mode 100644 (file)
index 0000000..99d4521
--- /dev/null
@@ -0,0 +1,223 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="twitter-credentials">
+    <div class="form-row" id="node-config-twitter-row"></div>
+    <input type="hidden" id="node-config-input-screen_name">
+</script>
+
+<script type="text/javascript">
+(function() {
+    var twitterConfigNodeId = null;
+    var twitterConfigNodeIntervalId = null;
+
+    function showTwitterAuthStart() {
+        var pathname = document.location.pathname;
+        if (pathname.slice(-1) != "/") {
+            pathname += "/";
+        }
+        var callback = encodeURIComponent(location.protocol+"//"+location.hostname+":"+location.port+pathname+"twitter-credentials/"+twitterConfigNodeId+"/auth/callback");
+        $("#node-config-dialog-ok").button("disable");
+        $("#node-config-twitter-row").html('<div style="text-align: center; margin-top: 20px; "><a class="btn" id="node-config-twitter-start" href="twitter-credentials/'+twitterConfigNodeId+'/auth?callback='+callback+'" target="_blank">Click here to authenticate with Twitter.</a></div>');
+        $("#node-config-twitter-start").click(function() {
+            twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
+        });
+    }
+    function updateTwitterScreenName(sn) {
+        $("#node-config-input-screen_name").val(sn);
+        $("#node-config-twitter-row").html('<label><i class="fa fa-user"></i> Twitter ID</label><span class="input-xlarge uneditable-input">'+sn+'</span>');
+    }
+    function pollTwitterCredentials(e) {
+        $.getJSON('credentials/twitter-credentials/'+twitterConfigNodeId,function(data) {
+            if (data.screen_name) {
+                updateTwitterScreenName(data.screen_name);
+                twitterConfigNodeIntervalId = null;
+                $("#node-config-dialog-ok").button("enable");
+            } else {
+                twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
+            }
+        })
+    }
+    RED.nodes.registerType('twitter-credentials',{
+        category: 'config',
+        defaults: {
+            screen_name: {value:""}
+        },
+        credentials: {
+            screen_name: {type:"text"},
+            access_token: {type: "password"},
+            access_token_secret: {type:"password"}
+        },
+            
+        label: function() {
+            return this.screen_name;
+        },
+        exportable: false,
+        oneditprepare: function() {
+            twitterConfigNodeId = this.id;
+            if (!this.screen_name || this.screen_name == "") {
+                showTwitterAuthStart();
+            } else {
+                if (this.credentials.screen_name) {
+                    updateTwitterScreenName(this.credentials.screen_name);
+                } else {
+                    showTwitterAuthStart();
+                }
+            }
+        },
+        oneditsave: function() {
+            if (twitterConfigNodeIntervalId) {
+                window.clearTimeout(twitterConfigNodeIntervalId);
+            }
+        },
+        oneditcancel: function(adding) {
+            if (twitterConfigNodeIntervalId) {
+                window.clearTimeout(twitterConfigNodeIntervalId);
+            }
+        }
+    });
+})();
+</script>
+
+<script type="text/x-red" data-template-name="twitter in">
+    <div class="form-row">
+        <label for="node-input-twitter"><i class="fa fa-user"></i> Log in as</label>
+        <input type="text" id="node-input-twitter">
+    </div>
+    <div class="form-row">
+        <label for="node-input-user"><i class="fa fa-search"></i> Search</label>
+        <select type="text" id="node-input-user" style="display: inline-block; vertical-align: middle; width:60%;">
+            <option value="false">all public tweets</option>
+            <option value="true">the tweets of who you follow</option>
+            <option value="user">the tweets of specific users</option>
+            <option value="dm">your direct messages</option>
+        </select>
+    </div>
+    <div class="form-row" id="node-input-tags-row">
+        <label for="node-input-tags"><i class="fa fa-tags"></i> <span id="node-input-tags-label">for</span></label>
+        <input type="text" id="node-input-tags" placeholder="comma-separated words, @ids, #tags">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">Tip: Use commas without spaces between multiple search terms. Comma = OR, Space = AND.
+    <br/>The Twitter API WILL NOT deliver 100% of all tweets.
+    <br/>Tweets of who you follow will include their retweets and favourites.</div>
+</script>
+
+<script type="text/x-red" data-help-name="twitter in">
+    <p>Twitter input node. Can be used to search either:
+    <ul><li>the public or a user's stream for tweets containing the configured search term</li>
+        <li>all tweets by specific users</li>
+        <li>direct messages received by the authenticated user</li>
+    </ul></p>
+    <p>Use space for <i>and</i> and comma , for <i>or</i> when searching for multiple terms.</p>
+    <p>Sets the <b>msg.topic</b> to <i>tweets/</i> and then appends the senders screen name.</p>
+    <p>Sets <b>msg.location</b> to the tweeters location if known.</p>
+    <p>Sets <b>msg.tweet</b> to the full tweet object as documented by <a href="https://dev.twitter.com/docs/platform-objects/tweets">Twitter</a>.
+    <p><b>Note:</b> when set to a specific user's tweets, or your direct messages, the node is subject to
+      Twitter's API rate limiting. If you deploy the flows multiple times within a 15 minute window, you may
+      exceed the limit and will see errors from the node. These errors will clear when the current 15 minute window
+      passes.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('twitter in',{
+        category: 'social-input',
+        color:"#C0DEED",
+        defaults: {
+            twitter: {type:"twitter-credentials",required:true},
+            tags: {value:"",validate:function(v) { return this.user == "dm" || v.length > 0;}},
+            user: {value:"false",required:true},
+            name: {value:""},
+            topic: {value:"tweets"}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "twitter.png",
+        label: function() {
+            if (this.name) {
+                return this.name;
+            }
+            if (this.user == "dm") {
+                var user = RED.nodes.node(this.twitter);
+                return (user?user.label()+" ":"")+"DMs";
+            } else if (this.user == "user") {
+                return this.tags+" tweets";
+            }
+            return this.tags;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $("#node-input-user").change(function() {
+                var type = $("#node-input-user option:selected").val();
+                if (type == "user") {
+                    $("#node-input-tags-row").show();
+                    $("#node-input-tags-label").html("User");
+                    $("#node-input-tags").attr("placeholder","comma-separated @twitter handles");
+                } else if (type == "dm") {
+                    $("#node-input-tags-row").hide();
+                } else {
+                    $("#node-input-tags-row").show();
+                    $("#node-input-tags-label").html("for");
+                    $("#node-input-tags").attr("placeholder","comma-separated words, @ids, #hashtags");
+                }                
+
+            });
+            $("#node-input-user").change();
+        
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="twitter out">
+    <div class="form-row">
+        <label for="node-input-twitter"><i class="fa fa-user"></i> Twitter</label>
+        <input type="text" id="node-input-twitter">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="twitter out">
+    <p>Twitter out node. Tweets the <b>msg.payload</b>.</p>
+    <p>If <b>msg.media</b> exists and is a Buffer object, this node will treat it
+       as an image and attach it to the tweet.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('twitter out',{
+        category: 'social-output',
+        color:"#C0DEED",
+        defaults: {
+            twitter: {type:"twitter-credentials",required:true},
+            name: {value:"Tweet"}
+        },
+        inputs:1,
+        outputs:0,
+        icon: "twitter.png",
+        align: "right",
+        label: function() {
+            return this.name;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/social/27-twitter.js b/dgbuilder/core_nodes/social/27-twitter.js
new file mode 100644 (file)
index 0000000..5cacd9e
--- /dev/null
@@ -0,0 +1,347 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var ntwitter = require('twitter-ng');
+    var OAuth= require('oauth').OAuth;
+    var request = require('request');
+    
+    function TwitterNode(n) {
+        RED.nodes.createNode(this,n);
+        this.screen_name = n.screen_name;
+    }
+    RED.nodes.registerType("twitter-credentials",TwitterNode,{
+        credentials: {
+            screen_name: {type:"text"},
+            access_token: {type: "password"},
+            access_token_secret: {type:"password"}
+        }
+    });
+
+    function TwitterInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.active = true;
+        this.user = n.user;
+        //this.tags = n.tags.replace(/ /g,'');
+        this.tags = n.tags;
+        this.twitter = n.twitter;
+        this.topic = n.topic||"tweets";
+        this.twitterConfig = RED.nodes.getNode(this.twitter);
+        var credentials = RED.nodes.getCredentials(this.twitter);
+
+        if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
+            var twit = new ntwitter({
+                consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
+                consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
+                access_token_key: credentials.access_token,
+                access_token_secret: credentials.access_token_secret
+            });
+
+
+            //setInterval(function() {
+            //        twit.get("/application/rate_limit_status.json",null,function(err,cb) {
+            //                console.log("direct_messages:",cb["resources"]["direct_messages"]);
+            //        });
+            //
+            //},10000);
+
+            var node = this;
+            if (this.user === "user") {
+                node.poll_ids = [];
+                node.since_ids = {};
+                var users = node.tags.split(",");
+                for (var i=0;i<users.length;i++) {
+                    var user = users[i].replace(" ","");
+                    twit.getUserTimeline({
+                            screen_name:user,
+                            trim_user:0,
+                            count:1
+                    },function() {
+                        var u = user+"";
+                        return function(err,cb) {
+                            if (err) {
+                                node.error(err);
+                                return;
+                            }
+                            if (cb[0]) {
+                                node.since_ids[u] = cb[0].id_str;
+                            } else {
+                                node.since_ids[u] = '0';
+                            }
+                            node.poll_ids.push(setInterval(function() {
+                                twit.getUserTimeline({
+                                        screen_name:u,
+                                        trim_user:0,
+                                        since_id:node.since_ids[u]
+                                },function(err,cb) {
+                                    if (cb) {
+                                        for (var t=cb.length-1;t>=0;t-=1) {
+                                            var tweet = cb[t];
+                                            var where = tweet.user.location||"";
+                                            var la = tweet.lang || tweet.user.lang;
+                                            //console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
+                                            var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
+                                            node.send(msg);
+                                            if (t == 0) {
+                                                node.since_ids[u] = tweet.id_str;
+                                            }
+                                        }
+                                    }
+                                    if (err) {
+                                        node.error(err);
+                                    }
+                                });
+                            },60000));
+                        }
+                    }());
+                }
+            } else if (this.user === "dm") {
+                node.poll_ids = [];
+                twit.getDirectMessages({
+                        screen_name:node.twitterConfig.screen_name,
+                        trim_user:0,
+                        count:1
+                },function(err,cb) {
+                    if (err) {
+                        node.error(err);
+                        return;
+                    }
+                    if (cb[0]) {
+                        node.since_id = cb[0].id_str;
+                    } else {
+                        node.since_id = '0';
+                    }
+                    node.poll_ids.push(setInterval(function() {
+                            twit.getDirectMessages({
+                                    screen_name:node.twitterConfig.screen_name,
+                                    trim_user:0,
+                                    since_id:node.since_id
+                            },function(err,cb) {
+                                if (cb) {
+                                    for (var t=cb.length-1;t>=0;t-=1) {
+                                        var tweet = cb[t];
+                                        var msg = { topic:node.topic+"/"+tweet.sender.screen_name, payload:tweet.text, tweet:tweet };
+                                        node.send(msg);
+                                        if (t == 0) {
+                                            node.since_id = tweet.id_str;
+                                        }
+                                    }
+                                }
+                                if (err) {
+                                    node.error(err);
+                                }
+                            });
+                    },120000));
+                });
+
+            } else if (this.tags !== "") {
+                try {
+                    var thing = 'statuses/filter';
+                    if (this.user === "true") { thing = 'user'; }
+                    var st = { track: [node.tags] };
+                    var bits = node.tags.split(",");
+                    if ((bits.length > 0) && (bits.length % 4 == 0)) {
+                        if ((Number(bits[0]) < Number(bits[2])) && (Number(bits[1]) < Number(bits[3]))) {
+                            st = { locations: node.tags };
+                        }
+                        else {
+                            node.log("possible bad geo area format. Should be lower-left lon, lat, upper-right lon, lat");
+                        }
+                    }
+
+                    var setupStream = function() {
+                        if (node.active) {
+                            twit.stream(thing, st, function(stream) {
+                                //console.log(st);
+                                //twit.stream('user', { track: [node.tags] }, function(stream) {
+                                //twit.stream('site', { track: [node.tags] }, function(stream) {
+                                //twit.stream('statuses/filter', { track: [node.tags] }, function(stream) {
+                                node.stream = stream;
+                                stream.on('data', function(tweet) {
+                                    //console.log(tweet.user);
+                                    if (tweet.user !== undefined) {
+                                        var where = tweet.user.location||"";
+                                        var la = tweet.lang || tweet.user.lang;
+                                        //console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
+                                        var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
+                                        node.send(msg);
+                                    }
+                                });
+                                stream.on('limit', function(tweet) {
+                                    node.log("tweet rate limit hit");
+                                });
+                                stream.on('error', function(tweet,rc) {
+                                    if (rc == 420) {
+                                        node.warn("Twitter rate limit hit");
+                                    } else {
+                                        node.warn("Stream error:"+tweet.toString()+" ("+rc+")");
+                                    }
+                                    setTimeout(setupStream,10000);
+                                });
+                                stream.on('destroy', function (response) {
+                                    if (this.active) {
+                                        node.warn("twitter ended unexpectedly");
+                                        setTimeout(setupStream,10000);
+                                    }
+                                });
+                            });
+                        }
+                    }
+                    setupStream();
+                }
+                catch (err) {
+                    node.error(err);
+                }
+            } else {
+                this.error("Invalid tag property");
+            }
+        } else {
+            this.error("missing twitter credentials");
+        }
+
+        this.on('close', function() {
+            if (this.stream) {
+                this.active = false;
+                this.stream.destroy();
+            }
+            if (this.poll_ids) {
+                for (var i=0;i<this.poll_ids.length;i++) {
+                    clearInterval(this.poll_ids[i]);
+                }
+            }
+        });
+    }
+    RED.nodes.registerType("twitter in",TwitterInNode);
+
+
+    function TwitterOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.topic = n.topic;
+        this.twitter = n.twitter;
+        this.twitterConfig = RED.nodes.getNode(this.twitter);
+        var credentials = RED.nodes.getCredentials(this.twitter);
+        var node = this;
+
+        if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
+            var twit = new ntwitter({
+                consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
+                consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
+                access_token_key: credentials.access_token,
+                access_token_secret: credentials.access_token_secret
+            });
+            node.on("input", function(msg) {
+                node.status({fill:"blue",shape:"dot",text:"tweeting"});
+
+                if (msg.payload.length > 140) {
+                    msg.payload = msg.payload.slice(0,139);
+                    node.warn("Tweet greater than 140 : truncated");
+                }
+
+                if (msg.media && Buffer.isBuffer(msg.media)) {
+                    var apiUrl = "https://api.twitter.com/1.1/statuses/update_with_media.json";
+                    var signedUrl = oa.signUrl(apiUrl,
+                        credentials.access_token,
+                        credentials.access_token_secret,
+                        "POST");
+
+                    var r = request.post(signedUrl,function(err,httpResponse,body) {
+                        if (err) {
+                            node.error(err.toString());
+                            node.status({fill:"red",shape:"ring",text:"failed"});
+                        } else {
+                            var response = JSON.parse(body);
+                            if (body.errors) {
+                                var errorList = body.errors.map(function(er) { return er.code+": "+er.message }).join(", ");
+                                node.error("tweet failed: "+errorList);
+                                node.status({fill:"red",shape:"ring",text:"failed"});
+                            } else {
+                                node.status({});
+                            }
+                        }
+                    });
+                    var form = r.form();
+                    form.append("status",msg.payload);
+                    form.append("media[]",msg.media,{filename:"image"});
+
+                } else {
+                    twit.updateStatus(msg.payload, function (err, data) {
+                        if (err) {
+                            node.status({fill:"red",shape:"ring",text:"failed"});
+                            node.error(err);
+                        }
+                        node.status({});
+                    });
+                }
+            });
+        }
+    }
+    RED.nodes.registerType("twitter out",TwitterOutNode);
+
+    var oa = new OAuth(
+        "https://api.twitter.com/oauth/request_token",
+        "https://api.twitter.com/oauth/access_token",
+        "OKjYEd1ef2bfFolV25G5nQ",
+        "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
+        "1.0",
+        null,
+        "HMAC-SHA1"
+    );
+
+    RED.httpAdmin.get('/twitter-credentials/:id/auth', function(req, res){
+        var credentials = {};
+        oa.getOAuthRequestToken({
+                oauth_callback: req.query.callback
+        },function(error, oauth_token, oauth_token_secret, results){
+            if (error) {
+                var resp = '<h2>Oh no!</h2>'+
+                '<p>Something went wrong with the authentication process. The following error was returned:<p>'+
+                '<p><b>'+error.statusCode+'</b>: '+error.data+'</p>'+
+                '<p>One known cause of this type of failure is if the clock is wrong on system running Node-RED.';
+                res.send(resp)
+            } else {
+                credentials.oauth_token = oauth_token;
+                credentials.oauth_token_secret = oauth_token_secret;
+                res.redirect('https://twitter.com/oauth/authorize?oauth_token='+oauth_token)
+                RED.nodes.addCredentials(req.params.id,credentials);
+            }
+        });
+    });
+
+    RED.httpAdmin.get('/twitter-credentials/:id/auth/callback', function(req, res, next){
+        var credentials = RED.nodes.getCredentials(req.params.id);
+        credentials.oauth_verifier = req.query.oauth_verifier;
+
+        oa.getOAuthAccessToken(
+            credentials.oauth_token,
+            credentials.token_secret,
+            credentials.oauth_verifier,
+            function(error, oauth_access_token, oauth_access_token_secret, results){
+                if (error){
+                    console.log(error);
+                    res.send("yeah something broke.");
+                } else {
+                    credentials = {};
+                    credentials.access_token = oauth_access_token;
+                    credentials.access_token_secret = oauth_access_token_secret;
+                    credentials.screen_name = "@"+results.screen_name;
+                    RED.nodes.addCredentials(req.params.id,credentials);
+                    res.send("<html><head></head><body>Authorised - you can close this window and return to Node-RED</body></html>");
+                }
+            }
+        );
+    });
+}
diff --git a/dgbuilder/core_nodes/social/32-feedparse.html b/dgbuilder/core_nodes/social/32-feedparse.html
new file mode 100644 (file)
index 0000000..a795427
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="feedparse">
+    <div class="form-row">
+        <label for="node-input-url"><i class="fa fa-globe"></i> Feed url</label>
+        <input type="text" id="node-input-url">
+    </div>
+    <div class="form-row">
+        <label for="node-input-interval"><i class="fa fa-repeat"></i> Repeat <span style="font-size: 0.9em;">(M)</span></label>
+        <input type="text" id="node-input-interval" placeholder="minutes">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <!-- <div class="form-tips"></div> -->
+</script>
+
+<script type="text/x-red" data-help-name="feedparse">
+       <p>Monitors an RSS/atom feed for new entries.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('feedparse',{
+        category: 'advanced-input',
+        color:"#C0DEED",
+        defaults: {
+            name: {value:""},
+            url: {value:"", required:true},
+            interval: { value:15, required: true,validate:RED.validators.number()}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "feed.png",
+        label: function() {
+            return this.name||this.url;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+
+</script>
diff --git a/dgbuilder/core_nodes/social/32-feedparse.js b/dgbuilder/core_nodes/social/32-feedparse.js
new file mode 100644 (file)
index 0000000..97630e7
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var FeedParser = require("feedparser");
+    var request = require("request");
+
+    function FeedParseNode(n) {
+        RED.nodes.createNode(this,n);
+        this.url = n.url;
+        this.interval = (parseInt(n.interval)||15)*60000;
+        var node = this;
+        this.interval_id = null;
+        this.seen = {};
+        if (this.url !== "") {
+            var getFeed = function() {
+                request(node.url,function(err) {
+                        if (err) node.error(err);
+                })
+                    .pipe(new FeedParser({feedurl:node.url}))
+                    .on('error', function(error) {
+                            node.error(error);
+                    })
+                    .on('meta', function (meta) {})
+                    .on('readable', function () {
+                            var stream = this, article;
+                            while (article = stream.read()) {
+                                if (!(article.guid in node.seen) || ( node.seen[article.guid] != 0 && node.seen[article.guid] != article.date.getTime())) {
+                                    node.seen[article.guid] = article.date?article.date.getTime():0;
+                                    var msg = {
+                                        topic:article.origlink||article.link,
+                                        payload: article.description,
+                                        article: article
+                                    };
+                                    node.send(msg);
+                                }
+                            }
+                    })
+                    .on('end', function () {
+                    });
+            };
+            this.interval_id = setInterval(getFeed,node.interval);
+            getFeed();
+
+        } else {
+            this.error("Invalid url");
+        }
+    }
+
+    RED.nodes.registerType("feedparse",FeedParseNode);
+
+    FeedParseNode.prototype.close = function() {
+        if (this.interval_id != null) {
+            clearInterval(this.interval_id);
+        }
+    }
+}
diff --git a/dgbuilder/core_nodes/social/61-email.html b/dgbuilder/core_nodes/social/61-email.html
new file mode 100644 (file)
index 0000000..3739708
--- /dev/null
@@ -0,0 +1,189 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="e-mail">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-envelope"></i> To</label>
+        <input type="text" id="node-input-name" placeholder="email@address.com">
+    </div>
+    <!-- <div class="form-row">
+        <label for="node-input-pin"><i class="fa fa-asterisk"></i> Service</label>
+        <select type="text" id="node-input-pin" style="width: 150px;">
+            <option value="-" disabled> </option>
+            <option value="DynectEmail">DynectEmail</option>
+            <option value="Gmail">Gmail</option>
+            <option value="hot.ee">hot.ee</option>
+            <option value="Hotmail">Hotmail</option>
+            <option value="iCloud">iCloud</option>
+            <option value="mail.ee">mail.ee</option>
+            <option value="Mail.Ru">Mail.Ru</option>
+            <option value="Mailgun">Mailgun</option>
+            <option value="Mailjet">Mailjet</option>
+            <option value="Mandrill">Mandrill</option>
+            <option value="Postmark">Postmark</option>
+            <option value="QQ">QQ</option>
+            <option value="QQex">QQex</option>
+            <option value="SendGrid">SendGrid</option>
+            <option value="SendCloud">SendCloud</option>
+            <option value="SES">SES</option>
+            <option value="Yahoo">Yahoo</option>
+            <option value="yandex">yandex</option>
+            <option value="Zoho">Zoho</option>
+         </select>
+    </div> -->
+    <div class="form-row">
+        <label for="node-input-server"><i class="fa fa-globe"></i> Server</label>
+        <input type="text" id="node-input-server" placeholder="smtp.gmail.com">
+    </div>
+    <div class="form-row">
+        <label for="node-input-port"><i class="fa fa-random"></i> Port</label>
+        <input type="text" id="node-input-port" placeholder="465">
+    </div>
+    <div class="form-row">
+        <label for="node-input-userid"><i class="fa fa-user"></i> Userid</label>
+        <input type="text" id="node-input-userid">
+    </div>
+    <div class="form-row">
+        <label for="node-input-password"><i class="fa fa-lock"></i> Password</label>
+        <input type="password" id="node-input-password">
+    </div>
+    <br/>
+    <div class="form-row">
+        <label for="node-input-dname"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-dname" placeholder="Name">
+    </div>
+    <div class="form-tips" id="node-tip"><b>Note:</b> Copied credentials from global emailkeys.js file.</div>
+</script>
+
+<script type="text/x-red" data-help-name="e-mail">
+    <p>Sends the <b>msg.payload</b> as an email, with a subject of <b>msg.topic</b>.</p>
+    <!-- <p>It sends the message to the configured recipient <i>only</i>.</p> -->
+    <p>You may dynamically overide the default recipient by setting a <b>msg.to</b> property.</p>
+    <!-- <p><b>msg.topic</b> is used to set the subject of the email, and <b>msg.payload</b> is the body text.</p> -->
+</script>
+
+<script type="text/javascript">
+(function() {
+    RED.nodes.registerType('e-mail',{
+        category: 'social-output',
+        color:"#c7e9c0",
+        defaults: {
+            server: {value:"smtp.gmail.com",required:true},
+            port: {value:"465",required:true},
+            name: {value:"",required:true},
+            dname: {value:""}
+        },
+        credentials: {
+            userid: {type:"text"},
+            password: {type: "password"},
+            global: { type:"boolean"}
+        },
+
+        inputs:1,
+        outputs:0,
+        icon: "envelope.png",
+        align: "right",
+        label: function() {
+            return this.dname||this.name||"email";
+        },
+        labelStyle: function() {
+            return (this.dname||!this.topic)?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if (this.credentials.global) {
+                $('#node-tip').show();
+            } else {
+                $('#node-tip').hide();
+            };
+        }
+    });
+})();
+</script>
+
+
+<script type="text/x-red" data-template-name="e-mail in">
+    <div class="form-row node-input-repeat">
+        <label for="node-input-repeat"><i class="fa fa-repeat"></i> Check Repeat (S)</label>
+        <input type="text" id="node-input-repeat" placeholder="300">
+    </div>
+    <div class="form-row">
+        <label for="node-input-server"><i class="fa fa-globe"></i> Server</label>
+        <input type="text" id="node-input-server" placeholder="imap.gmail.com">
+    </div>
+    <div class="form-row">
+        <label for="node-input-port"><i class="fa fa-random"></i> Port</label>
+        <input type="text" id="node-input-port" placeholder="993">
+    </div>
+    <div class="form-row">
+        <label for="node-input-userid"><i class="fa fa-user"></i> Userid</label>
+        <input type="text" id="node-input-userid">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
+        <input type="password" id="node-input-password">
+    </div>
+    <br/>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips" id="node-tip"><b>Note:</b> Copied credentials from global emailkeys.js file.</div>
+    <div id="node-input-tip" class="form-tips">Tip: <b>ONLY</b> retrieves the single most recent email.</div>
+</script>
+
+<script type="text/x-red" data-help-name="e-mail in">
+    <p>Repeatedly gets a <b>single email</b> from an IMAP server and forwards on as a msg if not already seen.</p>
+    <p>The subject is loaded into <b>msg.topic</b> and <b>msg.payload</b> is the plain text body.
+       If there is text/html then that is returned in <b>msg.html</b>. <b>msg.from</b> and <b>msg.date</b> are also set if you need them.</p>
+    <p>Uses the imap module.</p>
+    <p><b>Note:</b> this node <i>only</i> gets the most recent single email from the inbox, so set the repeat (polling) time appropriately.</p>
+</script>
+
+<script type="text/javascript">
+(function() {
+    RED.nodes.registerType('e-mail in',{
+        category: 'social-input',
+        color:"#c7e9c0",
+        defaults: {
+            repeat: {value:"300",required:true},
+            server: {value:"imap.gmail.com",required:true},
+            port: {value:"993",required:true},
+            name: {value:""}
+        },
+        credentials: {
+            userid: {type:"text"},
+            password: {type: "password"},
+            global: { type:"boolean"}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "envelope.png",
+        label: function() {
+            return this.name||"email";
+        },
+        labelStyle: function() {
+            return (this.name||!this.topic)?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if (this.credentials.global) {
+                $('#node-tip').show();
+            } else {
+                $('#node-tip').hide();
+            };
+        }
+    });
+})();
+</script>
diff --git a/dgbuilder/core_nodes/social/61-email.js b/dgbuilder/core_nodes/social/61-email.js
new file mode 100644 (file)
index 0000000..7d0f8cb
--- /dev/null
@@ -0,0 +1,246 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var nodemailer = require("nodemailer");
+    var Imap = require('imap');
+
+    //console.log(nodemailer.Transport.transports.SMTP.wellKnownHosts);
+
+    try {
+        var globalkeys = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js");
+    } catch(err) {
+    }
+
+    function EmailNode(n) {
+        RED.nodes.createNode(this,n);
+        this.topic = n.topic;
+        this.name = n.name;
+        this.outserver = n.server;
+        this.outport = n.port;
+        var flag = false;
+        if (this.credentials && this.credentials.hasOwnProperty("userid")) {
+            this.userid = this.credentials.userid;
+        } else {
+            if (globalkeys) {
+                this.userid = globalkeys.user;
+                flag = true;
+            } else {
+                this.error("No e-mail userid set");
+            }
+        }
+        if (this.credentials && this.credentials.hasOwnProperty("password")) {
+            this.password = this.credentials.password;
+        } else {
+            if (globalkeys) {
+                this.password = globalkeys.pass;
+                flag = true;
+            } else {
+                this.error("No e-mail password set");
+            }
+        }
+        if (flag) {
+            RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true});
+        }
+        var node = this;
+
+        var smtpTransport = nodemailer.createTransport({
+            host: node.outserver,
+            port: node.outport,
+            secure: true,
+            auth: {
+                user: node.userid,
+                pass: node.password
+            }
+        });
+
+        this.on("input", function(msg) {
+            if (smtpTransport) {
+                node.status({fill:"blue",shape:"dot",text:"sending"});
+                var payload = RED.util.ensureString(msg.payload);
+                smtpTransport.sendMail({
+                    from: node.userid, // sender address
+                    to: msg.to || node.name, // comma separated list of addressees
+                    subject: msg.topic, // subject line
+                    text: payload // plaintext body
+                }, function(error, info) {
+                    if (error) {
+                        node.error(error);
+                        node.status({fill:"red",shape:"ring",text:"send failed"});
+                    } else {
+                        node.log("Message sent: " + info.response);
+                        node.status({});
+                    }
+                });
+            }
+            else { node.warn("No Email credentials found. See info panel."); }
+        });
+    }
+    RED.nodes.registerType("e-mail",EmailNode,{
+        credentials: {
+            userid: {type:"text"},
+            password: {type: "password"},
+            global: { type:"boolean"}
+        }
+    });
+
+    function EmailInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.repeat = n.repeat * 1000 || 300000;
+        this.inserver = n.server || globalkeys.server || "imap.gmail.com";
+        this.inport = n.port || globalkeys.port || "993";
+        var flag = false;
+
+        if (this.credentials && this.credentials.hasOwnProperty("userid")) {
+            this.userid = this.credentials.userid;
+        } else {
+            if (globalkeys) {
+                this.userid = globalkeys.user;
+                flag = true;
+            } else {
+                this.error("No e-mail userid set");
+            }
+        }
+        if (this.credentials && this.credentials.hasOwnProperty("password")) {
+            this.password = this.credentials.password;
+        } else {
+            if (globalkeys) {
+                this.password = globalkeys.pass;
+                flag = true;
+            } else {
+                this.error("No e-mail password set");
+            }
+        }
+        if (flag) {
+            RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true});
+        }
+
+        var node = this;
+        this.interval_id = null;
+        var oldmail = {};
+
+        var imap = new Imap({
+            user: node.userid,
+            password: node.password,
+            host: node.inserver,
+            port: node.inport,
+            tls: true,
+            tlsOptions: { rejectUnauthorized: false },
+            connTimeout: node.repeat,
+            authTimeout: node.repeat
+        });
+
+        if (!isNaN(this.repeat) && this.repeat > 0) {
+            node.log("repeat = "+this.repeat);
+            this.interval_id = setInterval( function() {
+                node.emit("input",{});
+            }, this.repeat );
+        }
+
+        this.on("input", function(msg) {
+            imap.once('ready', function() {
+                node.status({fill:"blue",shape:"dot",text:"fetching"});
+                var pay = {};
+                imap.openBox('INBOX', true, function(err, box) {
+                    if (box.messages.total > 0) {
+                        var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)','TEXT'] });
+                        f.on('message', function(msg, seqno) {
+                            node.log('message: #'+ seqno);
+                            var prefix = '(#' + seqno + ') ';
+                            msg.on('body', function(stream, info) {
+                                var buffer = '';
+                                stream.on('data', function(chunk) {
+                                    buffer += chunk.toString('utf8');
+                                });
+                                stream.on('end', function() {
+                                    if (info.which !== 'TEXT') {
+                                        pay.from = Imap.parseHeader(buffer).from[0];
+                                        pay.topic = Imap.parseHeader(buffer).subject[0];
+                                        pay.date = Imap.parseHeader(buffer).date[0];
+                                    } else {
+                                        var parts = buffer.split("Content-Type");
+                                        for (var p = 0; p < parts.length; p++) {
+                                            if (parts[p].indexOf("text/plain") >= 0) {
+                                                pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim();
+                                            }
+                                            if (parts[p].indexOf("text/html") >= 0) {
+                                                pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim();
+                                            }
+                                        }
+                                        //pay.body = buffer;
+                                    }
+                                });
+                            });
+                            msg.on('end', function() {
+                                //node.log('Finished: '+prefix);
+                            });
+                        });
+                        f.on('error', function(err) {
+                            node.warn('fetch error: ' + err);
+                            node.status({fill:"red",shape:"ring",text:"fetch error"});
+                        });
+                        f.on('end', function() {
+                            if (JSON.stringify(pay) !== oldmail) {
+                                node.send(pay);
+                                oldmail = JSON.stringify(pay);
+                                node.log('received new email: '+pay.topic);
+                            }
+                            else { node.log('duplicate not sent: '+pay.topic); }
+                            //node.status({fill:"green",shape:"dot",text:"ok"});
+                            node.status({});
+                            imap.end();
+                        });
+                    }
+                    else {
+                        node.log("you have achieved inbox zero");
+                        //node.status({fill:"green",shape:"dot",text:"ok"});
+                        node.status({});
+                        imap.end();
+                    }
+                });
+            });
+            node.status({fill:"grey",shape:"dot",text:"connecting"});
+            imap.connect();
+        });
+
+        imap.on('error', function(err) {
+            node.log(err);
+            node.status({fill:"red",shape:"ring",text:"connect error"});
+        });
+
+        this.on("error", function(err) {
+            node.log("error: ",err);
+        });
+
+        this.on("close", function() {
+            if (this.interval_id != null) {
+                clearInterval(this.interval_id);
+            }
+            if (imap) { imap.destroy(); }
+        });
+
+        node.emit("input",{});
+    }
+    RED.nodes.registerType("e-mail in",EmailInNode,{
+        credentials: {
+            userid: {type:"text"},
+            password: {type: "password"},
+            global: { type:"boolean"}
+        }
+    });
+}
diff --git a/dgbuilder/core_nodes/social/91-irc.html b/dgbuilder/core_nodes/social/91-irc.html
new file mode 100644 (file)
index 0000000..1111237
--- /dev/null
@@ -0,0 +1,206 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="irc in">
+    <div class="form-row">
+        <label for="node-input-ircserver"><i class="fa fa-globe"></i> IRC Server</label>
+        <input type="text" id="node-input-ircserver">
+    </div>
+    <div class="form-row">
+        <label for="node-input-channel"><i class="fa fa-random"></i> Channel</label>
+        <input type="text" id="node-input-channel" placeholder="#nodered">
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">The channel to join must start with a # (as per normal irc rules...)<br/>
+    You may join multiple channels by comma separating a list - #chan1,#chan2,etc.</div>
+</script>
+
+<script type="text/x-red" data-help-name="irc in">
+    <p>Connects to a channel on an IRC server.</p>
+    <p>You may join multiple channels by comma separating a list - #chan1,#chan2,#etc.</p>
+    <p>Any messages on that channel will appear on the <code>msg.payload</code> at the output,
+    while <code>msg.topic</code> will contain who it is from.
+    <code>msg.to</code> contains either the name of the channel or PRIV in the case of a pm.</p>
+    <p>The second output provides a <code>msg.payload</code> that has any status messages such as joins, parts, kicks etc.</p>
+    <p>The type of the status message is set as <code>msg.payload.type</code>.</p>
+    <p>The possible status types are: <br />
+    <table border="1" cellpadding="1" cellspacing="1">
+    <thead>
+        <tr>
+            <th scope="col">Type</th>
+            <th scope="col">Description</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr>
+            <td>message</td>
+            <td>message is sent into the channel</td>
+        </tr>
+        <tr>
+            <td>pm</td>
+            <td>private message to the bot</td>
+        </tr>
+        <tr>
+            <td>join</td>
+            <td>a user joined the channel (also triggered when the bot joins a channel)</td>
+        </tr>
+        <tr>
+            <td>invite</td>
+            <td>the bot is being invited to a channel</td>
+        </tr>
+        <tr>
+            <td>part</td>
+            <td>a user leaves a channel</td>
+        </tr>
+        <tr>
+            <td>quit</td>
+            <td>a user quits a channel</td>
+        </tr>
+        <tr>
+            <td>kick</td>
+            <td>a user is kicked from a channel</td>
+        </tr>
+        <tr>
+            <td>names</td>
+            <td>retrieves the list of users when the bot joins a channel</td>
+        </tr>
+    </tbody>
+</table>
+</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('irc in',{
+        category: 'social-input',
+        defaults: {
+            name: {value:""},
+            ircserver: {type:"irc-server", required:true},
+            channel: {value:"",required:true,validate:RED.validators.regex(/^#/)}
+        },
+        color:"Silver",
+        inputs:0,
+        outputs:2,
+        icon: "hash.png",
+        label: function() {
+            var ircNode = RED.nodes.node(this.ircserver);
+            return this.name || (ircNode ? ircNode.label() : "irc");
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if ((this.ircserver !== undefined) && (this.ircserver !== "")) {
+                this.channel = this.channel || RED.nodes.node(this.ircserver).channel;
+                $("#node-input-channel").val(this.channel);
+            }
+            else { this.channel = this.channel; }
+            $("#node-input-channel").val(this.channel);
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="irc out">
+    <div class="form-row">
+        <label for="node-input-ircserver"><i class="fa fa-globe"></i> IRC Server</label>
+        <input type="text" id="node-input-ircserver">
+    </div>
+    <div class="form-row">
+        <label for="node-input-channel"><i class="fa fa-random"></i> Channel</label>
+        <input type="text" id="node-input-channel" placeholder="#nodered">
+    </div>
+    <div class="form-row">
+        <label for="node-input-sendObject"><i class="fa fa-arrows"></i> Action</label>
+        <select type="text" id="node-input-sendObject" style="display: inline-block; vertical-align: middle; width:70%;">
+            <option value="pay">Send payload to channel(s)</option>
+            <option value="true">Use msg.topic to set nickname or channel(s)</option>
+            <option value="false">Send complete msg object to channel(s)</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">The channel to join must start with a # (as per normal irc rules...)<br/>
+    Sending the complete object will stringify the whole msg object before sending.</div>
+</script>
+
+<script type="text/x-red" data-help-name="irc out">
+    <p>Sends messages to a channel on an IRC server</p>
+    <p>You can send just the <code>msg.payload</code>, or the complete <code>msg</code> object to the selected channel,
+    or you can select to use <code>msg.topic</code> to send the <code>msg.payload</code> to a specific user (private message) or channel.</p>
+    <p>If multiple output channels are listed (eg. #chan1,#chan2), then the message will be sent to all of them.</p>
+    <p><b>Note:</b> you can only send to channels you have previously joined so they MUST be specified in the node - even if you then decide to use a subset in msg.topic</p>
+    <p>You may send RAW commands using <code>msg.raw</code> - This must contain an array of parameters - eg. <pre>["privmsg","#nodered","Hello world"]</pre></p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('irc out',{
+        category: 'social-output',
+        defaults: {
+            name: {value:""},
+            sendObject: {value:"pay", required:true},
+            ircserver: {type:"irc-server", required:true},
+            channel: {value:"",required:true,validate:RED.validators.regex(/^#/)}
+        },
+        color:"Silver",
+        inputs:1,
+        outputs:0,
+        icon: "hash.png",
+        align: "right",
+        label: function() {
+            return this.name || (this.ircserver ? RED.nodes.node(this.ircserver).label() : "irc");
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            if ((this.ircserver !== undefined) && (this.ircserver !== "")) {
+                this.channel = this.channel || RED.nodes.node(this.ircserver).channel;
+                $("#node-input-channel").val(this.channel);
+            }
+            else { this.channel = this.channel; }
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="irc-server">
+    <div class="form-row">
+        <label for="node-config-input-server"><i class="fa fa-globe"></i> IRC Server</label>
+        <input type="text" id="node-config-input-server" placeholder="irc.freenode.net">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-nickname"><i class="fa fa-user"></i> Nickname</label>
+        <input type="text" id="node-config-input-nickname" placeholder="joe123">
+    </div>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('irc-server',{
+        category: 'config',
+        defaults: {
+            server: {value:"",required:true},
+            nickname: {value:"",required:true}
+        },
+        label: function() {
+            return this.server;
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/social/91-irc.js b/dgbuilder/core_nodes/social/91-irc.js
new file mode 100644 (file)
index 0000000..c520e44
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var irc = require("irc");
+
+    // The Server Definition - this opens (and closes) the connection
+    function IRCServerNode(n) {
+        RED.nodes.createNode(this,n);
+        this.server = n.server;
+        this.channel = n.channel;
+        this.nickname = n.nickname;
+        this.lastseen = 0;
+        this.ircclient = null;
+        this.on("close", function() {
+            if (this.ircclient != null) {
+                this.ircclient.removeAllListeners();
+                this.ircclient.disconnect();
+            }
+        });
+    }
+    RED.nodes.registerType("irc-server",IRCServerNode);
+
+
+    // The Input Node
+    function IrcInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.ircserver = n.ircserver;
+        this.serverConfig = RED.nodes.getNode(this.ircserver);
+        this.channel = n.channel || this.serverConfig.channel;
+        var node = this;
+        if (node.serverConfig.ircclient === null) {
+            node.log("Connecting to "+node.serverConfig.server);
+            node.status({fill:"grey",shape:"dot",text:"connecting"});
+            node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname,{autoConnect:false,retryDelay:20000});
+            node.serverConfig.ircclient.setMaxListeners(0);
+            node.serverConfig.ircclient.addListener('error', function(message) {
+                node.log(JSON.stringify(message));
+            });
+            node.serverConfig.ircclient.addListener('netError', function(message) {
+                node.log(JSON.stringify("NET "+message));
+                node.serverConfig.lastseen = Date.now();
+            });
+            node.serverConfig.ircclient.addListener('connect', function() {
+                node.serverConfig.lastseen = Date.now();
+            });
+            node.serverConfig.ircclient.addListener('ping', function(server) {
+                node.serverConfig.lastseen = Date.now();
+                //node.log("PING "+JSON.stringify(server));
+            });
+            node.recon = setInterval( function() {
+                //console.log("CHK ",(Date.now()-node.serverConfig.lastseen)/1000);
+                if ((Date.now()-node.serverConfig.lastseen) > 300000) {     // if more than 5 mins since last seen
+                    node.ircclient.send.apply(node.ircclient,["TIME"]);     // request time to check link
+                }
+                if ((Date.now()-node.serverConfig.lastseen) > 400000) {     // If more than 6.5 mins
+                    node.serverConfig.ircclient.disconnect();
+                    node.serverConfig.ircclient.connect();
+                    node.log("reconnect");                                  // then retry
+                }
+                node.ircclient.send.apply(node.ircclient,["TIME"]); // request time to check link
+            }, 60000); // check every 1 min
+        }
+        else { node.status({text:""}); }
+        node.ircclient = node.serverConfig.ircclient;
+
+        node.ircclient.addListener('registered', function(message) {
+            //node.log(node.ircclient.nick+" ONLINE");
+            node.status({fill:"yellow",shape:"dot",text:"connected"});
+            node.ircclient.join( node.channel, function(data) {
+                // node.log(data+" JOINED "+node.channel);
+                node.status({fill:"green",shape:"dot",text:"joined"});
+            });
+        });
+        node.ircclient.addListener('message', function (from, to, message) {
+            //node.log(from + ' => ' + to + ' : ' + message);
+            if (~node.channel.toLowerCase().indexOf(to.toLowerCase())) {
+                var msg = { "topic":from, "from":from, "to":to, "payload":message };
+                node.send([msg,null]);
+            }
+            //else { console.log(node.channel,to); }
+        });
+        node.ircclient.addListener('pm', function(from, message) {
+            //node.log("PM => "+from + ': ' + message);
+            var msg = { "topic":from, "from":from, "to":"PRIV", "payload":message };
+            node.send([msg,null]);
+        });
+        node.ircclient.addListener('join', function(channel, who) {
+            var msg = { "payload": { "type":"join", "who":who, "channel":channel } };
+            node.send([null,msg]);
+            //node.log(who+' has joined '+channel);
+        });
+        node.ircclient.addListener('invite', function(channel, from, message) {
+            var msg = { "payload": { "type":"invite", "who":from, "channel":channel, "message":message } };
+            node.send([null,msg]);
+            //node.log(from+' sent invite to '+channel+': '+message);
+        });
+        node.ircclient.addListener('part', function(channel, who, reason) {
+            var msg = { "payload": { "type":"part", "who":who, "channel":channel, "reason":reason } };
+            node.send([null,msg]);
+            //node.log(who+' has left '+channel+': '+reason);
+        });
+        node.ircclient.addListener('quit', function(nick, reason, channels, message) {
+            var msg = { "payload": { "type":"quit", "who":nick, "channel":channels, "reason":reason } };
+            node.send([null,msg]);
+            //node.log(nick+' has quit '+channels+': '+reason);
+        });
+        node.ircclient.addListener('kick', function(channel, who, by, reason) {
+            var msg = { "payload": { "type":"kick", "who":who, "channel":channel, "by":by, "reason":reason } };
+            node.send([null,msg]);
+            //node.log(who+' was kicked from '+channel+' by '+by+': '+reason);
+        });
+        node.ircclient.addListener('names', function (channel, nicks) {
+            var msg = { "payload": { "type": "names", "channel": channel, "names": nicks} };
+            node.send([null, msg]);
+        });
+        node.ircclient.addListener('raw', function (message) { // any message means we are alive
+            node.serverConfig.lastseen = Date.now();
+        });
+        node.on("close", function() {
+            node.ircclient.removeAllListeners();
+            if (node.recon) { clearInterval(node.recon); }
+        });
+    }
+    RED.nodes.registerType("irc in",IrcInNode);
+
+
+    // The Output Node
+    function IrcOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.sendFlag = n.sendObject;
+        this.ircserver = n.ircserver;
+        this.serverConfig = RED.nodes.getNode(this.ircserver);
+        this.channel = n.channel || this.serverConfig.channel;
+        var node = this;
+        if (node.serverConfig.ircclient === null) {
+            node.log("connecting to "+node.serverConfig.server);
+            node.status({fill:"grey",shape:"dot",text:"connecting"});
+            node.serverConfig.ircclient = new irc.Client(node.serverConfig.server, node.serverConfig.nickname,{autoConnect:false,retryDelay:20000});
+            node.serverConfig.ircclient.setMaxListeners(0);
+            node.serverConfig.ircclient.addListener('error', function(message) {
+                node.log(JSON.stringify(message));
+            });
+            node.serverConfig.ircclient.addListener('netError', function(message) {
+                node.log(JSON.stringify("NET "+message));
+                node.serverConfig.lastseen = Date.now();
+            });
+            node.serverConfig.ircclient.addListener('connect', function() {
+                node.serverConfig.lastseen = Date.now();
+            });
+            node.serverConfig.ircclient.addListener('ping', function(server) {
+                node.serverConfig.lastseen = Date.now();
+                //node.log("PING "+JSON.stringify(server));
+            });
+            node.serverConfig.ircclient.addListener('raw', function (message) { // any message received means we are alive
+                if (message.commandType === "reply") { node.serverConfig.lastseen = Date.now(); }
+            });
+            node.recon = setInterval( function() {
+                //console.log("CHK ",(Date.now()-node.serverConfig.lastseen)/1000);
+                if ((Date.now()-node.serverConfig.lastseen) > 300000) {     // if more than 5 mins since last seen
+                    node.ircclient.send.apply(node.ircclient,["TIME"]);     // request time to check link
+                }
+                if ((Date.now()-node.serverConfig.lastseen) > 400000) {     // If more than 6.5 mins
+                    node.serverConfig.ircclient.disconnect();
+                    node.serverConfig.ircclient.connect();
+                    node.log("reconnect");                                  // then retry
+                }
+                node.ircclient.send.apply(node.ircclient,["TIME"]); // request time to check link
+            }, 60000); // check every 1 min
+            node.serverConfig.ircclient.connect();
+        }
+        else { node.status({text:""}); }
+        node.ircclient = node.serverConfig.ircclient;
+
+        node.ircclient.addListener('registered', function(message) {
+            node.log(node.ircclient.nick+" ONLINE");
+            node.status({fill:"yellow",shape:"dot",text:"connected"});
+            node.ircclient.join( node.channel, function(data) {
+                //node.log(data+" JOINED "+node.channel);
+                node.status({fill:"green",shape:"dot",text:"joined"});
+            });
+        });
+
+        node.on("input", function(msg) {
+            if (Object.prototype.toString.call( msg.raw ) === '[object Array]') {
+                node.log("RAW command:"+msg.raw);
+                node.ircclient.send.apply(node.ircclient,msg.raw);
+                //var m = msg.raw;
+                //for (var i = 0; i < 10; i++) {
+                    //if (typeof m[i] !== "string") { m[i] = ""; }
+                    //m[i] = m[i].replace(/"/g, "");
+                //}
+                //node.log("RAW command:"+m);
+                //node.ircclient.send(m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9]);
+            }
+            else {
+                if (msg._topic) { delete msg._topic; }
+                var ch = node.channel.split(","); // split on , so we can send to multiple
+                if (node.sendFlag == "true") { // override channels with msg.topic
+                    if ((msg.hasOwnProperty('topic'))&&(typeof msg.topic === "string")) {
+                        ch = msg.topic.split(","); // split on , so we can send to multiple
+                    }
+                    else { node.warn("msg.topic not set"); }
+                }
+                for (var c = 0; c < ch.length; c++) {
+                    if (node.sendFlag == "false") { // send whole message object to each channel
+                        node.ircclient.say(ch[c], JSON.stringify(msg));
+                    }
+                    else { // send just the payload to each channel
+                        if (typeof msg.payload === "object") { msg.payload = JSON.stringify(msg.payload); }
+                        node.ircclient.say(ch[c], msg.payload);
+                    }
+                }
+            }
+        });
+
+        node.on("close", function() {
+            node.ircclient.removeAllListeners();
+            if (node.recon) { clearInterval(node.recon); }
+        });
+    }
+    RED.nodes.registerType("irc out",IrcOutNode);
+}
diff --git a/dgbuilder/core_nodes/storage/28-tail.html b/dgbuilder/core_nodes/storage/28-tail.html
new file mode 100644 (file)
index 0000000..c094d06
--- /dev/null
@@ -0,0 +1,58 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="tail">
+    <div class="form-row node-input-filename">
+         <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label>
+         <input type="text" id="node-input-filename" placeholder="Filename">
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-split" style="width: 70%;">Split lines if we see \n ?</label>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <!-- <div class="form-tips">WON'T work on Windows.</div> -->
+</script>
+
+<script type="text/x-red" data-help-name="tail">
+    <p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p>
+    <p>This won't work on Windows filesystems, as it relies on the tail -F command.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('tail',{
+        category: 'storage-input',
+        defaults: {
+            name: {value:""},
+            split: {value:false},
+            filename: {value:"",required:true}
+        },
+        color:"BurlyWood",
+        inputs:0,
+        outputs:1,
+        icon: "file.png",
+        label: function() {
+            return this.name||this.filename;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/storage/28-tail.js b/dgbuilder/core_nodes/storage/28-tail.js
new file mode 100644 (file)
index 0000000..89c7a63
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var spawn = require('child_process').spawn;
+    var plat = require('os').platform();
+
+    if (plat.match(/^win/)) {
+        throw "Info : Currently not supported on Windows.";
+    }
+
+    function TailNode(n) {
+        RED.nodes.createNode(this,n);
+
+        this.filename = n.filename;
+        this.split = n.split;
+        var node = this;
+
+        var err = "";
+        // TODO: rewrite to use node-tail
+        var tail = spawn("tail", ["-F", "-n", "0", this.filename]);
+        tail.stdout.on("data", function (data) {
+            if (node.split) {
+                // TODO: allow customisation of the line break - as we do elsewhere
+                var strings = data.toString().split("\n");
+                for (var s in strings) {
+                    //TODO: should we really filter blanks? Is that expected?
+                    if (strings[s] !== "") {
+                        node.send({
+                            topic: node.filename,
+                            payload: strings[s]
+                        });
+                    }
+                }
+            }
+            else {
+                var msg = {
+                    topic:node.filename,
+                    payload: data.toString()
+                };
+                node.send(msg);
+            }
+        });
+
+        tail.stderr.on("data", function(data) {
+            node.warn(data.toString());
+        });
+
+        this.on("close", function() {
+            if (tail) { tail.kill(); }
+        });
+    }
+
+    RED.nodes.registerType("tail",TailNode);
+}
diff --git a/dgbuilder/core_nodes/storage/50-file.html b/dgbuilder/core_nodes/storage/50-file.html
new file mode 100644 (file)
index 0000000..5113a17
--- /dev/null
@@ -0,0 +1,110 @@
+<!--
+  Copyright 2013, 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="file">
+    <div class="form-row node-input-filename">
+         <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label>
+         <input type="text" id="node-input-filename" placeholder="Filename">
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-appendNewline" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-appendNewline" style="width: 70%;">Append newline ?</label>
+    </div>
+    <div class="form-row">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-overwriteFile" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-overwriteFile" style="width: 70%;">Overwrite complete file ?</label>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="file">
+    <p>Writes <b>msg.payload</b> to the file specified, e.g. to create a log.</p>
+    <p>The filename can be overridden by the <b>msg.filename</b> property of the incoming message.</p>
+    <p>A newline is added to every message. But this can be turned off if required, for example, to allow binary files to be written.</p>
+    <p>The default behaviour is to append to the file. This can be changed to overwrite the file each time, for example if you want to output a "static" web page or report.</p>
+    <p>If a <b>msg.delete</b> property exists then the file will be deleted instead.</p>
+</script>
+
+<script type="text/x-red" data-template-name="file in">
+    <div class="form-row">
+         <label for="node-input-filename"><i class="fa fa-file"></i> Filename</label>
+         <input type="text" id="node-input-filename" placeholder="Filename">
+    </div>
+    <div class="form-row">
+        <label for="node-input-format"><i class="fa fa-sign-out"></i> Output as</label>
+        <select id="node-input-format">
+            <option value="utf8">a utf8 string</option>
+            <option value="">a Buffer</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="file in">
+    <p>Reads the specified file and sends the content as <b>msg.payload</b>, and the filename as <b>msg.filename</b>.</p>
+    <p>The filename can be overridden by the <b>msg.filename</b> property of the incoming message.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('file',{
+        category: 'storage-output',
+        defaults: {
+            name: {value:""},
+            filename: {value:""},
+            appendNewline: {value:true},
+            overwriteFile: {value:false}
+        },
+        color:"BurlyWood",
+        inputs:1,
+        outputs:0,
+        icon: "file.png",
+        align: "right",
+        label: function() {
+            return this.name||this.filename;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+
+    RED.nodes.registerType('file in',{
+        category: 'storage-input',
+        defaults: {
+            name: {value:""},
+            filename: {value:""},
+            format: {value:"utf8"},
+        },
+        color:"BurlyWood",
+        inputs:1,
+        outputs:1,
+        icon: "file.png",
+        label: function() {
+            return this.name||this.filename;
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        }
+    });
+
+</script>
diff --git a/dgbuilder/core_nodes/storage/50-file.js b/dgbuilder/core_nodes/storage/50-file.js
new file mode 100644 (file)
index 0000000..d6cc441
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var fs = require("fs");
+
+    function FileNode(n) {
+        RED.nodes.createNode(this,n);
+        this.filename = n.filename || "";
+        this.appendNewline = n.appendNewline;
+        this.overwriteFile = n.overwriteFile;
+        var node = this;
+        this.on("input",function(msg) {
+            var filename = msg.filename || this.filename;
+            if (filename === "") {
+                node.warn('No filename specified');
+            } else if (msg.hasOwnProperty('delete')) {
+                fs.unlink(filename, function (err) {
+                    if (err) { node.warn('Failed to delete file : '+err); }
+                    //console.log('Deleted file",filename);
+                });
+            } else if (typeof msg.payload != "undefined") {
+                var data = msg.payload;
+                if (typeof data === "object") {
+                    if (!Buffer.isBuffer(data)) {
+                        data = JSON.stringify(data);
+                    }
+                }
+                if (typeof data === "boolean") { data = data.toString(); }
+                if ((this.appendNewline)&&(!Buffer.isBuffer(data))) { data += "\n"; }
+                if (this.overwriteFile) {
+                    // using "binary" not {encoding:"binary"} to be 0.8 compatible for a while
+                    fs.writeFile(filename, data, "binary", function (err) {
+                        if (err) { node.warn('Failed to write to file : '+err); }
+                        //console.log('Message written to file',filename);
+                    });
+                }
+                else {
+                    // using "binary" not {encoding:"binary"} to be 0.8 compatible for a while
+                    fs.appendFile(filename, data, "binary", function (err) {
+                        if (err) { node.warn('Failed to append to file : '+err); }
+                        //console.log('Message appended to file',filename);
+                    });
+                }
+            }
+        });
+    }
+    RED.nodes.registerType("file",FileNode);
+
+    function FileInNode(n) {
+        RED.nodes.createNode(this,n);
+
+        this.filename = n.filename || "";
+        this.format = n.format;
+        var node = this;
+        var options = {};
+        if (this.format) {
+            options['encoding'] = this.format;
+        }
+        this.on("input",function(msg) {
+            var filename = msg.filename || this.filename;
+            if (filename === "") {
+                node.warn('No filename specified');
+            } else {
+                fs.readFile(filename,options,function(err,data) {
+                    if (err) {
+                        node.warn(err);
+                        msg.error = err;
+                    } else {
+                        msg.filename = filename;
+                        msg.payload = data;
+                    }
+                    node.send(msg);
+                });
+            }
+        });
+    }
+    RED.nodes.registerType("file in",FileInNode);
+}
diff --git a/dgbuilder/core_nodes/storage/65-redisout.html b/dgbuilder/core_nodes/storage/65-redisout.html
new file mode 100644 (file)
index 0000000..9000dfd
--- /dev/null
@@ -0,0 +1,105 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="redis out">
+    <div class="form-row node-input-hostname">
+        <label for="node-input-hostname"><i class="fa fa-bookmark"></i> Host</label>
+        <input class="input-append-left" type="text" id="node-input-hostname" placeholder="127.0.0.1" style="width: 40%;" ><button id="node-input-hostname-lookup" class="btn input-append-right"><span class="caret"></span></button>
+        <label for="node-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
+        <input type="text" id="node-input-port" placeholder="6379" style="width:45px">
+    </div>
+    <div class="form-row">
+        <label for="node-input-key"><i class="fa fa-key"></i> Key</label>
+        <input type="text" id="node-input-key" placeholder="Redis Key">
+    </div>
+    <div class="form-row">
+        <label for="node-input-type"><i class="fa fa-th"></i> Type</label>
+        <select type="text" id="node-input-structtype" style="width: 150px;">
+        <option value="string">String</option>
+        <option value="hash">Hash</option>
+        <option value="set">Set</option>
+        <option value="list">List</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips">
+        If key is blank, the topic will be used as the key.<br>
+        If type is hash, payload should be field=value.
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="redis out">
+    <p>A Redis output node. Options include Hash, Set, List and String.</p>
+    <p>To run this you need a local Redis server running. For details see <a href="http://redis.io/" target="_new">the Redis site</a>.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('redis out',{
+        category: 'storage-output',
+        color:"#ffaaaa",
+        defaults: {
+            hostname: { value:"127.0.0.1",required:true},
+            port: { value: 6379,required:true},
+            name: {value:""},
+            key: {value:""},
+            structtype: {value:"",required:true}
+        },
+        inputs:1,
+        outputs:0,
+        icon: "redis.png",
+        align: "right",
+        label: function() {
+            return this.name||this.key+" ("+this.structtype+")";
+        },
+        oneditprepare: function() {
+            var availableServers = [];
+            var matchedServers = {};
+            RED.nodes.eachNode(function(node) {
+                if (node.type == "redis out" && node.hostname && node.port && !matchedServers[node.hostname+":"+node.port]) {
+                    var label = node.hostname+":"+node.port;
+                    matchedServers[label] = true;
+                    availableServers.push({
+                        label:label,
+                        value:node.hostname,
+                        port:node.port
+                    });
+                }
+            });
+            $( "#node-input-hostname" ).autocomplete({
+                minLength: 0,
+                source: availableServers,
+                select: function( event, ui ) {
+                    $("#node-input-port").val(ui.item.port);
+                }
+            });
+            var tt = this;
+            tt._acOpen = false;
+            $( "#node-input-hostname" ).on( "autocompleteclose", function( event, ui ) { tt._acOpen = false;} );
+            $( "#node-input-hostname-lookup" ).click(function(e) {
+                if (tt._acOpen) {
+                    $( "#node-input-hostname" ).autocomplete( "close");
+                } else {
+                    $( "#node-input-hostname" ).autocomplete( "search", "" );
+                }
+                tt._acOpen = !tt._acOpen;
+                e.preventDefault();
+            });
+        }
+    });
+</script>
diff --git a/dgbuilder/core_nodes/storage/65-redisout.js b/dgbuilder/core_nodes/storage/65-redisout.js
new file mode 100644 (file)
index 0000000..907e2a5
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var redis = require("redis");
+
+    var hashFieldRE = /^([^=]+)=(.*)$/;
+
+    var redisConnectionPool = function() {
+        var connections = {};
+        var obj = {
+            get: function(host,port) {
+                var id = host+":"+port;
+                if (!connections[id]) {
+                    connections[id] = redis.createClient(port,host);
+                    connections[id].on("error",function(err) {
+                            util.log("[redis] "+err);
+                    });
+                    connections[id].on("connect",function() {
+                            util.log("[redis] connected to "+host+":"+port);
+                    });
+                    connections[id]._id = id;
+                    connections[id]._nodeCount = 0;
+                }
+                connections[id]._nodeCount += 1;
+                return connections[id];
+            },
+            close: function(connection) {
+                connection._nodeCount -= 1;
+                if (connection._nodeCount === 0) {
+                    if (connection) {
+                        clearTimeout(connection.retry_timer);
+                        connection.end();
+                    }
+                    delete connections[connection._id];
+                }
+            }
+        };
+        return obj;
+    }();
+
+
+    function RedisOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.port = n.port||"6379";
+        this.hostname = n.hostname||"127.0.0.1";
+        this.key = n.key;
+        this.structtype = n.structtype;
+
+        this.client = redisConnectionPool.get(this.hostname,this.port);
+
+        if (this.client.connected) {
+            this.status({fill:"green",shape:"dot",text:"connected"});
+        } else {
+            this.status({fill:"red",shape:"ring",text:"disconnected"},true);
+        }
+
+        var node = this;
+        this.client.on("end", function() {
+            node.status({fill:"red",shape:"ring",text:"disconnected"});
+        });
+        this.client.on("connect", function() {
+            node.status({fill:"green",shape:"dot",text:"connected"});
+        });
+
+        this.on("input", function(msg) {
+            var k = this.key || msg.topic;
+            if (k) {
+                if (this.structtype == "string") {
+                    this.client.set(k,RED.util.ensureString(msg.payload));
+                } else if (this.structtype == "hash") {
+                    var r = hashFieldRE.exec(msg.payload);
+                    if (r) {
+                        this.client.hset(k,r[1],r[2]);
+                    } else {
+                        this.warn("Invalid payload for redis hash");
+                    }
+                } else if (this.structtype == "set") {
+                    this.client.sadd(k,msg.payload);
+                } else if (this.structtype == "list") {
+                    this.client.rpush(k,msg.payload);
+                }
+            } else {
+                this.warn("No key or topic set");
+            }
+        });
+        this.on("close", function() {
+            redisConnectionPool.close(node.client);
+        });
+    }
+    RED.nodes.registerType("redis out",RedisOutNode);
+}
diff --git a/dgbuilder/core_nodes/storage/66-mongodb.html b/dgbuilder/core_nodes/storage/66-mongodb.html
new file mode 100644 (file)
index 0000000..81c5638
--- /dev/null
@@ -0,0 +1,231 @@
+<!--
+  Copyright 2013,2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="mongodb">
+    <div class="form-row">
+        <label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label>
+        <input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
+        <label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
+        <input type="text" id="node-config-input-port" placeholder="27017" style="width:45px">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-db"><i class="fa fa-database"></i> Database</label>
+        <input type="text" id="node-config-input-db" placeholder="test">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-user"><i class="fa fa-user"></i> Username</label>
+        <input type="text" id="node-config-input-user">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
+        <input type="password" id="node-config-input-password">
+    </div>
+    <div class="form-row">
+        <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-config-input-name" placeholder="Name">
+    </div>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('mongodb', {
+        category: 'config',
+        color: "rgb(218, 196, 180)",
+        defaults: {
+            hostname: {value: "127.0.0.1", required: true},
+            port: {value: 27017, required: true},
+            db: {value: "", required: true},
+            name: {value: ""}
+        },
+        credentials: {
+            user: {type: "text"},
+            password: {type: "password"}
+        },
+        label: function() {
+            return this.name || this.hostname + ":" + this.port + "/" + this.db;
+        }
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="mongodb out">
+    <div class="form-row">
+        <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label>
+        <input type="text" id="node-input-mongodb">
+    </div>
+    <div class="form-row">
+        <label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label>
+        <input type="text" id="node-input-collection" placeholder="collection">
+    </div>
+    <div class="form-row">
+        <label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label>
+        <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;">
+            <option value="store">save</option>
+            <option value="insert">insert</option>
+            <option value="update">update</option>
+            <option value="delete">remove</option>
+        </select>
+    </div>
+    <div class="form-row node-input-payonly">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-payonly" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-payonly" style="width: 70%;">Only store msg.payload object</label>
+    </div>
+    <div class="form-row node-input-upsert">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-upsert" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;">
+        <label for="node-input-upsert" style="width: 70%;">Create a new document if no match found</label>
+    </div>
+    <div class="form-row node-input-multi">
+        <label>&nbsp;</label>
+        <input type="checkbox" id="node-input-multi" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;;">
+        <label for="node-input-multi" style="width: 70%;">Update all matching documents</label>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="mongodb out">
+    <p>A simple MongoDB output node. Can save, insert, update and remove objects from a chosen collection.</p>
+    <p>Save will update an existing object or insert a new object if one does not already exist.</p>
+    <p>Insert will insert a new object.</p>
+    <p>Save and insert either store <b>msg</b> or <b>msg.payload</b>.</p>
+    <p>Update will modify an existing object or objects. The query to select objects to update uses <b>msg.query</b> and the update to the element uses <b>msg.payload</b>.</p>
+    <p>Update can add a object if it does not exist or update multiple objects.</p>
+    <p>Remove will remove objects that match the query passed in on <b>msg.payload</b>. A blank query will delete <i>all of the objects</i> in the collection.</p>
+    <p>You can either set the collection method in the node config or on <b>msg.collection</b>. Setting it in the node will override <b>msg.collection</b>.</p>
+    <p>By default MongoDB creates an <i>_id</i> property as the primary key - so repeated injections of the same <b>msg</b> will result in many database entries.</p>
+    <p>If this is NOT the desired behaviour - ie. you want repeated entries to overwrite, then you must set the <b>msg._id</b> property to be a constant by the use of a previous function node.</p>
+    <p>This could be a unique constant or you could create one based on some other msg property.</p>
+    <p>Currently we do not limit or cap the collection size at all... this may well change.</p>
+</script>
+
+<script type="text/javascript">
+
+    function oneditprepare() {
+        $("#node-input-operation").change(function () {
+            var id = $("#node-input-operation option:selected").val();
+
+            if (id === "update") {
+                $(".node-input-payonly").hide();
+                $(".node-input-upsert, .node-input-multi").show();
+            } else if (id === "delete") {
+                $(".node-input-payonly, .node-input-upsert, .node-input-multi").hide();
+            } else {
+                $(".node-input-payonly").show();
+                $(".node-input-upsert, .node-input-multi").hide();
+            }
+        });
+
+        $("#node-input-collection").change(function () {
+            if($("#node-input-collection").val() === "") {
+                $("#node-warning").show();
+            } else {
+                $("#node-warning").hide();
+            }
+        });
+    }
+
+    RED.nodes.registerType('mongodb out', {
+        category: 'storage-output',
+        color: "rgb(218, 196, 180)",
+        defaults: {
+            mongodb: {type: "mongodb", required: true},
+            name: {value: ""},
+            collection: {value: ""},
+            payonly: {value: false},
+            upsert: {value: false},
+            multi: {value: false},
+            operation: {value: "store"}
+        },
+        inputs: 1,
+        outputs: 0,
+        icon: "mongodb.png",
+        align: "right",
+        label: function() {
+            var mongoNode = RED.nodes.node(this.mongodb);
+            return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb");
+        },
+        labelStyle: function() {
+            return this.name ? "node_label_italic" : "";
+        },
+        oneditprepare: oneditprepare
+    });
+</script>
+
+
+<script type="text/x-red" data-template-name="mongodb in">
+    <div class="form-row">
+        <label for="node-input-mongodb"><i class="fa fa-bookmark"></i> Server</label>
+        <input type="text" id="node-input-mongodb">
+    </div>
+    <div class="form-row">
+        <label for="node-input-collection"><i class="fa fa-briefcase"></i> Collection</label>
+        <input type="text" id="node-input-collection" placeholder="collection">
+    </div>
+    <div class="form-row">
+        <label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label>
+        <select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;">
+            <option value="find">find</option>
+            <option value="count">count</option>
+            <option value="aggregate">aggregate</option>
+        </select>
+    </div>
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-tips" id="node-warning" style="display: none"><b> Tip:</b> If no collection is set, ensure <b>msg.collection</b> will contain the collection name
+    </div>
+</script>
+
+<script type="text/x-red" data-help-name="mongodb in">
+    <p>Calls a MongoDB collection method based on the selected operator.</p>
+    <p>Find queries a collection using the <b>msg.payload</b> as the query statement as per the .find() function. Optionally, you may also (via a function) set a <b>msg.projection</b> object to constrain the returned fields, a <b>msg.sort</b> object and a <b>msg.limit</b> object.</p>
+    <p>Count returns a count of the number of documents in a collection or matching a query using the <b>msg.payload</b> as the query statement.</p>
+    <p>Aggregate provides access to the aggregation pipeline using the <b>msg.payload</b> as the pipeline array.</p>
+    <p>You can override the collection the method is performed on by setting <b>msg.collection</b> to the desired collection name.</p>
+    <p>See the <a href="http://docs.mongodb.org/manual/reference/method/db.collection.find/" target="new"><i>MongoDB collection methods docs</i></a> for examples.</p>
+    <p>The result is returned in <b>msg.payload</b>.</p>
+</script>
+
+<script type="text/javascript">
+
+    RED.nodes.registerType('mongodb in', {
+        category: 'storage-input',
+        color: "rgb(218, 196, 180)",
+        defaults: {
+            mongodb: {type: "mongodb", required: true},
+            name: {value: ""},
+            collection: {value: ""},
+            operation: {value: "find"}
+        },
+        inputs: 1,
+        outputs: 1,
+        icon: "mongodb.png",
+        label: function() {
+            var mongoNode = RED.nodes.node(this.mongodb);
+            return this.name || (mongoNode ? mongoNode.label() + " " + this.collection: "mongodb");
+        },
+        labelStyle: function() {
+            return this.name ? "node_label_italic" : "";
+        },
+        oneditprepare: oneditprepare
+    });
+</script>
diff --git a/dgbuilder/core_nodes/storage/66-mongodb.js b/dgbuilder/core_nodes/storage/66-mongodb.js
new file mode 100644 (file)
index 0000000..3a71407
--- /dev/null
@@ -0,0 +1,233 @@
+/**
+ * Copyright 2013,2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var mongo = require('mongodb');
+    var MongoClient = mongo.MongoClient;
+
+    function MongoNode(n) {
+        RED.nodes.createNode(this,n);
+        this.hostname = n.hostname;
+        this.port = n.port;
+        this.db = n.db;
+        this.name = n.name;
+
+        var url = "mongodb://";
+        if (this.credentials && this.credentials.user && this.credentials.password) {
+            url += this.credentials.user+":"+this.credentials.password+"@";
+        }
+        url += this.hostname+":"+this.port+"/"+this.db;
+
+        this.url = url;
+    }
+
+    RED.nodes.registerType("mongodb",MongoNode,{
+        credentials: {
+            user: {type:"text"},
+            password: {type: "password"}
+        }
+    });
+
+    function ensureValidSelectorObject(selector) {
+        if (selector != null && (typeof selector != 'object' || Buffer.isBuffer(selector))) {
+            return {};
+        }
+        return selector;
+    }
+        
+    
+    function MongoOutNode(n) {
+        RED.nodes.createNode(this,n);
+        this.collection = n.collection;
+        this.mongodb = n.mongodb;
+        this.payonly = n.payonly || false;
+        this.upsert = n.upsert || false;
+        this.multi = n.multi || false;
+        this.operation = n.operation;
+        this.mongoConfig = RED.nodes.getNode(this.mongodb);
+
+        if (this.mongoConfig) {
+            var node = this;
+            MongoClient.connect(this.mongoConfig.url, function(err, db) {
+                if (err) {
+                    node.error(err);
+                } else {
+                    node.clientDb = db;
+                    var coll;
+                    if (node.collection) {
+                        coll = db.collection(node.collection);
+                    }
+                    node.on("input",function(msg) {
+                        if (!coll) {
+                            if (msg.collection) {
+                                coll = db.collection(msg.collection);
+                            } else {
+                                node.error("No collection defined");
+                                return;
+                            }
+                        }
+                        delete msg._topic;
+                        delete msg.collection;
+                        if (node.operation === "store") {
+                            if (node.payonly) {
+                                if (typeof msg.payload !== "object") {
+                                    msg.payload = {"payload": msg.payload};
+                                }
+                                coll.save(msg.payload,function(err, item) {
+                                    if (err) {
+                                        node.error(err);
+                                    }
+                                });
+                            } else {
+                                coll.save(msg,function(err, item) {
+                                    if (err) {
+                                        node.error(err);
+                                    }
+                                });
+                            }
+                        } else if (node.operation === "insert") {
+                            if (node.payonly) {
+                                if (typeof msg.payload !== "object") {
+                                    msg.payload = {"payload": msg.payload};
+                                }
+                                coll.insert(msg.payload, function(err, item) {
+                                    if (err) {
+                                        node.error(err);
+                                    }
+                                });
+                            } else {
+                                coll.insert(msg, function(err,item) {
+                                    if (err) {
+                                        node.error(err);
+                                    }
+                                });
+                            }
+                        } else if (node.operation === "update") {
+                            if (typeof msg.payload !== "object") {
+                                msg.payload = {"payload": msg.payload};
+                            }
+                            var query = msg.query || {};
+                            var payload = msg.payload || {};
+                            var options = {
+                                upsert: node.upsert,
+                                multi: node.multi
+                            };
+
+                            coll.update(query, payload, options, function(err, item) {
+                                if (err) {
+                                    node.error(err + " " + payload);
+                                }
+                            });
+                        } else if (node.operation === "delete") {
+                            coll.remove(msg.payload, function(err, items) {
+                                if (err) {
+                                    node.error(err);
+                                }
+                            });
+                        }
+                    });
+                }
+            });
+        } else {
+            this.error("missing mongodb configuration");
+        }
+
+        this.on("close", function() {
+            if (this.clientDb) {
+                this.clientDb.close();
+            }
+        });
+    }
+    RED.nodes.registerType("mongodb out",MongoOutNode);
+
+    function MongoInNode(n) {
+        RED.nodes.createNode(this,n);
+        this.collection = n.collection;
+        this.mongodb = n.mongodb;
+        this.operation = n.operation || "find";
+        this.mongoConfig = RED.nodes.getNode(this.mongodb);
+
+        if (this.mongoConfig) {
+            var node = this;
+            MongoClient.connect(this.mongoConfig.url, function(err,db) {
+                if (err) {
+                    node.error(err);
+                } else {
+                    node.clientDb = db;
+                    var coll;
+                    if (node.collection) {
+                        coll = db.collection(node.collection);
+                    }
+                    node.on("input", function(msg) {
+                        if (!coll) {
+                            if (msg.collection) {
+                                coll = db.collection(msg.collection);
+                            } else {
+                                node.error("No collection defined");
+                                return;
+                            }
+                        }
+                        if (node.operation === "find") {
+                            msg.projection = msg.projection || {};
+                            var selector = ensureValidSelectorObject(msg.payload);
+                            coll.find(selector,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) {
+                                if (err) {
+                                    node.error(err);
+                                } else {
+                                    msg.payload = items;
+                                    delete msg.projection;
+                                    delete msg.sort;
+                                    delete msg.limit;
+                                    node.send(msg);
+                                }
+                            });
+                        } else if (node.operation === "count") {
+                            var selector = ensureValidSelectorObject(msg.payload);
+                            coll.count(selector, function(err, count) {
+                                if (err) {
+                                    node.error(err);
+                                } else {
+                                    msg.payload = count;
+                                    node.send(msg);
+                                }
+                            });
+                        } else if (node.operation === "aggregate") {
+                            msg.payload = (msg.payload instanceof Array) ? msg.payload : [];
+                            coll.aggregate(msg.payload, function(err, result) {
+                                if (err) {
+                                    node.error(err);
+                                } else {
+                                    msg.payload = result;
+                                    node.send(msg);
+                                }
+                            });
+                        }
+                    });
+                }
+            });
+        } else {
+            this.error("missing mongodb configuration");
+        }
+
+        this.on("close", function() {
+            if (this.clientDb) {
+                this.clientDb.close();
+            }
+        });
+    }
+    RED.nodes.registerType("mongodb in",MongoInNode);
+}
diff --git a/dgbuilder/createReleaseDir.sh b/dgbuilder/createReleaseDir.sh
new file mode 100755 (executable)
index 0000000..00d185f
--- /dev/null
@@ -0,0 +1,129 @@
+#!/bin/bash
+export PATH=$PATH:.
+appDir=$(pwd)
+if [ "$#" != 3 -a "$#" != 4 ]
+then
+       echo "Usage $0 releaseDir  loginId emailAddress [gitLocalRepository]"
+       echo "Note: Specify the gitLocalRepository path if you would want to be able to import flows from your local git repository"
+       exit
+fi 
+if [ ! -e "releases" ]
+then
+       mkdir releases
+fi
+releaseDir="$1"
+name="Release $releaseDir"
+loginId="$2"
+emailid="$3"
+dbHost="dbhost"
+dbPort="3306"
+dbName="sdnctl"
+dbUser="sdnctl"
+dbPassword="gamma"
+gitLocalRepository="$4"
+
+lastPort=$(find "releases/" -name "customSettings.js" |xargs grep uiPort|cut -d: -f2|sed -e s/,//|sort|tail -1)
+echo $lastPort|grep uiPort >/dev/null 2>&1
+if [ "$?" == "0" ]
+then
+lastPort=$(find "releases/" -name "customSettings.js" |xargs grep uiPort|cut -d: -f3|sed -e s/,//|sort|tail -1)
+fi
+#echo $lastPort
+if [ "${lastPort}" == "" ]
+then
+       lastPort="3099"
+fi
+let nextPort=$(expr $lastPort+1)
+#echo $nextPort
+if [ ! -e "releases/$releaseDir" ]
+then
+mkdir releases/$releaseDir
+cd releases/$releaseDir
+mkdir flows
+mkdir flows/shared
+mkdir flows/shared/backups
+mkdir html
+mkdir xml
+mkdir lib
+mkdir lib/flows
+mkdir logs
+mkdir conf
+mkdir codecloud
+customSettingsFile="customSettings.js"
+if [ ! -e "./$customSettingsFile" ]
+then
+       echo "module.exports = {" >$customSettingsFile
+       echo "          'name' : '$name'," >>$customSettingsFile
+       echo "          'emailAddress' :'$emailid'," >>$customSettingsFile
+       echo "          'uiPort' :$nextPort," >>$customSettingsFile
+       echo "          'mqttReconnectTime': 15000," >>$customSettingsFile
+       echo "          'serialReconnectTime' : 15000,"  >>$customSettingsFile
+       echo "          'debugMaxLength': 1000," >>$customSettingsFile
+       echo "          'htmlPath': 'releases/$releaseDir/html/'," >>$customSettingsFile
+       echo "          'xmlPath': 'releases/$releaseDir/xml/'," >>$customSettingsFile
+       echo "          'flowFile' : 'releases/$releaseDir/flows/flows.json'," >>$customSettingsFile
+       echo "          'sharedDir': 'releases/$releaseDir/flows/shared'," >>$customSettingsFile
+       echo "          'userDir' : 'releases/$releaseDir'," >>$customSettingsFile
+       echo "          'httpAuth': {user:'$loginId',pass:'cc03e747a6afbbcbf8be7668acfebee5'}," >>$customSettingsFile
+       echo "          'dbHost': '$dbHost'," >>$customSettingsFile
+       echo "          'dbPort': '$dbPort'," >>$customSettingsFile
+       echo "          'dbName': '$dbName'," >>$customSettingsFile
+       echo "          'dbUser': '$dbUser'," >>$customSettingsFile
+       echo "          'dbPassword': '$dbPassword'," >>$customSettingsFile
+       echo "          'gitLocalRepository': '$gitLocalRepository'" >>$customSettingsFile
+       echo "          }" >>$customSettingsFile
+fi
+       #echo "Created custom settings  file $customSettingsFile"
+       echo "Done ....."
+else
+       echo "ERROR:customSettings file $customSettingsFile already exists for $releaseDir"     
+       exit
+fi
+#echo "Content of custom settings file"
+#echo "============================================================================"
+#      cat $customSettingsFile
+#echo "============================================================================"
+svclogicPropFile="./conf/svclogic.properties"
+if [ ! -d "${appDir}/yangFiles" ]
+then
+       mkdir -p "${appDir}/yangFiles" 
+fi
+if [ ! -d "${appDir}/generatedJS" ]
+then
+       mkdir -p "${appDir}/generatedJS" 
+fi
+
+if [ ! -e "./$svclogicPropFile" ]
+then
+       echo "org.onap.ccsdk.sli.dbtype=jdbc" >$svclogicPropFile
+       echo "org.onap.ccsdk.sli.jdbc.url=jdbc:mysql://dbhost:3306/sdnctl" >>$svclogicPropFile
+       echo "org.onap.ccsdk.sli.jdbc.database=sdnctl" >>$svclogicPropFile
+       echo "org.onap.ccsdk.sli.jdbc.user=sdnctl" >>$svclogicPropFile
+       echo "org.onap.ccsdk.sli.jdbc.password=gamma" >>$svclogicPropFile
+fi
+if [ ! -e "${appDir}/flowShareUsers.js" ]
+then
+       echo "module.exports = {\"flowShareUsers\":" >${appDir}/flowShareUsers.js
+        echo " [" >>${appDir}/flowShareUsers.js
+        echo " ]" >>${appDir}/flowShareUsers.js
+        echo "}" >>${appDir}/flowShareUsers.js
+fi
+grep "$releaseDir" ${appDir}/flowShareUsers.js >/dev/null 2>&1
+if [ "$?" != "0" ]
+then
+       num_of_lines=$(cat ${appDir}/flowShareUsers.js|wc -l)
+       if [ $num_of_lines -gt 4 ]
+       then
+               content=$(head -n -2 ${appDir}/flowShareUsers.js)
+               echo "${content}," > ${appDir}/flowShareUsers.js
+       else
+               content=$(head -n -2 ${appDir}/flowShareUsers.js)
+               echo "$content" > ${appDir}/flowShareUsers.js
+       fi
+       echo "  {" >> ${appDir}/flowShareUsers.js
+       echo "          \"name\" : \"$name\"," >> ${appDir}/flowShareUsers.js
+       echo "          \"rootDir\" : \"$releaseDir\"" >> ${appDir}/flowShareUsers.js
+       echo "  }" >> ${appDir}/flowShareUsers.js
+       echo "  ]" >> ${appDir}/flowShareUsers.js
+       echo "}" >> ${appDir}/flowShareUsers.js
+fi
diff --git a/dgbuilder/flowShareUsers.js b/dgbuilder/flowShareUsers.js
new file mode 100644 (file)
index 0000000..d132116
--- /dev/null
@@ -0,0 +1,16 @@
+module.exports = {"flowShareUsers":
+       [
+       {
+          "name" : "Release sdnc1.0",
+          "rootDir" : "sdnc1.0"
+       },
+       {
+          "name" : "Release sdnc2.0",
+          "rootDir" : "sdnc2.0"
+       },
+       {
+          "name" : "Release sdnc3.0",
+          "rootDir" : "sdnc3.0"
+       }
+       ]
+}
diff --git a/dgbuilder/generatedJS/.gitignore b/dgbuilder/generatedJS/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/dgbuilder/git_scripts/gitcheckout b/dgbuilder/git_scripts/gitcheckout
new file mode 100755 (executable)
index 0000000..ca01dd7
--- /dev/null
@@ -0,0 +1,17 @@
+if [ "$#" != "2" ]
+then
+       echo "Usage $0 gitLocalRepositoryDir branch"
+       exit
+fi
+branch=$2
+localGitRepository=$1
+cd $localGitRepository
+if [ -e "$localGitRepository" ]
+then
+       git checkout $branch
+       echo
+       echo -n  "Now on Branch:"
+       git rev-parse --abbrev-ref HEAD
+else
+       echo Git Local repository not set
+fi
diff --git a/dgbuilder/git_scripts/gitckout b/dgbuilder/git_scripts/gitckout
new file mode 100755 (executable)
index 0000000..3db9db8
--- /dev/null
@@ -0,0 +1,15 @@
+if [ "$#" != "2" ]
+then
+       echo "Usage $0 commitId full_path_to_the_source_file"
+       exit
+fi
+fileName=$(basename $2)
+dirName=$(dirname $2)
+commitId=$1
+cd $dirName
+if [ -e "$2" ]
+then
+       rm $2 2>/dev/null
+fi
+git checkout $commitId $fileName
+cat $fileName
diff --git a/dgbuilder/git_scripts/gitcurbranch b/dgbuilder/git_scripts/gitcurbranch
new file mode 100755 (executable)
index 0000000..5a82e48
--- /dev/null
@@ -0,0 +1,13 @@
+if [ "$#" != "1" ]
+then
+       echo "Usage $0 gitLocalRepositoryDir"
+       exit
+fi
+localGitRepository=$1
+cd $localGitRepository
+if [ -e "$localGitRepository" ]
+then
+       git rev-parse --abbrev-ref HEAD
+else
+       echo Git Local repository not set
+fi
diff --git a/dgbuilder/git_scripts/gitlog b/dgbuilder/git_scripts/gitlog
new file mode 100755 (executable)
index 0000000..fd8cd37
--- /dev/null
@@ -0,0 +1,18 @@
+if [ "$#" != "1" ]
+then
+       echo "Usage $0 full_path_to_the_source_file"
+       exit
+fi
+fileName=$(basename $1)
+dirName=$(dirname $1)
+cd $dirName
+glog=$(git log --pretty=format:'%H %cD %an %s' -n 25 ${fileName}|awk ' ORS=" "{print \
+"\n{\n" \
+"\"commit\": \"" $1 "\",\n" \
+"\"date\": \""$2 " "$3" "$4" "$5 " "$6 "\",\n" \
+"\"author\": \"" $8 ", "$9 "\",\n" \
+"\"comment\": \""} { s = ""; for (i = 10; i <= NF; i++) s = s $i " "; print s } { print  "\"\n},"}')
+echo "["
+update_glog=$(echo $glog|sed -e 's/,$//g')
+echo $update_glog
+echo "]"
diff --git a/dgbuilder/git_scripts/gitpull b/dgbuilder/git_scripts/gitpull
new file mode 100755 (executable)
index 0000000..8d475ad
--- /dev/null
@@ -0,0 +1,7 @@
+if [ "$#" != "1" ]
+then
+       echo "Usage $0 full_path_to_local_repository"
+       exit
+fi
+cd $1
+git pull
diff --git a/dgbuilder/git_scripts/gitstatus b/dgbuilder/git_scripts/gitstatus
new file mode 100755 (executable)
index 0000000..9b24ea7
--- /dev/null
@@ -0,0 +1,7 @@
+if [ "$#" != "1" ]
+then
+       echo "Usage $0 full_path_to_local_repository"
+       exit
+fi
+cd $1
+git status
diff --git a/dgbuilder/nodes/99-sample.html.demo b/dgbuilder/nodes/99-sample.html.demo
new file mode 100644 (file)
index 0000000..4dcc8ba
--- /dev/null
@@ -0,0 +1,79 @@
+<!--
+  Copyright 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- Sample html file that corresponds to the 99-sample.js file              -->
+<!-- This creates and configures the onscreen elements of the node           -->
+
+<!-- If you use this as a template, update the copyright with your own name. -->
+
+<!-- First, the content of the edit dialog is defined.                       -->
+
+<script type="text/x-red" data-template-name="sample">
+   <!-- data-template-name identifies the node type this is for              -->
+
+   <!-- Each of the following divs creates a field in the edit dialog.       -->
+   <!-- Generally, there should be an input for each property of the node.   -->
+   <!-- The for and id attributes identify the corresponding property        -->
+   <!-- (with the 'node-input-' prefix).                                     -->
+   <!-- The available icon classes are defined Twitter Bootstrap glyphicons  -->
+    <div class="form-row">
+        <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
+        <input type="text" id="node-input-topic" placeholder="Topic">
+    </div>
+
+    <br/>
+    <!-- By convention, most nodes have a 'name' property. The following div -->
+    <!-- provides the necessary field. Should always be the last option      -->
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+</script>
+
+
+<!-- Next, some simple help text is provided for the node.                   -->
+<script type="text/x-red" data-help-name="sample">
+   <!-- data-help-name identifies the node type this help is for             -->
+   <!-- This content appears in the Info sidebar when a node is selected     -->
+   <!-- The first <p> is used as the pop-up tool tip when hovering over a    -->
+   <!-- node in the palette.                                                 -->
+   <p>Simple sample input node. Just sends a single message when it starts up.
+   This is not very useful.</p>
+   <p>Outputs an object called <b>msg</b> containing <b>msg.topic</b> and
+   <b>msg.payload</b>. msg.payload is a String.</p>
+</script>
+
+<!-- Finally, the node type is registered along with all of its properties   -->
+<!-- The example below shows a small subset of the properties that can be set-->
+<script type="text/javascript">
+    RED.nodes.registerType('sample',{
+        category: 'input',      // the palette category
+        defaults: {             // defines the editable properties of the node
+            name: {value:""},   //  along with default values.
+            topic: {value:"", required:true}
+        },
+        inputs:1,               // set the number of inputs - only 0 or 1
+        outputs:1,              // set the number of outputs - 0 to n
+        // set the icon (held in icons dir below where you save the node)
+        icon: "myicon.png",     // saved in  icons/myicon.png
+        label: function() {     // sets the default label contents
+            return this.name||this.topic||"sample";
+        },
+        labelStyle: function() { // sets the class to apply to the label
+            return this.name?"node_label_italic":"";
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/99-sample.js.demo b/dgbuilder/nodes/99-sample.js.demo
new file mode 100644 (file)
index 0000000..f926945
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+// If you use this as a template, update the copyright with your own name.
+
+// Sample Node-RED node file
+
+
+module.exports = function(RED) {
+    "use strict";
+    // require any external libraries we may need....
+    //var foo = require("foo-library");
+
+    // The main node definition - most things happen in here
+    function SampleNode(n) {
+        // Create a RED node
+        RED.nodes.createNode(this,n);
+
+        // Store local copies of the node configuration (as defined in the .html)
+        this.topic = n.topic;
+
+        // Do whatever you need to do in here - declare callbacks etc
+        // Note: this sample doesn't do anything much - it will only send
+        // this message once at startup...
+        // Look at other real nodes for some better ideas of what to do....
+        var msg = {};
+        msg.topic = this.topic;
+        msg.payload = "Hello world !"
+
+        // send out the message to the rest of the workspace.
+        this.send(msg);
+
+        // respond to inputs....
+        this.on('input', function (msg) {
+            node.warn("I saw a payload: "+msg.payload);
+            // in this example just send it straight on... should process it here really
+            this.send(msg);
+        });
+
+        this.on("close", function() {
+            // Called when the node is shutdown - eg on redeploy.
+            // Allows ports to be closed, connections dropped etc.
+            // eg: this.client.disconnect();
+        });
+    }
+
+    // Register the node by name. This must be called before overriding any of the
+    // Node functions.
+    RED.nodes.registerType("sample",SampleNode);
+
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/block.html b/dgbuilder/nodes/dge/dgelogic/block.html
new file mode 100644 (file)
index 0000000..fadf8a8
--- /dev/null
@@ -0,0 +1,223 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<script type="text/x-red" data-template-name="block">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+       <div> 
+       <table border='0' width='100%' style='cellspacing:5px;'>
+       <tr>
+       <td>
+        <input type="checkbox" id="node-input-atomic-chkBox" onclick=updateXml()>
+        <input type="hidden" id="node-input-atomic" value="">
+       </td>
+       <td>
+       <span style="font-size:.8em;">Atomic</span>
+       </td>
+       </tr>
+       </table>
+       </div>
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a>
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="block">
+       <p>A block node.</p>
+       <p>Name can be anything.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+       <div class="section">
+<h3><a name="Flow_Control"></a>Flow Control</h3>
+<div class="section">
+<h4><a name="Block_node"></a>Block node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>block</b> node is used to executes a set of nodes. </p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>atomic</b></td>
+<td align="left">if <i>true</i>, then if a node returns failure, subsequent nodes will not be executed and nodes already executed will be backed out.</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;block&gt;
+  &lt;record plugin=&quot;org.onap.ccsdk.sli.core.sli.recording.FileRecorder&quot;&gt;
+    &lt;parameter name=&quot;file&quot; value=&quot;/tmp/sample_r1.log&quot; /&gt;
+    &lt;parameter name=&quot;field1&quot; value=&quot;__TIMESTAMP__&quot;/&gt;
+    &lt;parameter name=&quot;field2&quot; value=&quot;RESERVED&quot;/&gt;
+    &lt;parameter name=&quot;field3&quot; value=&quot;$asePort.uni_circuit_id&quot;/&gt;
+  &lt;/record&gt;
+  &lt;return status=&quot;success&quot;&gt;
+    &lt;parameter name=&quot;uni-circuit-id&quot; value=&quot;$asePort.uni_circuit_id&quot; /&gt;
+  &lt;/return&gt;
+&lt;/block&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+ var blockXmlEditor ; 
+    RED.nodes.registerType('block',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"block"},
+            xml: {value:"<block>\n"},
+           atomic: {value:"false"},    
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+               var atomic = $( "#node-input-atomic").val();
+               if(atomic == "true"){
+                       $('#node-input-atomic-chkBox').prop('checked', true);
+               }else{
+                       $('#node-input-atomic-chkBox').prop('checked', false);
+               }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+               blockXmlEditor=that.editor;
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               //console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+               
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+               delete blockXmlEditor;
+        }
+    });
+function updateXml(){
+       if($("#node-input-atomic-chkBox").is(':checked')){
+               $("#node-input-name").val("block : atomic");
+               $("#node-input-atomic").val("true");
+               //alert($("#node-input-xml-editor div.textview div.textviewContent").text());
+               var xmlStr = blockXmlEditor.getText();
+               var re = new RegExp("<block[^<]+");
+               xmlStr=xmlStr.replace(re,"<block atomic='true'>");
+               //$("#node-input-xml-editor div.textview div.textviewContent").text(xmlStr);
+               blockXmlEditor.setText(xmlStr);
+               //console.log("block xmlStr:" + xmlStr);
+       }else{
+               $("#node-input-name").val("block");
+               $("#node-input-atomic").val("false");
+               var xmlStr = blockXmlEditor.getText();
+               var re = new RegExp("<block[^<]+");
+               xmlStr=xmlStr.replace(re,"<block>");
+               blockXmlEditor.setText(xmlStr);
+               //$("#node-input-xml-editor div.textview div.textviewContent").text(xmlStr);
+               //console.log("block xmlStr:" + xmlStr);
+       }
+}
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/block.js b/dgbuilder/nodes/dge/dgelogic/block.js
new file mode 100644 (file)
index 0000000..4414d86
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function block(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("block",block);
+    // RED.library.register("block");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/breakNode.html b/dgbuilder/nodes/dge/dgelogic/breakNode.html
new file mode 100644 (file)
index 0000000..e3edef9
--- /dev/null
@@ -0,0 +1,161 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="break">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a>
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="break">
+       <p>A break node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Break_node"></a>Break node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>break</b> node works like a break in any programming language. So you can break out of a for loop.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<p>Not applicable. The <b>break</b> node does not have attributes.</p></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Not applicable. The <b>break</b> node does not have attributes.</p> </div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Not applicable. The <b>break</b> node has no outcomes.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;break&gt;
+</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('break',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"break"},
+            xml: {value:"<break>\n"},
+           comments:{value:""} 
+        },
+        inputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/breakNode.js b/dgbuilder/nodes/dge/dgelogic/breakNode.js
new file mode 100644 (file)
index 0000000..9b0b1b0
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function breakNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("break",breakNode);
+    // RED.library.register("block");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/call.html b/dgbuilder/nodes/dge/dgelogic/call.html
new file mode 100644 (file)
index 0000000..0e49e26
--- /dev/null
@@ -0,0 +1,183 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="call">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a>
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="call">
+       <p>A call node.</p>
+       <p>Name can be anything.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Call_node"></a>Call node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>call</b> node is used to call another graph</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>module</b></td>
+<td align="left">Module of directed graph to call. If unset, defaults to that of calling graph</td></tr>
+<tr class="b">
+<td align="center"><b>rpc</b></td>
+<td align="left">rpc of directed graph to call.</td></tr>
+<tr class="a">
+<td align="center"><b>version</b></td>
+<td align="left">version of graph to call, If unset, uses active version.</td></tr>
+<tr class="b">
+<td align="center"><b>mode</b></td>
+<td align="left">mode (sync/async) of graph to call. If unset, defaults to that of calling graph.</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Not applicable</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped"><caption> .</caption>
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Sub graph returned success</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Graph not found</td></tr>
+<tr class="a">
+<td align="center"><b>failure</b></td>
+<td align="left">Subgraph returned success</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;call rpc=&quot;svc-topology-reserve&quot; mode=&quot;sync&quot; /&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('call',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"call"},
+            xml: {value:"<call module='' rpc='' mode='sync' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("show Values clicked.");
+                               showValuesBox(that.editor,rpcValues);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/call.js b/dgbuilder/nodes/dge/dgelogic/call.js
new file mode 100644 (file)
index 0000000..3570e3d
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function call(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("call",call);
+    // RED.library.register("call");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/configure.html b/dgbuilder/nodes/dge/dgelogic/configure.html
new file mode 100644 (file)
index 0000000..7503b1f
--- /dev/null
@@ -0,0 +1,227 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="configure">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="configure">
+       <p>A configure node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+
+       <div class="section">
+<h3><a name="Device_Management"></a>Device Management</h3>
+<div class="section">
+<h4><a name="Configure_node"></a>Configure node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>configure</b> node is used to configure a device.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>activate</b></td>
+<td align="left">Activate device/interface, for devices that support a separate activation step.</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying criteria for item to configure</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Specific to device adaptor.</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Device successfully configured</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Element to be configured does not exist.</td></tr>
+<tr class="a">
+<td align="center"><b>not-ready</b></td>
+<td align="left">Element is not in a state where it can be configured/activated</td></tr>
+<tr class="b">
+<td align="center"><b>already-active</b></td>
+<td align="left">Attempt to activate element that is already active</td></tr>
+<tr class="a">
+<td align="center"><b>failure</b></td>
+<td align="left">Configure failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;configure adaptor=&quot;org.onap.ccsdk.sli.adaptor.emt.EmtAdaptor&quot;
+           key=&quot;$uni-circuit-id&quot; activate=&quot;true&quot;&gt;
+  &lt;parameter name=&quot;circuit.id&quot; value=&quot;$uni-circuit-id&quot; /&gt;
+  &lt;parameter name=&quot;subscriber.name&quot; value=&quot;$subscriber-name&quot; /&gt;
+  &lt;parameter name=&quot;emt.clli&quot; value=&quot;$edge-device-clli&quot; /&gt;
+  &lt;parameter name=&quot;port.tagging&quot; value=&quot;$port-tagging&quot; /&gt;
+  &lt;parameter name=&quot;port.mediaSpeed&quot; value=&quot;$media-speed&quot; /&gt;
+  &lt;parameter name=&quot;location.state&quot; value=&quot;$uni-location-state&quot; /&gt;
+  &lt;parameter name=&quot;location.city&quot; value=&quot;$uni-location-city&quot; /&gt;
+  &lt;parameter name=&quot;cosCategory&quot; value=&quot;$cos-category&quot; /&gt;
+  &lt;parameter name=&quot;gosProfile&quot; value=&quot;$gos-profile&quot; /&gt;
+  &lt;parameter name=&quot;lldp&quot; value=&quot;$asePort.resource-lldp&quot; /&gt;
+  &lt;parameter name=&quot;mtu&quot; value=&quot;$asePort.resource-mtu&quot; /&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+    &lt;block&gt;
+      &lt;record plugin=&quot;org.onap.ccsdk.sli.recording.FileRecorder&quot;&gt;
+        &lt;parameter name=&quot;file&quot; value=&quot;/tmp/sampler1.log&quot; /&gt;
+        &lt;parameter name=&quot;field1&quot; value=&quot;__TIMESTAMP__&quot;/&gt;
+        &lt;parameter name=&quot;field2&quot; value=&quot;ACTIVE&quot;/&gt;
+        &lt;parameter name=&quot;field3&quot; value=&quot;$uni-circuit-id&quot;/&gt;
+      &lt;/record&gt;
+      &lt;return status=&quot;success&quot;&gt;
+        &lt;parameter name=&quot;edge-device-clli&quot; value=&quot;$asePort.resource-emt-clli&quot; /&gt;
+      &lt;/return&gt;
+    &lt;/block&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;already-active&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1590&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Port already active&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;Other&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1542&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Activation failure&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+&lt;/configure&gt;</pre></div></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('configure',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"configure"},
+            xml: {value:"<configure adaptor='' key='' activate='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/configure.js b/dgbuilder/nodes/dge/dgelogic/configure.js
new file mode 100644 (file)
index 0000000..7345750
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function configure(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("configure",configure);
+    // RED.library.register("configure");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/delete.html b/dgbuilder/nodes/dge/dgelogic/delete.html
new file mode 100644 (file)
index 0000000..b4c7f52
--- /dev/null
@@ -0,0 +1,187 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="delete">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="delete">
+       <p>A delete node.</p>
+       <p>Name can be anything.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Delete_node"></a>Delete node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>delete</b> node is used to delete a resource from the local resource inventory.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to delete</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying key to delete</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Resource specified deleted successfully.</td></tr>
+<tr class="b">
+<td align="center"><i>failure</i>&gt;</td>
+<td align="left">Resource specified was not deleted</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;delete plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+        resource=&quot;ase-port&quot;
+        key=&quot;uni_circuit_id == $uni-circuit-id&quot;&gt;
+  &lt;outcome value=&quot;true&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;false&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/delete&gt;</pre></div></div></div>
+       
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('delete',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"delete"},
+            xml: {value:"<delete plugin='' resource='' key=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/delete.js b/dgbuilder/nodes/dge/dgelogic/delete.js
new file mode 100644 (file)
index 0000000..3773106
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function deleteNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("delete",deleteNode);
+    // RED.library.register("delete");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/execute.html b/dgbuilder/nodes/dge/dgelogic/execute.html
new file mode 100644 (file)
index 0000000..3d5fc6d
--- /dev/null
@@ -0,0 +1,197 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="execute">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="execute">
+       <p>A execute node.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+       <div class="section">
+<h3><a name="Java_Plugin_Support"></a>Java Plugin Support</h3>
+<div class="section">
+<h4><a name="Execute_node"></a>Execute node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>An <b>execute</b> node is used to execute Java code supplied as a plugin</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of plugin to be used</td></tr>
+<tr class="b">
+<td align="center"><b>method</b></td>
+<td align="left">Name of method in the plugin class to execute. Method must return void, and take 2 arguments: a Map (for parameters) and a SvcLogicContext (to allow plugin read/write access to context memory)</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Specific to plugin / method</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Device successfully configured</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Plugin class could not be loaded</td></tr>
+<tr class="a">
+<td align="center"><b>unsupported-method</b></td>
+<td align="left">Named method taking (Map, SvcLogicContext) could not be found</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Configure failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;execute plugin=&quot;org.onap.ccsdk.sli.plugin.HelloWorld&quot;
+           method=&quot;log&quot;&gt;
+  &lt;parameter name=&quot;message&quot; value=&quot;Hello, world!&quot; /&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+      &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;not-found&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1590&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Could not locate plugin&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;Other&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1542&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Internal error&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+&lt;/execute&gt;</pre></div></div></div></div>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('execute',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"execute"},
+            xml: {value:"<execute plugin='' method='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/execute.js b/dgbuilder/nodes/dge/dgelogic/execute.js
new file mode 100644 (file)
index 0000000..66265f9
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function execute(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("execute",execute);
+    // RED.library.register("configure");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/exists.html b/dgbuilder/nodes/dge/dgelogic/exists.html
new file mode 100644 (file)
index 0000000..001e8ca
--- /dev/null
@@ -0,0 +1,187 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="exists">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="exists">
+       <p>A exists node.</p>
+       <p>Name can be anything.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Exists_node"></a>Exists node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>An <b>exists</b> node is used to determine whether a particular instance of a resource exists. For example, this might be used to test whether a particular switch CLLI is provisioned.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to check</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying key to check for</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>true</b></td>
+<td align="left">Resource specified exists.</td></tr>
+<tr class="b">
+<td align="center"><b>false</b></td>
+<td align="left">Resource specified is unknown</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;exists plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+        resource=&quot;ase-port&quot;
+        key=&quot;uni_circuit_id == $uni-circuit-id&quot;&gt;
+  &lt;outcome value=&quot;true&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;false&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/exists&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('exists',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"exists"},
+            xml: {value:"<exists plugin='' resource='' key=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/exists.js b/dgbuilder/nodes/dge/dgelogic/exists.js
new file mode 100644 (file)
index 0000000..d4482af
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function exists(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("exists",exists);
+    // RED.library.register("exists");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/forNode.html b/dgbuilder/nodes/dge/dgelogic/forNode.html
new file mode 100644 (file)
index 0000000..c7327db
--- /dev/null
@@ -0,0 +1,172 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="for">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="for">
+       <p>A for node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>for</b> node provides a fixed iteration looping mechanism, similar to the Java for loop</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>index</b></td>
+<td align="left">index variable</td></tr>
+<tr class="b">
+<td align="center"><b>start</b></td>
+<td align="left">initial value</td></tr>
+<tr class="a">
+<td align="center"><b>end</b></td>
+<td align="left">maximum value</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Not applicable.</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Not applicable. The <b>status</b> node has no outcomes.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;for index=&quot;i&quot; start=&quot;0&quot; end=&quot;$network.num-segments&quot;&gt;
+  &lt;set&gt;
+    &lt;parameter name=&quot;$vlanlist&quot; value=&quot;$network.segment[i].provider-segmentation-id&quot;/&gt;
+  &lt;/set&gt;
+&lt;/for&gt;</pre></div></div></div>   
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('for',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"for"},
+            xml: {value:"<for index='' start='' end='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/forNode.js b/dgbuilder/nodes/dge/dgelogic/forNode.js
new file mode 100644 (file)
index 0000000..567da85
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function forNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("for",forNode);
+    // RED.library.register("for");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/get-resource.html b/dgbuilder/nodes/dge/dgelogic/get-resource.html
new file mode 100644 (file)
index 0000000..b3b6558
--- /dev/null
@@ -0,0 +1,192 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="get-resource">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="get-resource">
+       <p>A get-resource node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Get-resource_node"></a>Get-resource node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>get-resource</b> node is used to retrieve information about a particular resource and make it available to other nodes in the service logic tree. For example, this might be used to retrieve information about a particular uni-port.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to retrieve</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying criteria for retrieval</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Resource successfully released</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Resource referenced does not exist</td></tr>
+<tr class="a">
+<td align="center"><b>failure</b></td>
+<td align="left">Resource release failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;get-resource plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+              resource=&quot;ase-port&quot;
+              key=&quot;uni_circuit_id == $uni-circuit-id&quot;&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;not-found&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;failure&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/get-resource&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('get-resource',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"get-resource"},
+            xml: {value:"<get-resource plugin='' resource='' key='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/get-resource.js b/dgbuilder/nodes/dge/dgelogic/get-resource.js
new file mode 100644 (file)
index 0000000..597e021
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function getResource(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("get-resource",getResource);
+    // RED.library.register("get-resource");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/is-available.html b/dgbuilder/nodes/dge/dgelogic/is-available.html
new file mode 100644 (file)
index 0000000..8bc45ef
--- /dev/null
@@ -0,0 +1,186 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="is-available">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="is-available">
+       <p>A is-available node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Is-available_node"></a>Is-available node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>An <b>is-available</b> node is used to determine whether a particular type of resource is available. For example, this might be used to test whether any ports are available for assignment on a particular switch.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to check</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying key to check for</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>true</b></td>
+<td align="left">Resource requested is available</td></tr>
+<tr class="b">
+<td align="center"><b>false</b></td>
+<td align="left">Resource requested is not available</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;is-available plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+              resource=&quot;ase-port&quot;
+              key=&quot;resource-emt-clli == $edge-device-clli and speed &gt;= $uni-cir-value&quot;&gt;
+  &lt;outcome value=&quot;true&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;false&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/is-available&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('is-available',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"is-available"},
+            xml: {value:"<is-available plugin='' resource='' key=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/is-available.js b/dgbuilder/nodes/dge/dgelogic/is-available.js
new file mode 100644 (file)
index 0000000..93f23f4
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function isAvailable(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("is-available",isAvailable);
+    // RED.library.register("is-available");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/notify.html b/dgbuilder/nodes/dge/dgelogic/notify.html
new file mode 100644 (file)
index 0000000..e5bc24b
--- /dev/null
@@ -0,0 +1,195 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="notify">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="notify">
+       <p>A notify node.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+<!--
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>An <b>notify</b> node is used to execute Java code supplied as a plugin</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of plugin to be used</td></tr>
+<tr class="b">
+<td align="center"><b>method</b></td>
+<td align="left">Name of method in the plugin class to execute. Method must return void, and take 2 arguments: a Map (for parameters) and a SvcLogicContext (to allow plugin read/write access to context memory)</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Specific to plugin / method</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Device successfully configured</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Plugin class could not be loaded</td></tr>
+<tr class="a">
+<td align="center"><b>unsupported-method</b></td>
+<td align="left">Named method taking (Map, SvcLogicContext) could not be found</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Configure failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;notify plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+            resource=&quot;network-connection&quot; action=&quot;DELETE&quot; &gt;
+  &lt;parameter name=&quot;message&quot; value=&quot;Hello, world!&quot; /&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+      &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;not-found&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1590&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Could not locate plugin&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;Other&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1542&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Internal error&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+&lt;/notify&gt;</pre></div></div></div></div>
+-->
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('notify',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"notify"},
+            xml: {value:"<notify plugin='' resource='' action='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               //console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/notify.js b/dgbuilder/nodes/dge/dgelogic/notify.js
new file mode 100644 (file)
index 0000000..8b58e9e
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function notify(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("notify",notify);
+    // RED.library.register("configure");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/record.html b/dgbuilder/nodes/dge/dgelogic/record.html
new file mode 100644 (file)
index 0000000..3eb7a2e
--- /dev/null
@@ -0,0 +1,185 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="record">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="record">
+       <p>A record node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h3><a name="Recording"></a>Recording</h3>
+<div class="section">
+<h4><a name="Record_node"></a>Record node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>record</b> node is used to record an event. For example, this might be used to log provisioning events.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class to handle recording.</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Parameters will depend on the plugin being used. For the FileRecorder class, the parameters are as follows</p>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>file</b></td>
+<td align="left">The file to which the record should be written</td></tr>
+<tr class="b">
+<td align="center"><b>field1</b></td>
+<td align="left">First field to write. There will be <b>field</b> parameters for each field to write, from <b>field1</b> through <b>fieldN</b>. A special value __TIMESTAMP__ may be assigned to a field to insert the current timestamp</td></tr></table></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Record successfully written</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Record could not be successfully written</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;record plugin=&quot;org.onap.ccsdk.sli.core.sli.recording.FileRecorder&quot;&gt;
+  &lt;parameter name=&quot;file&quot; value=&quot;/tmp/sample_r1.log&quot; /&gt;
+  &lt;parameter name=&quot;field1&quot; value=&quot;__TIMESTAMP__&quot;/&gt;
+  &lt;parameter name=&quot;field2&quot; value=&quot;ACTIVE&quot;/&gt;
+  &lt;parameter name=&quot;field3&quot; value=&quot;$uni-circuit-id&quot;/&gt;
+&lt;/record&gt;</pre></div></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('record',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"record"},
+            xml: {value:"<record>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/record.js b/dgbuilder/nodes/dge/dgelogic/record.js
new file mode 100644 (file)
index 0000000..f29bf8f
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function record(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("record",record);
+    // RED.library.register("record");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/release.html b/dgbuilder/nodes/dge/dgelogic/release.html
new file mode 100644 (file)
index 0000000..044616a
--- /dev/null
@@ -0,0 +1,192 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="release">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="release">
+       <p>A release node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Release_node"></a>Release node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>release</b> node is used to mark a resource as no longer in use, and thus available for assignment.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to release</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying key to check of resource to release</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Resource successfully released</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Resource referenced does not exist</td></tr>
+<tr class="a">
+<td align="center"><b>failure</b></td>
+<td align="left">Resource release failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;release plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+         resource=&quot;ase-port&quot;
+         key=&quot;uni_circuit_id == $uni-circuit-id&quot;&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;not-found&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;failure&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/release&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('release',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"release"},
+            xml: {value:"<release plugin='' resource='' key='' >\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/release.js b/dgbuilder/nodes/dge/dgelogic/release.js
new file mode 100644 (file)
index 0000000..ff03fff
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function release(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("release",release);
+    // RED.library.register("release");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/reserve.html b/dgbuilder/nodes/dge/dgelogic/reserve.html
new file mode 100644 (file)
index 0000000..bcd3fcb
--- /dev/null
@@ -0,0 +1,189 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="reserve">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="reserve">
+       <p>A reserve node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Reserve_node"></a>Reserve node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>reserve</b> node is used to reserve a particular type of resource.. For example, this might be used to reserve a port on a particular switch.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to reserve</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying criteria for reservation</td></tr>
+<tr class="b">
+<td align="center"><b>select</b></td>
+<td align="left">String to specify, if <b>key</b> matches multiple entries, which entry should take precedence</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Resource requested was successfully reserved</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Resource requested was not successfully reserved</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;reserve plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+         resource=&quot;ase-port&quot;
+         key=&quot;resource-emt-clli == $edge-device-clli and speed &gt;= $uni-cir-value&quot;
+         select=&quot;min(speed)&quot;&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+    &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;failure&quot;&gt;
+    &lt;return status=&quot;failure&quot;/&gt;
+  &lt;/outcome&gt;
+&lt;/reserve&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('reserve',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"reserve"},
+            xml: {value:"<reserve plugin='' resource='' key='' select=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/reserve.js b/dgbuilder/nodes/dge/dgelogic/reserve.js
new file mode 100644 (file)
index 0000000..6aab1bd
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function reserve(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("reserve",reserve);
+    // RED.library.register("reserve");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/save.html b/dgbuilder/nodes/dge/dgelogic/save.html
new file mode 100644 (file)
index 0000000..6e02215
--- /dev/null
@@ -0,0 +1,189 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="save">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="save">
+       <p>A save node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Save_node"></a>Save node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>save</b> node is used to save information about a particular resource to persistent storage. For example, this might be used to save information about a particular uni-port.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of resource adaptor to be used</td></tr>
+<tr class="b">
+<td align="center"><b>resource</b></td>
+<td align="left">Type of resource to save</td></tr>
+<tr class="a">
+<td align="center"><b>key</b></td>
+<td align="left">SQL-like string specifying criteria for retrieval</td></tr>
+<tr class="b">
+<td align="center"><b>force</b></td>
+<td align="left">If &quot;true&quot;, save resource even if this resource is already stored in persistent storage</td></tr>
+<tr class="a">
+<td align="center"><b>pfx</b></td>
+<td align="left">Prefix to be prepended to variable names, when attributes are set in SvcLogicContext</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Values to save (columns) are specified as parameters, with each name corresponding to a column name and each value corresponding to the value to set.</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Resource successfully saved</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Resource save failed</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;save plugin=&quot;`$resource-plugin`&quot; resource=&quot;resourceName&quot;
+        key=&quot;keyName=value&quot;
+        pfx=&quot;requests.resourceName&quot;&gt;
+        &lt;parameter name=&quot;parameter1&quot;
+                value=&quot;`$parameterOneValue`&quot; /&gt;
+        &lt;parameter name=&quot;parameter2&quot; value=&quot;`$parameterparameterTwoValue`&quot; /&gt;
+&lt;/save&gt;</pre></div></div></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('save',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"save"},
+            xml: {value:"<save plugin='' resource='' key='' force='' pfx=''>\n<parameter name='' value='' />\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/save.js b/dgbuilder/nodes/dge/dgelogic/save.js
new file mode 100644 (file)
index 0000000..5771ae9
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function save(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("save",save);
+    // RED.library.register("save");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/set.html b/dgbuilder/nodes/dge/dgelogic/set.html
new file mode 100644 (file)
index 0000000..bcbcae3
--- /dev/null
@@ -0,0 +1,162 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="set">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="set">
+       <p>A set node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Set_node"></a>Set node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>set</b> node is used to set one or more values in the execution context</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<p>Not applicable. The <b>set</b> node does not have attributes.</p></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Values to be set are passed as parameters</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Not applicable. The <b>set</b> node has no outcomes.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;set&gt;
+  &lt;parameter name=&quot;vlan&quot; value=&quot;$network.provider-segmentation-id&quot; /&gt;
+&lt;/set&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('set',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"set"},
+            xml: {value:"<set>\n<parameter name='' value='' />\n"},
+           comments:{value:""} 
+        },
+        inputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/set.js b/dgbuilder/nodes/dge/dgelogic/set.js
new file mode 100644 (file)
index 0000000..9b93950
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function set(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("set",set);
+    // RED.library.register("set");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/switchNode.html b/dgbuilder/nodes/dge/dgelogic/switchNode.html
new file mode 100644 (file)
index 0000000..35c9fe6
--- /dev/null
@@ -0,0 +1,232 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="switchNode">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="switchNode">
+       <p>A switch node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Switch_node"></a>Switch node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>switch</b> node is used to make a decision based on its <b>test</b> attribute.</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>test</b></td>
+<td align="left">Condition to test</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>None</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Depends on the <b>test</b> condition</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;switch test=&quot;$uni-cir-units&quot;&gt;
+  &lt;outcome value=&quot;Mbps&quot;&gt;
+    &lt;reserve plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+                         resource=&quot;ase-port&quot;
+                         key=&quot;resource-emt-clli == $edge-device-clli and speed &gt;= $uni-cir-value&quot;
+                         pfx=&quot;asePort&quot;&gt;
+
+      &lt;outcome value=&quot;success&quot;&gt;
+            &lt;return status=&quot;success&quot;&gt;
+                  &lt;parameter name=&quot;uni-circuit-id&quot; value=&quot;$asePort.uni_circuit_id&quot; /&gt;
+                &lt;/return&gt;
+      &lt;/outcome&gt;
+      &lt;outcome value=&quot;Other&quot;&gt;
+        &lt;return status=&quot;failure&quot;&gt;
+          &lt;parameter name=&quot;error-code&quot; value=&quot;1010&quot; /&gt;
+          &lt;parameter name=&quot;error-message&quot; value=&quot;No ports found that match criteria&quot; /&gt;
+        &lt;/return&gt;
+      &lt;/outcome&gt;
+    &lt;/reserve&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;Gbps&quot;&gt;
+    &lt;reserve plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+                         resource=&quot;ase-port&quot;
+                         key=&quot;resource-emt-clli == $edge-device-clli and speed &gt;= $uni-cir-value*1000&quot;
+                         pfx=&quot;asePort&quot;&gt;
+
+      &lt;outcome value=&quot;success&quot;&gt;
+            &lt;return status=&quot;success&quot;&gt;
+                  &lt;parameter name=&quot;uni-circuit-id&quot; value=&quot;$asePort.uni_circuit_id&quot; /&gt;
+                &lt;/return&gt;
+      &lt;/outcome&gt;
+      &lt;outcome value=&quot;Other&quot;&gt;
+        &lt;return status=&quot;failure&quot;&gt;
+          &lt;parameter name=&quot;error-code&quot; value=&quot;1010&quot; /&gt;
+          &lt;parameter name=&quot;error-message&quot; value=&quot;No ports found that match criteria&quot; /&gt;
+        &lt;/return&gt;
+      &lt;/outcome&gt;
+    &lt;/reserve&gt;
+  &lt;/outcome&gt;    
+&lt;/switch&gt;</pre></div></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('switchNode',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"switch"},
+            xml: {value:"<switch test=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+               //To increase the width of dialogbox
+               //$(".ui-dialog.ui-widget.ui-widget-content.ui-corner-all.ui-front.ui-dialog-buttons.ui-draggable.ui-resizable").css("width","1400px");
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+
+function encodeTestStr(xmlStr){
+       var updatedXmlStr=xmlStr;
+       if(updatedXmlStr != null){
+               var testCondition = getAttributeValue(xmlStr,"test");
+               if(testCondition != null && testCondition != ''){
+                       if(testCondition.indexOf("&lt;") == -1){
+                               testCondition=testCondition.replace(/</g,"&lt;");
+                       }
+                       updatedXmlStr="<switch test=\"" + testCondition + "\" >";
+               }
+       }
+       return updatedXmlStr;
+}
+
+function decodeTestStr(xmlStr){
+       var updatedXmlStr=xmlStr;
+       if(updatedXmlStr != null){
+               var testCondition = getAttributeValue(xmlStr,"test");
+               if(testCondition != null && testCondition != ''){
+                       testCondition=testCondition.replace(/&lt;/g,"<");
+                       updatedXmlStr="<switch test=\"" + testCondition + "\" >";
+               }
+       }
+       return updatedXmlStr;
+}
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/switchNode.js b/dgbuilder/nodes/dge/dgelogic/switchNode.js
new file mode 100644 (file)
index 0000000..6a7a545
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function switchNode(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("switchNode",switchNode);
+    // RED.library.register("switch");
+}
diff --git a/dgbuilder/nodes/dge/dgelogic/update.html b/dgbuilder/nodes/dge/dgelogic/update.html
new file mode 100644 (file)
index 0000000..a7d2828
--- /dev/null
@@ -0,0 +1,195 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="update">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="update">
+       <p>A update node.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+<!--
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>An <b>update</b> node is used to execute Java code supplied as a plugin</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>plugin</b></td>
+<td align="left">Fully qualified Java class of plugin to be used</td></tr>
+<tr class="b">
+<td align="center"><b>method</b></td>
+<td align="left">Name of method in the plugin class to execute. Method must return void, and take 2 arguments: a Map (for parameters) and a SvcLogicContext (to allow plugin read/write access to context memory)</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>Specific to plugin / method</p></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>success</b></td>
+<td align="left">Device successfully configured</td></tr>
+<tr class="b">
+<td align="center"><b>not-found</b></td>
+<td align="left">Plugin class could not be loaded</td></tr>
+<tr class="a">
+<td align="center"><b>unsupported-method</b></td>
+<td align="left">Named method taking (Map, SvcLogicContext) could not be found</td></tr>
+<tr class="b">
+<td align="center"><b>failure</b></td>
+<td align="left">Configure failed for some other reason</td></tr></table></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;update plugin=&quot;org.onap.ccsdk.sli.resource.samplesvc.SampleServiceResource&quot;
+            resource=&quot;network-connection&quot; action=&quot;DELETE&quot; &gt;
+  &lt;parameter name=&quot;message&quot; value=&quot;Hello, world!&quot; /&gt;
+  &lt;outcome value=&quot;success&quot;&gt;
+      &lt;return status=&quot;success&quot;/&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;not-found&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1590&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Could not locate plugin&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+  &lt;outcome value=&quot;Other&quot;&gt;
+    &lt;return status=&quot;failure&quot;&gt;
+      &lt;parameter name=&quot;error-code&quot; value=&quot;1542&quot; /&gt;
+      &lt;parameter name=&quot;error-message&quot; value=&quot;Internal error&quot; /&gt;
+    &lt;/return&gt;
+  &lt;/outcome&gt;
+&lt;/update&gt;</pre></div></div></div></div>
+-->
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('update',{
+        color:"#fdd0a2",
+        category: 'DGElogic',
+        defaults: {
+            name: {value:"update"},
+            xml: {value:"<update resource='' force='' plugin='' key='' pfx='' local-only=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               //console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgelogic/update.js b/dgbuilder/nodes/dge/dgelogic/update.js
new file mode 100644 (file)
index 0000000..f614af8
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function update(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("update",update);
+    // RED.library.register("configure");
+}
diff --git a/dgbuilder/nodes/dge/dgemain/GenericXML.html b/dgbuilder/nodes/dge/dgemain/GenericXML.html
new file mode 100644 (file)
index 0000000..4c9c01a
--- /dev/null
@@ -0,0 +1,140 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="GenericXML">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 250px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show SLI Values</b></a>
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="GenericXML">
+       <p>A generic DGEmain node.</p>
+       <p>Name can be anything.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('GenericXML',{
+        color:"#fdd0a2",
+        category: 'DGEmain',
+        defaults: {
+            name: {value:"dge-node"},
+            xml: {value:""},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgemain/GenericXML.js b/dgbuilder/nodes/dge/dgemain/GenericXML.js
new file mode 100644 (file)
index 0000000..e5fc062
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function GenericXML(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("GenericXML",GenericXML);
+    // RED.library.register("GenericXML");
+}
diff --git a/dgbuilder/nodes/dge/dgemain/comment.html b/dgbuilder/nodes/dge/dgemain/comment.html
new file mode 100644 (file)
index 0000000..c34d14c
--- /dev/null
@@ -0,0 +1,97 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="comment">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-comment"></i> Comment</label>
+        <input type="text" id="node-input-name" placeholder="Comment">
+    </div>
+    <div class="form-row">
+        <label for="node-input-info" style="width: 100% !important;"><i class="fa fa-comments"></i> More</label>
+        <input type="hidden" id="node-input-info" autofocus="autofocus">
+        <div style="height: 250px;" class="node-text-editor" id="node-input-info-editor" ></div>
+        <input type="hidden" id="node-input-comments">
+    </div>
+    <div class="form-tips">Tip: this isn't meant for "War and Peace" - but useful notes can be kept here.</div>
+</script>
+
+<script type="text/x-red" data-help-name="comment">
+    <p>Simple comment block.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('comment',{
+        category: 'DGEmain',
+        color:"#ffffff",
+        defaults: {
+            name: {value:""},
+            info: {value:""},
+           comments:{value:""} 
+        },
+        inputs:0,
+        outputs:0,
+        icon: "comment.png",
+        label: function() {
+            return this.name||"";
+        },
+        labelStyle: function() {
+            return this.name?"node_label_italic":"";
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-info-editor").css("height",(ui.size.height-235)+"px");
+            };
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-info-editor'),
+                    lang:"text",
+                    showLinesRuler:false,
+                    showFoldingRuler:false,
+                    contents: $("#node-input-info").val()
+                });
+                $("#node-input-name").focus();
+            });
+        },
+        oneditsave: function() {
+            $("#node-input-info").val(this.editor.getText());
+            delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgemain/comment.js b/dgbuilder/nodes/dge/dgemain/comment.js
new file mode 100644 (file)
index 0000000..ef5f080
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    function CommentNode(n) {
+        RED.nodes.createNode(this,n);
+    }
+    RED.nodes.registerType("comment",CommentNode);
+}
diff --git a/dgbuilder/nodes/dge/dgemain/dgstart.html b/dgbuilder/nodes/dge/dgemain/dgstart.html
new file mode 100644 (file)
index 0000000..9caa841
--- /dev/null
@@ -0,0 +1,1322 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<div id="svclogicPageDiv" ></div>
+<!-- dgbuilder javascript files START -->
+<script src="util/js/validateNodeXml.js"/>
+<script src="util/js/sliValues.js"/>
+<script src="util/js/dgeToXml.js"/>
+<script src="util/js/vkbeautify.0.99.00.beta.js"/>
+<!-- dgbuilder javascript files END -->
+
+<script type="text/x-red" data-template-name="dgstart">
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+<style>
+.no-close .ui-dialog-titlebar-close {display: none }
+.alertDialogButton {
+   border-top: 1px solid #96d1f8;
+   background: #65a9d7;
+   background: -webkit-gradient(linear, left top, left bottom, from(#3e779d), to(#65a9d7));
+   background: -webkit-linear-gradient(top, #3e779d, #65a9d7);
+   background: -moz-linear-gradient(top, #3e779d, #65a9d7);
+   background: -ms-linear-gradient(top, #3e779d, #65a9d7);
+   background: -o-linear-gradient(top, #3e779d, #65a9d7);
+   padding: 5px 10px;
+   -webkit-border-radius: 8px;
+   -moz-border-radius: 8px;
+   border-radius: 8px;
+   -webkit-box-shadow: rgba(0,0,0,1) 0 1px 0;
+   -moz-box-shadow: rgba(0,0,0,1) 0 1px 0;
+   box-shadow: rgba(0,0,0,1) 0 1px 0;
+   text-shadow: rgba(0,0,0,.4) 0 1px 0;
+   color: white;
+   font-size: 14px;
+   font-family: Georgia, serif;
+   text-decoration: none;
+   vertical-align: middle;
+   }
+.alertDialogButton:hover {
+   border-top-color: #28597a;
+   background: #28597a;
+   color: #ccc;
+   }
+
+.alertDialogButton:active {
+   border-top-color: #1b435e;
+   background: #1b435e;
+   }
+.disabled-button {
+   border-top: 1px solid #96d1f8;
+   background: lightgrey;
+   background: -webkit-gradient(linear, left top, left bottom, from(grey), to(lightgrey));
+   background: -webkit-linear-gradient(top, grey, grey);
+   background: -moz-linear-gradient(top, grey, grey);
+   background: -ms-linear-gradient(top, grey, grey);
+   background: -o-linear-gradient(top, grey, grey);
+   padding: 5px 10px;
+   -webkit-border-radius: 8px;
+   -moz-border-radius: 8px;
+   border-radius: 8px;
+   -webkit-box-shadow: rgba(0,0,0,1) 0 1px 0;
+   -moz-box-shadow: rgba(0,0,0,1) 0 1px 0;
+   box-shadow: rgba(0,0,0,1) 0 1px 0;
+   text-shadow: rgba(0,0,0,.4) 0 1px 0;
+   color: lightgrey;
+   font-size: 14px;
+   font-family: Georgia, serif;
+   text-decoration: none;
+   vertical-align: middle;
+   }
+</style>
+<script type="text/javascript">
+
+function activateDG(module,rpc,version,mode,displayOnlyCurrent){
+       var paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : false};
+       if(displayOnlyCurrent){
+               paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : true};
+       }
+       var dgInfo = "<div><table width='100%' border='1'><tr style='background-color:#65a9d7;color:white;' ><th>Module</th><th>RPC</th><th>Version</th></tr><tr style='background-color:white'><td>" + module +"</td><td>" + rpc + "</td><td>" +version +  "</td></tr></table></div><br>";
+       var alertMsg = dgInfo + "<p>Are you sure you want to Activate this DG ?</p>"; 
+$( "#alertdialog" ).dialog({
+  dialogClass: "no-close",
+  autoOpen :false,
+  modal:true,
+  draggable : true,
+  /*dialogClass: "alert",*/
+  title: "Confirm Activate",
+  width: 600,
+  buttons: [
+    {
+      text: "Activate",
+      class:"alertDialogButton",
+      click: function() {
+       $.get("/activateDG" , paramsObj)
+       .done(function( data ) {
+                  //RED.notify("<strong>Activated Successfully</strong>");
+               var htmlStr = "";
+               var title ="";
+               if(displayOnlyCurrent){
+                        htmlStr=getHtmlStr(data,true);
+                        title="Service Logic Administration  Module=" + module + " and RPC=" + rpc;
+               }else{
+                        htmlStr=getHtmlStr(data);
+                        title= "Service Logic Administration - " + data.dbHost; 
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: title,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .fail(function( err ) {
+                  RED.notify("<strong>Could not Activate</strong>");
+               var htmlStr = "<p>" + "could not activate" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showSLA()'></a>";
+               if(displayOnlyCurrent == true){
+                        htmlStr = "<p>" + "could not activate" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>Back to DG List</a>";
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration - " + err.dbHost, 
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .always(function() { 
+               // $('.ui-dialog:has(#alertdialog)').empty().remove();
+               $("#alertdialog" ).dialog('close');
+               
+       });
+       }
+    },
+    {
+      text: "Cancel",
+      class:"alertDialogButton",
+      click: function() {
+       //$('.ui-dialog:has(#alertdialog)').empty().remove();
+        $( this ).dialog( "close" );
+      }
+    }
+  ]
+}).html(alertMsg).dialog('open');
+//var dialogClass = $("#alertdialog").dialog( "option", "dialogClass" );
+//$( "#alertdialog" ).dialog( "option", "dialogClass", "alert" );
+//$("#alertdialog").dialog("widget").find(".ui-dialog-buttonpane").css("background-color", "#ECECFF");
+/*
+$('#alertdialog').css("background-color", "#ECECEC");
+$("#alertdialog").dialog("widget").find(".ui-dialog-buttonpane").css("background-color", "#ECECEC");
+
+// button pane style
+$("#alertdialog").dialog("widget").find(".ui-dialog-buttonpane").css({"padding":".1em .1em .1em 0","margin":"0 0 0 0"} )
+
+// button style
+$("#alertdialog").dialog("widget").find("button").css({"padding":"0 .2em 0 .2em","margin":"0 .5em 0 0"} )
+$("#alertdialog").dialog("widget").find("button").addClass("alertDialogButton");
+*/
+//console.dir($("#alertdialog"));
+}
+
+
+function deActivateDG(module,rpc,version,mode,displayOnlyCurrent){
+       var paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : false};
+       if(displayOnlyCurrent){
+               paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : true};
+       }
+       var dgInfo = "<div ><table width='100%' border='1'><tr style='background-color:#65a9d7;color:white;'><th>Module</th><th>RPC</th><th>Version</th></tr><tr style='background-color:white'><td>" + module +"</td><td>" + rpc + "</td><td>" +version +  "</td></tr></table></div><br>";
+       var alertMsg = dgInfo + "<p>Are you sure you want to De-Activate this DG ?</p>"; 
+$( "#alertdialog" ).dialog({
+  dialogClass: "no-close",
+  autoOpen : false,    
+  modal:true,
+  draggable : true,
+  title: "Confirm De-Activate",
+  width: 600,
+  buttons: [
+    {
+      text: "De-Activate",
+      class:"alertDialogButton",
+      click: function() {
+       $.get("/deActivateDG" , paramsObj)
+       .done(function( data ) {
+                  //RED.notify("<strong>deActivated Successfully</strong>");
+               var htmlStr = "";
+               var title ="";
+               if(displayOnlyCurrent){
+                        htmlStr=getHtmlStr(data,true);
+                        title="Service Logic Administration  Module=" + module + " and RPC=" + rpc;
+               }else{
+                        htmlStr=getHtmlStr(data);
+                        title= "Service Logic Administration - " + data.dbHost; 
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: title,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .fail(function( err ) {
+                  RED.notify("<strong>Could not De-Activate</strong>");
+               var htmlStr = "<p>" + "could not deactivate" + module + " " + rpc + " " + version +"</p>  <a onclick='javascript:showSLA()'></a>";
+               if(displayOnlyCurrent == true){
+                        htmlStr = "<p>" + "could not deactivate" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>Back to DG List</a>";
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration - " + err.dbHost, 
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .always(function() { 
+                //$('.ui-dialog:has(#alertdialog)').empty().remove();
+               $( "#alertdialog" ).dialog( "close" );
+               //$("#alertdialog" ).dialog('destroy').remove();
+       });
+      }
+    },
+    {
+      text: "Cancel",
+      class:"alertDialogButton",
+      click: function() {
+       //$('.ui-dialog:has(#alertdialog)').empty().remove();
+       //$(this).dialog('destroy').remove()
+        //$( this ).dialog( "close" );
+       /*if ($("#alertdialog").hasClass('ui-dialog-content')) {
+               $("#alertdialog" ).dialog('close');
+       }else{
+               $( this ).dialog( "close" );
+       }
+       */
+        $( this ).dialog( "close" );
+      }
+    }
+  ]
+}).html(alertMsg).dialog("open");
+}
+
+function deleteDG(module,rpc,version,mode,displayOnlyCurrent){
+       var paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : false};
+       if(displayOnlyCurrent){
+               paramsObj = {'module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : true};
+       }
+       var dgInfo = "<div ><table width='100%' border='1'><tr style='background-color:#65a9d7;color:white;'><th>Module</th><th>RPC</th><th>Version</th></tr><tr style='background-color:white'><td>" + module +"</td><td>" + rpc + "</td><td>" +version +  "</td></tr></table></div><br>";
+       var alertMsg = dgInfo + "<p>Are you sure you want to Delete this DG ?</p>"; 
+$( "#alertdialog" ).dialog({
+  dialogClass: "no-close",
+  autoOpen: false,
+  modal:true,
+  draggable : true,
+  title: "Confirm Delete",
+  width: 600,
+  buttons: [
+    {
+      text: "Delete",
+      class:"alertDialogButton",
+      click: function() {
+       $.get("/deleteDG" , paramsObj)
+       .done(function( data ) {
+                  RED.notify("<strong>Deleted " + module + " " + rpc + " " + version + " Successfully</strong>");
+               var htmlStr = "";
+               var title ="";
+               if(displayOnlyCurrent){
+                        htmlStr=getHtmlStr(data,true);
+                        title="Service Logic Administration  Module=" + module + " and RPC=" + rpc;
+               }else{
+                        htmlStr=getHtmlStr(data);
+                        title= "Service Logic Administration - " + data.dbHost; 
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: title,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .fail(function( err ) {
+                  //RED.notify("<strong>Could not Delete" +  module + " " + rpc + " " + version +  "</strong>");
+               var htmlStr = "<p>" + "could not delete" + module + " " + rpc + " " + version +"</p>  <a onclick='javascript:showSLA()'></a>";
+               if(displayOnlyCurrent == true){
+                        htmlStr = "<p>" + "could not delete" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>Back to DG List</a>";
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration - " + err.dbHost, 
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .always(function() { 
+               $( "#alertdialog" ).dialog( "close" );
+                //$('.ui-dialog:has(#alertdialog)').empty().remove();
+               //$("#alertdialog" ).dialog('destroy').remove();
+       });
+      }
+    },
+    {
+      text: "Cancel",
+      class:"alertDialogButton",
+      click: function() {
+       /*
+       if ($("#alertdialog").hasClass('ui-dialog-content')) {
+               $("#alertdialog" ).dialog('close');
+       }else{
+               $( this ).dialog( "close" );
+       }
+       */
+        //$( "#alertdialog" ).dialog( "close" );
+       //$('.ui-dialog:has(#alertdialog)').empty().remove();
+        //$( this ).dialog( "close" );
+        $( this ).dialog( "close" );
+      }
+    }
+  ]
+}).html(alertMsg).dialog("open");
+}
+/*
+function downloadDGXml(_module,rpc,version,mode){
+       var paramsObj = {'_module': _module , 'rpc' : rpc , 'version' : version , 'mode' : mode};
+       var form = $('<form id="dwnldDbXmlFormId" method="POST" action="/downloadDGXml"></form>');
+       form.append('<input type="hidden" name="_module" value="' + _module + '"/>');
+       form.append('<input type="hidden" name="rpc" value="' + rpc + '"/>');
+       form.append('<input type="hidden" name="version" value="' + version + '"/>');
+       form.append('<input type="hidden" name="mode" value="' + mode + '"/>');
+       form.appendTo('body');
+       $("#dwnldDbXmlFormId").submit();
+}
+*/
+
+function displayXml(module,rpc,version,mode,displayOnlyCurrent){
+       var paramsObj = {'_module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : false};
+       var title="Service Logic Administration";
+       if(displayOnlyCurrent){
+               paramsObj = {'_module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : true};
+               title="Service Logic Administration  Module=" + module + " and RPC=" + rpc;
+       }else{
+               title="Service Logic Administration";
+       }
+       //var headingStr = "<a style='color: #337ab7;' onclick='javascript:showSLA()'>&lt;&lt;Back to DG List</a><br><div style='background-color:#337ab7;clear:both;'><table style='width:100%;' border='0'>" +
+       var headingStr = "<a style='color: #337ab7;cursor:pointer;' onclick='javascript:showSLA()'>&lt;&lt;Back to DG List</a><br><div style='clear:both;'><table style='width:25%' border='0'>" ;
+               if(displayOnlyCurrent == true){
+                       headingStr = "<a style='color: #337ab7;cursor:pointer;' onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>&lt;&lt;Back to DG List</a><br><div style='clear:both;'><table style='width:25%' border='0'>" ;
+               }
+                       headingStr += "<tr><td><b>Module</b></td><td>" + module + "</td></tr>" +
+                       "<tr><td><b>RPC</b></td><td>" + rpc + "</td></tr>" +
+                       "<tr><td><b>Version</b></td><td>" + version + "</td></tr>" +
+                       "<tr><td><b>Mode</b></td><td>" + mode + "</td></tr>" +
+                       "</table></div>";
+
+       //var urlStr = "/displayXml?_module=" + module + "&rpc=" + rpc + "&version=" + version + "&mode=" + mode; 
+       $.get("/displayXml",paramsObj)
+       .done(function( data ) {
+               //var htmlStr= headingStr + '<div style="clear:both;"></div><div style="background-color:lightgrey;border-style: solid;border-color:#337ab7;clear:both;">' + data.xmldata + "</div>";
+               var htmlStr= headingStr + '<hr style="clear:both;height:5px;background-color:#337ab7;"><div>' + data.xmldata + "</div>";
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: title,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .fail(function( err ) {
+                  //RED.notify("<strong>Could not display XML</strong>");
+               var htmlStr = "<p>" + "Could not display xml for" + module + " " + rpc + " " + version + "</p><a style='color: #337ab7;cursor:pointer;' onclick='javascript:showSLA()'>Back to DG List</a><br>";
+               if(displayOnlyCurrent == true){
+                        htmlStr = "<p>" + "could not display XML" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>Back to DG List</a>";
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration",
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .always(function() { 
+       });
+}
+
+function displayDG(module,rpc,version,mode,displayOnlyCurrent){
+       var paramsObj = {'_module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : false};
+       var title="Service Logic Administration";
+       if(displayOnlyCurrent){
+               paramsObj = {'_module': module , 'rpc' : rpc , 'version' : version , 'mode' : mode,'displayOnlyCurrent' : true};
+       }
+       //var headingStr = "<a style='color: #337ab7;cursor:pointer' onclick='javascript:showSLA()'>&lt;&lt;Back to DG List</a><br><div><table id='msgTable' style='width:25%;background-color:lightgrey' border='0'>" +
+       var headingStr = "<a style='color: #337ab7;cursor:pointer;' onclick='javascript:showSLA()'>&lt;&lt;Back to DG List</a><br><div><table id='msgTable' style='width:25%;' border='0'>" ;
+               if(displayOnlyCurrent == true){
+                       headingStr = "<a style='color: #337ab7;cursor:pointer;' onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>&lt;&lt;Back to DG List</a><br><div style='clear:both;'><table style='width:25%' border='0'>" ;
+                      title="Service Logic Administration  Module=" + module + " and RPC=" + rpc;
+               }
+                       headingStr +="<tr><td><b>Module</b></td><td>" + module + "</td></tr>" +
+                       "<tr><td><b>RPC</b></td><td>" + rpc + "</td></tr>" +
+                       "<tr><td><b>Version</b></td><td>" + version + "</td></tr>" +
+                       "<tr><td><b>Mode</b></td><td>" + mode + "</td></tr>" +
+                       "</table></div>";
+
+       //var urlStr = "/displayAsGv?_module=" + module + "&rpc=" + rpc + "&version=" + version + "&mode=" + mode; 
+       $.get("/displayAsGv",paramsObj)
+       .done(function( data ) {
+               var htmlStr= headingStr + '<div style="background-color:white;">' + data.svg_html + "</div>";
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration",
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .fail(function( err ) {
+                  //RED.notify("<strong>Could not display XML</strong>");
+               var htmlStr = "<p>" + "Could not display DG for" + module + " " + rpc + " " + version + "</p><a style='color: #337ab7;cursor:pointer;' onclick='javascript:showSLA()'>Back to DG List</a><br>";
+               if(displayOnlyCurrent == true){
+                        htmlStr = "<p>" + "could not display DG for" + module + " " + rpc + " " + version +"</p> <a onclick='javascript:showCurrentDGs(\"" + module + "\",\"" + rpc + "\")'>Back to DG List</a>";
+               }
+               $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration",
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+         })
+       .always(function() { 
+       });
+}
+
+function getHtmlStr(data,displayOnlyCurrent,module,rpc){
+       var styleStr = "<style> " + 
+                       "table#t01 { width:100%; } \n" +
+                               "table#t01 th,table#t01 td { border: 1px solid black; border-collapse: collapse; } \n" +
+                               /*"table, th, td { border: 1px solid #65a9d7; border-collapse: collapse; } \n" +*/
+                               "table#t01 th,table#t01 td { padding: 5px; text-align: left; } \n" +
+                               "table#t01 tr:nth-child(even) { background-color: #eee; }\n" +
+                               "table#t01 tr:nth-child(odd) { background-color:#fff; }\n" +
+                               "table#t01 th   { background-color: #65a9d7; color: white; }\n" +
+                               "table#t01 a { color: #337ab7; }\n" +
+                               "table#t01 a:link { color: #65a9d7; }\n" +
+                               "table#t01 a:visited { color: #636; }\n" + 
+                               "table#t01 a:hover { color: #3366CC; cursor: pointer }\n" + 
+                               "table#t01 a:active { color: #65a9d7 }\n" +
+                               "</style>";
+                       if(data != null && data.rows != undefined && data.error == undefined){
+                               var alertDialog = '<div id="alertdialog"></div>';
+                               htmlStr= alertDialog +  "<div style='width:1050;height:650'>" + styleStr;
+                               htmlStr += "<table id='t01' >";
+                               htmlStr += "<tr>";
+                               htmlStr += "<th>Module</th>" ;
+                               htmlStr += "<th>RPC</th>" ;
+                               htmlStr += "<th>Version</th>" ;
+                               htmlStr += "<th>Mode</th>" ;
+                               htmlStr += "<th>Active</th>" ;
+                               htmlStr += "<th>Activate/Deactivate</th>";
+                               htmlStr += "<th>Display DG</th>";
+                               htmlStr += "<th>XML</th>";
+                               htmlStr += "<th>Delete</th>";
+                               htmlStr += "</tr>";
+                               var rows = data.rows;
+                               if(rows != null && rows.length == 0){
+                                       htmlStr += "<tr>";
+                                       htmlStr += "<td><b>No rows found</b></td>";
+                                       htmlStr += "</tr></table></div>";
+                                       return htmlStr;
+                               }
+                               for(var i=0;i<rows.length;i++){
+                                       var row = rows[i];
+                                       var _module = row.module;
+                                       var rpc = row.rpc;
+                                       var version = row.version;
+                                       var mode = row.mode;
+                                       var active = row.active;
+                                       htmlStr += "<tr>";
+                                       htmlStr += "<td>" + _module + "</td>";
+                                       htmlStr += "<td>" + rpc + "</td>";
+                                       htmlStr += "<td>" + version + "</td>";
+                                       htmlStr += "<td>" + mode + "</td>";
+                                       htmlStr += "<td>" + active + "</td>";
+
+                                       var methodParams =  "'" + _module +  "','" + rpc + "','" + version + "','"  + mode + "'";
+                                       if(displayOnlyCurrent){
+                                               methodParams+= ",true";
+                                       }
+                                       if(active == 'Y'){
+                                                       htmlStr += "<td><a onclick=\"javascript:deActivateDG(" +  methodParams + ")\">DeActivate</a></td>";
+                                       }else{
+                                               htmlStr += "<td><a onclick=\"javascript:activateDG(" + methodParams +  ")\">Activate</a></td>";
+                                       }
+                                       htmlStr += "<td><a onclick=\"javascript:displayDG(" + methodParams + ")\">Display</a></td>";
+
+                                       htmlStr += "<td><a onclick=\"javascript:displayXml(" + methodParams + ")\">XML</a></td>";
+
+                                       htmlStr += "<td><a onclick=\"javascript:deleteDG(" + methodParams + ")\">Delete</a></td>";
+                                       htmlStr += "</tr>";
+                               }
+                               htmlStr += "</table>";
+                               htmlStr += "</div>";
+                       }
+       return htmlStr;
+}
+
+function showSLA(){
+       var htmlStr = "";
+       try{
+               $.get("/listSLA")
+               .done(function( data ) {
+                       var htmlStr=getHtmlStr(data);
+                       $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration - " + data.dbHost, 
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+               })
+               .fail(function(err) {
+                       htmlStr= "<div>Error occured displaying the DG list</div>";
+                       $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title: "Service Logic Administration - " + data.dbHost, 
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+               })
+               .always(function() { 
+               });
+       }catch(err){
+       }
+}
+
+function showCurrentDGs(module,rpc){
+       var htmlStr = "";
+       try{
+               var params="?module=" + module + "&rpc=" + rpc;
+               var url="/listCurrentDGs" + params;
+               //console.log("url:" + url);
+               $.get(url)
+               .done(function( data ) {
+                       var htmlStr=getHtmlStr(data,true);
+                       $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title:"Service Logic Administration  Module=" + module + " and RPC=" + rpc,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+               })
+               .fail(function(err) {
+                       htmlStr= "<div>Error occured displaying the DG list</div>";
+                       $("#svclogicPageDiv").dialog({
+                               modal:true,     
+                               title:"Service Logic Administration  Module=" + module + " and RPC=" + rpc,
+                               width: 1200,
+                               height: 750,
+                                       minWidth : 600, 
+                                       minHeight :450, 
+                               }).html(htmlStr);
+               })
+               .always(function() { 
+               });
+       }catch(err){
+       }
+}
+
+
+function displaySLA(callback){
+       var htmlStr = "";
+       try{
+               $.get("/listSLA")
+               .done(function( data ) {
+                       var htmlStr=getHtmlStr(data);
+                       callback(htmlStr,data.dbHost);
+               })
+               .fail(function(err) {
+                       htmlStr= "<div>Error occured displaying the DG list</div>";
+                       callback(htmlStr,err.dbHost);
+               })
+               .always(function() { 
+               });
+       }catch(err){
+                       callback(htmlStr,"");
+       }
+}
+
+function displayCurrentDGs(module,rpc,callback){
+       var htmlStr = "";
+       try{
+               var params="?module=" + module + "&rpc=" + rpc;
+               var url="/listCurrentDGs" + params;
+               //console.log("url:" + url);
+               $.get(url )
+               .done(function( data ) {
+                       var htmlStr=getHtmlStr(data,true);
+                       callback(htmlStr,data.dbHost);
+               })
+               .fail(function(err) {
+                       htmlStr= "<div>Error occured displaying the Current DG list</div>";
+                       callback(htmlStr,err.dbHost);
+               })
+               .always(function() { 
+               });
+       }catch(err){
+                       callback(htmlStr,"");
+       }
+}
+
+
+window.onbeforeunload = function (event) {
+       var dis = $('#btn-deploy').attr('class')
+       if ( dis.indexOf('disabled') == -1 ) {
+               var message = 'Important: You have changes that were not \'deployed\'.';
+               if (typeof event == 'undefined') {
+                       event = window.event;
+               }
+               if (event) {
+                       event.returnValue = message;
+               }
+               return message;
+       }
+};
+</script>
+<script type="text/x-red" data-help-name="dgstart">
+       <p>This node starts a flow. This node is required on every flow.</p>
+       <p>This node has a button to its left, when clicked generates the XML for the flow</p>
+       <img src="images/dgstart.png"></img>
+</script>
+<style>
+.textview{
+       font-size:20px;
+}
+</style>
+
+<div id="screenInfoId"></div>
+<script type="text/javascript">
+function getAttributeValue(xmlStr,attribute){
+        var attrVal=null;
+        try{
+                var myRe = new RegExp(attribute + "[\s+]?=[\s+]?['\"]([^'\"]+)['\"]","m");
+                var myArray = myRe.exec(xmlStr);
+                if(myArray != null && myArray[1] != null){
+                        attrVal=myArray[1];
+                }
+        }catch(err){
+                console.log(err);
+        }
+        return attrVal;
+
+}
+
+
+function showDgStartGenerateXmlStatus(){
+       var htmlStr="<div id='dgstart-generate-xml-div' style='width:375;height:225'><p>Generating XML. Please wait... </p><img src='images/page-loading.gif'></div>"
+       $("#dgstart-generate-xml-dialog").dialog({
+               modal:true,     
+               title: "DGBuilder XML Generation Status",
+               width: 400,
+               height: 250,
+                minWidth : 400, 
+                minHeight :200, 
+               }).html(htmlStr);
+}
+
+    RED.nodes.registerType('dgstart',{
+        color:"#fdd0a2",
+        category: 'DGEmain',
+        defaults: {
+            name: {value:"DGSTART"},
+            outputs: {value:1}
+        },
+        inputs:0,
+        outputs:1,
+        icon: "inject.png",
+        label: function() {
+            return this.name;
+        },
+       onpaletteadd: function() {
+               //console.log("DGSTART Added to the palette.");
+       },
+        button: {
+            onclick: function() {
+               //$('#processingStatusId').text('working...');
+               //$('#processingStatusId').html("<span><p>    Processing Please Wait...</span><img src='images/page-loading.gif'>");
+               $('#processingStatusId').html("<span style='font-size:0.2em;color:green'>   Processing...</span>");
+               var timerObj = window.setTimeout(function() {
+               //document.getElementById("processingStatusId").innerHTML ="<img src='images/page-loading.gif'>";
+
+               /*
+               var target = $(event.target);
+               //target.text("Validating XML");
+               target.css({ "background-image": "url('images/page-loading.gif')" });
+               target.css({ "background-repeat": "no-repeat" });
+               target.css({ "background-size": "25px 25px" });
+               */
+
+               //deploy button 
+               //$("#btn-deploy")
+               var loopDetectionEnabled = true;
+               console.log("loopDetectionEnabled:" +loopDetectionEnabled);
+               if(loopDetectionEnabled){
+                       var msecs1= Date.now();
+                       var isLoopDetected = detectLoop();
+                       var msecs2= Date.now();
+                       console.log("Time taken for loop detection:" + (msecs2 - msecs1));
+                       if(isLoopDetected){
+                               //RED.notify("<strong>Error</strong>: Loop Detected","error");
+                               //target.css({ "background-image": "none" });
+                               return false;
+                       }
+               }
+               var nodeSetWithUpdatedDgNumbers = updateDgNumbers();
+               validateEachNodeXml();
+               //var nodeToXmlStr = getNodeToXml();
+               var unformatted_xml_str = getNodeToXml();
+               //console.log("Size of unformatted_xml_str" + unformatted_xml_str.length);      
+               //console.log("output:" + nodeToXmlStr);
+               var formatted_xml = vkbeautify.xml(unformatted_xml_str);        
+               /*
+               var minified_xml = vkbeautify.xmlmin(unformatted_xml_str,true);         
+               var lengthOfMinifiedXml = minified_xml.length;
+               if(lengthOfMinifiedXml >0){
+                       var val = lengthOfMinifiedXml/(1024*1024)
+                       var minSizeStr = val.toFixed(4) + " MB";
+                       console.log("minified XML size:" + minSizeStr);
+               }
+               */
+               var lengthOfXml = formatted_xml.length;
+               var sizeStr = "";
+               if(lengthOfXml >0){
+                       var val = lengthOfXml/(1024*1024)
+                       sizeStr = val.toFixed(4) + " MB";
+                       console.log("length:" + val);
+               }
+               var xmlLines = formatted_xml.split("\n");
+               console.log("Number of lines " + xmlLines.length);
+               var numberOfLines = xmlLines.length;
+               //var display_formatted_xml = formatted_xml.replace("&lt;","<");
+               var currentNodeSet = getCurrentFlowNodeSet();
+               //get max x and y coordinates
+               var x=0;
+               var y=0;
+               var maxX=0;
+               var maxY=0;
+               var moduleName = "";
+               var dgVersion = "";
+               var methodName = "";
+               var formattedMethodName = "";
+               var origModuleName = "";
+               var origMethodName = "";
+               for(var i=0;currentNodeSet != null && i<currentNodeSet.length;i++){
+                       if(currentNodeSet[i].type == "service-logic"){
+                               //moduleName = currentNodeSet[i].name;
+                               moduleName = currentNodeSet[i].module;
+                               dgVersion = currentNodeSet[i].version;
+                               origModuleName = getAttributeValue(currentNodeSet[i].xml,"module");
+                       }
+                       if(currentNodeSet[i].type == "method"){
+                               //methodName = currentNodeSet[i].name;
+                               origMethodName = getAttributeValue(currentNodeSet[i].xml,"rpc");;
+                               methodName = origMethodName;
+                               if(methodName == ""){
+                                       methodName = "rpc_not_set";
+                               }
+                       }
+                       x = currentNodeSet[i].x;        
+                       y = currentNodeSet[i].y;        
+                       if(x>maxX){
+                               maxX=x;
+                       }
+                       if(y>maxY){
+                               maxY=y;
+                       }
+               }
+               //add 5 more pixels to that
+               maxX= Math.ceil(maxX) + 5;
+               maxY= Math.ceil(maxY) + 5;
+               //console.log("maxX:" + maxX);
+               //console.log("maxY:" + maxY);
+               var unformatted_json_str=JSON.stringify(currentNodeSet);
+               var formatted_json = vkbeautify.json(unformatted_json_str);
+               //var displayHtmlStr="<div><textarea readonly='1' style='width:1100px;height:700px;border:none'>" + formatted_xml + "</textarea></div>";
+               var displayHtmlStr="<div style='font-size:20px;'><xmp>" + formatted_xml + "</xmp></div>";
+               var xmlInfoStr = "<div id='xml-info-div'><p>" + "XML size:" + sizeStr +  " <br>Number of Lines:" + numberOfLines +  "</p></div>";
+               var htmlCode ="";
+               $( "#xmldialog" ).dialog({
+                       title: "XML Generated",
+                       width: 1200,
+                       height: 750,
+                               minWidth : 800, 
+                               minHeight :450, 
+                       dialogClass : "no-close",
+                       closeOnEscape : false,  
+                       autoOpen : false,
+                       resize: function( event, ui ) {
+                               /*
+                                       $( this ).dialog( "option", "title",
+                                       ui.size.height + " x " + ui.size.width );
+                               */
+                       },
+                       modal: true,
+                       /*show: {
+                               effect: "slide",
+                               duration: 1000
+                       },
+                       */
+                       /*hide: {
+                               effect: "slide",
+                               duration: 500
+                       },
+                       */
+                        buttons: {
+                       /*      
+                           "+" : function () {
+                                       var size= $("#xmldialog").find('.textview').css("font-size");
+                                       console.log("size:" + size);
+                                       size=size.replace("px","");
+                                       var fsize=Number(size) +1;
+                                       if(fsize<19){
+                                               fsize+=4;
+                                       }
+                                       if(fsize >= 26){
+                                               return;
+                                       }
+                                       $("#xmldialog").find('.textview').css("font-size",fsize);
+                               },
+                           "-" : function () {
+                                       var size= $("#xmldialog").find('.textview').css("font-size");
+                                       console.log("size:" + size);
+                                       size=size.replace(/px/,"");
+                                       var fsize=Number(size) -1;
+                                       if(fsize <= 14){
+                                               return;
+                                       }
+                                       $("#xmldialog").find('.textview').css("font-size",fsize);
+                               },
+                       */
+                           "Validate XML" : function (event) {
+                               if(!event) event = window.event;
+                               var target = $(event.target);
+                               target.text("Validating XML");
+                               target.css({ "background-image": "url('images/page-loading.gif')" });
+                               target.css({ "background-repeat": "no-repeat" });
+                               target.css({ "background-size": "25px 25px" });
+
+                               var resp= validateFinalXML(unformatted_xml_str);
+                               console.log("errorList:" + errList);
+                               if(!resp){
+                                       showErrors();   
+                               }
+                               target.text("Validate XML");
+                               target.css({ "background-image": "none" });
+                           },
+                           "Email Flow" : function (event) {
+                               if(!event) event = window.event;
+                               var target = $(event.target);
+                               target.text("Processing");
+                               target.css({ "background-image": "url('images/page-loading.gif')" });
+                               target.css({ "background-repeat": "no-repeat" });
+                               target.css({ "background-size": "25px 25px" });
+                               d3.xhr("style.css").get(function(err,resp){
+                                       console.log("resp:" + resp);
+                                       //console.dir(resp);
+                                       var styleSheetText = resp.responseText;
+                                       /*var htmlCode = "<style>"  + styleSheetText + "</style></head>" + 
+                                                '<body><div id="chart" class="ui-droppable">' +
+                                       */
+                                       //var svgTagInfo = '<div style="overflow:auto;border:1px solid #D76D2D;height:600px;"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 768" preserveAspectRatio="xMidYMid meet">';
+                                       //var svgTagInfo = '<div style="overflow-x:auto;overflow-y:auto;border:1px solid #D76D2D;width:1200px;height:750px;"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" width="3500px" height="3200px" viewBox="0 0 5500 5000" >';
+                                       var svgTagInfo = '<div style="overflow-x:auto;overflow-y:auto;border:1px solid #D76D2D;width:1200px;height:750px;"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" width="3500px" height="3200px" viewBox="0 0 8000 7500" >';
+                                       var svgHtmlCode = $("svg").html();
+                                       //svgHtmlCode = svgHtmlCode.replace('<rect width="5000" height="5000"','<rect width="' + maxX +  '" height="' + maxY +'"');
+                                       var find = 'href="icons/arrow-in.png"';
+                                       var re = new RegExp(find, 'g');
+                                        svgHtmlCode = svgHtmlCode.replace(re, 'href=""');
+                                       find = 'href="icons/inject.png"';
+                                       re = new RegExp(find, 'g');
+                                        svgHtmlCode = svgHtmlCode.replace(re, 'href=""');
+                                       htmlCode = "\n<style>\n"  + styleSheetText + "</style></head>\n<body>" + svgTagInfo + svgHtmlCode + "\n</svg></div>";
+                                       //console.log($("svg").html());
+                                        //console.log(htmlCode);               
+                                       //html,xml,json form id
+                               /*
+                                       //using form to submit
+                                       var form = $('<form id="hxjFormId" method="POST" action="/sendEmail"></form>');
+                                       form.append('<input id="flowHtmlId" type="hidden" name="flowHtml" value=""/>');
+                                       form.append('<input id="flowXmlId" type="hidden" name="flowXml" value=""/>');
+                                       form.append('<input id="flowJsonId"  type="hidden" name="flowJson" value=""/>');
+                                       $("#screenInfoId").append(form);
+                                       //console.log($("#screenInfoId").html());
+                                       document.getElementById("flowHtmlId").value=htmlCode;
+                                       document.getElementById("flowXmlId").value=formatted_xml;
+                                       document.getElementById("flowJsonId").value=formatted_json;
+                                       //console.log($("#screenInfoId").html());
+                                       $("#hxjFormId").submit();
+                                       console.log("Submitted.");
+                                       */
+                                       var reqData = {
+                                               "flowHtml" : htmlCode,
+                                               "flowXml" : formatted_xml,
+                                               "flowJson" : formatted_json
+                                       };
+
+                                       $.post( "/sendEmail",reqData )
+                                       .done(function( data ) {
+                                               //console.log( "Data Loaded: " + data );
+                                               if(data != null && data.envelope != undefined && data.envelope != null){
+                                                       var toAddress = data.envelope.to;
+                                                       RED.notify("Email sent successfully to " + toAddress);
+                                               }else{
+                                                       RED.notify("Email sent successfully.");
+                                               }
+                                       })
+                                       .fail(function(err) {
+                                                console.log( "error" + err ); 
+                                               RED.notify("Email send Failed.");
+                                       }) 
+                                       .always(function() { 
+                                               console.log( "finished" ); 
+                                               target.text("Email Flow");
+                                               target.css({ "background-image": "none" });
+                                       });
+
+                                       /*
+                                       d3.xhr("/sendEmail").post(reqData,function(err,resp){
+                                               console.log("Error:" + JSON.stringify(err));
+                                               console.log("resp:" + JSON.stringify(resp));
+                                               console.dir(resp);
+                                       });
+                                       */
+                               });
+                           },
+                               /*
+                           Deploy : function () {
+                               $("#btn-deploy").click();       
+                           },
+                               */
+                           "Upload XML" : function (event) {
+                               if(!event) event = window.event;
+                               //Save the flows.json
+                               //RED.view.dirty(true);
+                               //$('#btn-deploy').click();
+                               console.log("Deployed..");
+                               var target = $(event.target);
+                               target.text("Processing");
+                               target.css({ "background-image": "url('images/page-loading.gif')" });
+                               target.css({ "background-repeat": "no-repeat" });
+                               target.css({ "background-size": "25px 25px" });
+                               var date = new Date();  
+                               
+                               var fileName = date.getTime() + ".xml"; 
+                               var reqData = {
+                                       "flowXml" : unformatted_xml_str,
+                                       "module" : origModuleName,
+                                       "rpc" : origMethodName
+                                       };
+                               $.post("/uploadxml", reqData )
+                                       .done(function( data ) {
+                                       console.log("calling uploadxml. sending to server");
+                                               //var successHtmlStr = "<object width='600' height='450' type='text/html' data='"  + data.url + "' />";
+                                               
+                                               if( data != undefined  && data != null &&  (data.stdout.indexOf('Saving SvcLogicGraph to database') != -1 || data.stderr.indexOf('Saving SvcLogicGraph to database') != -1)){
+                                                       //RED.notify("<strong>Uploaded Successfully</strong>");
+                                                       //console.dir(data);
+                                                       var _moduleName = data.module;
+                                                       var _rpc = data.rpc;
+                                                       var msg = "";
+                                                       var actualMsg = "";
+                                                       var msg_lines = "";
+                                                       msg_lines += data.stderr;
+                                                       msg_lines += data.stdout;
+                                                               
+                                                       msgHtmlStr="<div><p><b>Uploaded the XML.<br>Additional Details<br><textarea style='width:90%;height:100%' readonly='1' rows='10' cols='90' >" + msg_lines + "</textarea></div>";
+                                                               $("#upload-xml-status-dialog").dialog({
+                                                                       modal:true,     
+                                                                       title: "Upload XML ",
+                                                                       width: 900,
+                                                                       height: 750,
+                                                                               minWidth : 600, 
+                                                                               minHeight :450, 
+                                                                       buttons: [
+                                                                               {
+                                                                               text: "ViewDGList",
+                                                                               class:"alertDialogButton",
+                                                                               click: function() {
+                                                                                       $(this).dialog("close");
+                                                                                       displayCurrentDGs(_moduleName,_rpc,function(htmlStr,dbHost){
+                                                                                               $("#svclogicPageDiv").dialog({
+                                                                                               modal:true,     
+                                                                                               title:"Service Logic Administration  Module=" + _moduleName + " and RPC=" + _rpc,
+                                                                                               width: 1200,
+                                                                                               height: 750,
+                                                                                                       minWidth : 600, 
+                                                                                                       minHeight :450, 
+                                                                                               }).html(htmlStr);
+                                                                                       });     
+                                                                                       }
+                                                                               },
+                                                                               {
+                                                                               text: "Close",
+                                                                               class:"alertDialogButton",
+                                                                               click: function() {
+                                                                                       $(this).dialog("close");
+                                                                               }
+                                                                               }
+                                                                               ]
+                                                               }).html(msgHtmlStr);
+                                               }else{
+                                                       console.log("Could not upload.");
+                                                       var emsg =JSON.parse( data.responseText);
+                                                       var msg = "";
+                                                       var actualMsg = "";
+                                                       var msg_lines = "";
+                                                       if( emsg.stderr != "COMPILE_ERROR"){
+                                                               msg = JSON.stringify(emsg.stderr);
+                                                               actualMsg = msg;
+                                                               msg = msg.replace('\\t',"");
+                                                               msg1 = msg.split('\\n');
+                                                               for(var k=0;k<=msg1.length && k<=10;k++){
+                                                                       /*
+                                                                       if(k == 0){
+                                                                               //msg_lines += "<span style='color:blue'>" + msg1[k] + "</span><br>";   
+                                                                               //msg_lines +=  msg1[k]  +"\n";
+                                                                       }else{
+                                                                               if(msg1[k].indexOf("Caused by:") != -1){
+                                                                                       //msg_lines += "<span style='color:red'> " + msg1[k] + "</span><br>";   
+                                                                                       msg_lines += msg1[k] ;
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                                       */
+                                                                       if(msg1[k] != null && msg1[k].indexOf("Caused by:") != -1){
+                                                                               msg_lines +=  msg1[k] ;
+                                                                               if((k+1)<=msg1.length){
+                                                                                       msg_lines +=   "\n" + msg1[k+1] ;
+                                                                               }       
+                                                                               if((k+2)<=msg1.length){
+                                                                                       msg_lines +=   "\n" + msg1[k+2] ;
+                                                                               }       
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       htmlStr="<div><p><b>Could not upload the XML. Status:" + data.status + " Message:" + data.statusText + "</b><br></p><br>Additional Details<br><textarea style='width:90%;height:100%' readonly='1' rows='10' cols='90' >" + msg_lines + "</textarea></div>";
+                                               $("#svclogicPageDiv").dialog({
+                                                       modal:true,     
+                                                       title: "Upload XML ",
+                                                       width: 900,
+                                                       height: 750,
+                                                               minWidth : 600, 
+                                                               minHeight :450, 
+                                               }).html(htmlStr);
+                                               }
+                                       })
+                                       .fail(function(err) {
+                                                //console.log( "error" + JSON.stringify(err) ); 
+                                                //console.log( JSON.stringify(err.responseText)); 
+                                                var emsg =JSON.parse( err.responseText);
+                                                //console.log( emsg.stderr); 
+                                               var msg = "";
+                                               var actualMsg = "";
+                                               var msg_lines = "";
+                                               if( emsg != null &&  emsg.stderr != 'COMPILE_ERROR'){
+                                                       msg = JSON.stringify(emsg.stderr);
+                                                       actualMsg = msg;
+                                                       //msg = msg.replace("Caused by:","<span style='color:red'>Caused by:</span>"); 
+                                                       msg = msg.replace(/\\t/g,"");
+                                                       msg1 = msg.split('\\n');
+                                                       for(var k=0;k<=msg1.length && k<=msg1.length;k++){
+                                                               /*
+                                                               if(k == 0){
+                                                                       //msg_lines += "<span style='color:blue'>" + msg1[k] + "</span><br>";   
+                                                                       //msg_lines +=  msg1[k] + "\n" ;
+                                                               }else{
+                                                                       if(msg1[k].indexOf("Caused by:") != -1){
+                                                                               //msg_lines += "<span style='color:red'> " + msg1[k] + "</span><br>";   
+                                                                               msg_lines +=  msg1[k] ;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                               */
+                                                               if(msg1[k] != null && msg1[k].indexOf("Caused by:") != -1){
+                                                                       msg_lines +=  msg1[k] ;
+                                                                       if((k+1)<=msg1.length){
+                                                                               msg_lines +=   "\n" + msg1[k+1] ;
+                                                                       }       
+                                                                       if((k+2)<=msg1.length){
+                                                                               msg_lines +=   "\n" + msg1[k+2] ;
+                                                                       }       
+                                                                       break;
+                                                               }
+                                                       }
+                                               }else{
+                                                               msg = JSON.stringify(emsg.stdout);
+                                                                actualMsg = msg;
+                                                                msg = msg.replace('\\t',"");
+                                                                msg1 = msg.split('\\n');
+                                                               msg_lines=msg1;
+                                               }
+                                                 var  htmlStr="<div><p><b>Could not upload the XML. Status:" + err.status + " Message:" + err.statusText + "</b><br></p><br><b>Additional Details</b><br><textarea style='width:90%;height:100%' readonly='1' rows='15' cols='90'>" + msg_lines + "</textarea></div>";
+                                               $("#svclogicPageDiv").dialog({
+                                                       modal:true,     
+                                                       title: "Upload XML ",
+                                                       width: 900,
+                                                       height: 750,
+                                                               minWidth : 600, 
+                                                               minHeight :450, 
+                                               }).html(htmlStr);
+                                               //RED.notify("<strong>ERROR:</strong>:" + err,"error");
+                                       }) 
+                                       .always(function() { 
+                                               console.log( "finished" ); 
+                                               target.text("Upload XML");
+                                               target.css({ "background-image": "none" });
+                                       });
+                               /*
+                               d3.xhr("/uploadxml?fileName=" + fileName).post(function(err,resp) {
+                                       if ( resp != null && resp.status == 200) {
+                                               RED.notify("<strong>Uploaded Successfully</strong>");
+                                       }else{
+                                               RED.notify("<strong>ERROR:</strong>:" + err,"error");
+                                               console.log(err);
+                                               //console.dir(resp);
+                                       }
+                               });
+                               */
+                           },
+                           "View DG List": function () {
+
+                                       displayCurrentDGs(origModuleName,origMethodName,function(htmlStr,dbHost){
+                                               //console.log("htmlStr:" + htmlStr);
+                                               $("#svclogicPageDiv").dialog({
+                                                       modal:true,     
+                                                       title: "Service Logic Administration for Module=" + origModuleName + "  and RPC=" + origMethodName, 
+                                                       width: 1200,
+                                                       height: 750,
+                                                               minWidth : 600, 
+                                                               minHeight :450, 
+                                               }).html(htmlStr);
+                                       });     
+                           },
+                           "Download XML": function () {
+                               $(document).ready(function(){
+                                       errList=[];
+                                       if(moduleName != undefined && moduleName != null && moduleName != ""){
+                                               moduleName=moduleName.replace(/\s/g, "_");
+                                       }else{
+                                               errList.push("Module name is required in the service-logic node.");
+                                       }
+
+                                       if(dgVersion == undefined || dgVersion == null || dgVersion == ""){
+                                               errList.push("Module version is required in the service-logic node.");
+                                       }
+
+                                       if(methodName != undefined && methodName != null && methodName != ""){
+                                               methodName=methodName.replace(/\s/g, "_");
+                                               //formattedMethodName=methodName + "_" + dgVersion;
+                                               formattedMethodName=methodName ;
+                                       }else{
+                                               errList.push("rpc name is required in the method node.");
+                                       }
+                                       console.log("Download Xml moduleName:" + moduleName);   
+                                       console.log("Download Xml methodName:" + formattedMethodName);  
+
+                                       if(errList != null && errList.length > 0 ){
+                                               showErrors();
+                                               return;
+                                       }
+
+                                       $("#dwnldXmlFormId").empty().remove();
+                                       //using form to submit
+                                       var form = $('<form id="dwnldXmlFormId" method="POST" action="/downloadXml"></form>');
+                                       form.append('<input id="flowXmlId"  type="hidden" name="flowXml"/>');
+                                       form.append('<input type="hidden" name="moduleName" value="' + moduleName + '"/>');
+                                       form.append('<input type="hidden" name="methodName" value="' + formattedMethodName + '"/>');
+                                       form.appendTo('body');
+                                       //$("#flowXmlId").val(formatted_xml);
+                                       $("#flowXmlId").val(unformatted_xml_str);
+                                       $("#dwnldXmlFormId").submit();
+                                       //console.log("Form submitted.");
+                               });
+                           },
+                           "Download JSON": function () {
+                               $(document).ready(function(){
+                                       errList=[];
+                                       if(moduleName != undefined && moduleName != null && moduleName != ""){
+                                               moduleName=moduleName.replace(/\s/g, "_");
+                                       }else{
+                                               errList.push("Module name is required in the service-logic node.");
+                                       }
+
+                                       if(dgVersion == undefined || dgVersion == null || dgVersion == ""){
+                                               errList.push("Module version is required in the service-logic node.");
+                                       }
+
+                                       if(methodName != undefined && methodName != null && methodName != ""){
+                                               methodName=methodName.replace(/\s/g, "_");
+                                               //formattedMethodName=methodName + "_" + dgVersion;
+                                               formattedMethodName=methodName ;
+                                       }else{
+                                               errList.push("rpc name is required in the method node.");
+                                       }
+                                       console.log("Download Xml moduleName:" + moduleName);   
+                                       console.log("Download Xml methodName:" + formattedMethodName);  
+
+                                       if(errList != null && errList.length > 0 ){
+                                               showErrors();
+                                               return;
+                                       }
+                                       //console.log("formatted_json:" + formatted_json);      
+                                       $("#dwnldJsonFormId").empty().remove();
+                                       //using form to submit
+                                       var form = $('<form id="dwnldJsonFormId" method="POST" action="/downloadJson"></form>');
+                                       form.append('<input id="flowJsonId" type="hidden" name="flowJson" value=""/>');
+                                       form.append('<input type="hidden" name="moduleName" value="' + moduleName + '"/>');
+                                       form.append('<input type="hidden" name="methodName" value="' + formattedMethodName + '"/>');
+                                       form.appendTo('body');
+                                       //$("#flowJsonId").val(formatted_json);
+                                       $("#flowJsonId").val(unformatted_json_str);
+                                       $("#dwnldJsonFormId").submit();
+                                       //console.log("Form submitted.");
+                               });
+                           },
+                           Close: function ()  {
+                               /*
+                               console.log("clearing the variables.");
+                               htmlCode ="";
+                               formatted_json ="";
+                               formatted_xml ="";
+                               xmlLines =[];
+                               unformatted_xml_str="";
+                               unformatted_json_str="";
+                               */
+                              $('.ui-dialog:has(#xmldialog)').empty().remove();
+                               RED.view.redraw();
+
+                               //console.log($("#xmldialog").attr('id'));
+                               //$('.ui-dialog:has(# + $("#xmldialog").attr('id') + ')').empty().remove();
+                                //$("#xmldialog").hide();
+                                //$("#xmldialog").dialog("destroy").remove();
+                       }
+                       },
+                       open:function (){
+                               $(function(){
+                               $("#xmldialog").dialog("widget").find(".ui-dialog-buttonpane").append(xmlInfoStr);
+                                       console.log("opened.");
+                               });
+                       }       
+               }).html(displayHtmlStr).dialog("open");
+               
+               //}).html(displayHtmlStr).dialog("widget").find(".ui-dialog-buttonpane").append(xmlInfoStr);
+
+               //display size and number of lines in XML
+               //$("#xmldialog").dialog("widget").find(".ui-dialog-buttonpane").append(xmlInfoStr);
+
+               //$("#processingStatusId").html("");
+                //This logic is commented as formatting and displaying orion is taking time
+               //START
+               /*
+               var msecs1= Date.now();
+               var that = this;
+               require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('xmldialog'),
+                    lang:"html",
+                   readonly:true,
+                   //showLinesRuler: false,
+                    contents: formatted_xml
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                });
+               var msecs2= Date.now();
+               //console.log("Time taken for displaying XML:" + (msecs2 - msecs1));
+               */
+                //END
+               //var success = customValidation(currentNodeSet);
+               var success = customValidation(nodeSetWithUpdatedDgNumbers);
+               if(!success){
+                       showFlowDesignErrorBox();
+               }
+               $('#processingStatusId').html("");
+               }, 0);
+            }
+        }
+
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgemain/dgstart.js b/dgbuilder/nodes/dge/dgemain/dgstart.js
new file mode 100644 (file)
index 0000000..f2b4815
--- /dev/null
@@ -0,0 +1,594 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+    //var dgxml=require("/home/users/schinthakayala/nodered/sheshi/dgxml/dgxml2");
+    var _=require('lodash');
+    var fs=require('fs');
+    var path = require('path');
+    var appDir = path.dirname(require.main.filename);
+    var userDir = appDir + "/" + RED.settings.userDir;
+    var dbHost = RED.settings.dbHost;
+    var request = require('request');
+    var sharedDir = appDir + "/" + RED.settings.sharedDir;
+    var xmlDir = appDir + "/" + RED.settings.xmlPath;
+
+    //console.log("appDir:" + appDir);
+    //var dgeraw=fs.readFileSync(appDir + "/dge.json").toString();
+    //var dgejson=JSON.parse(dgeraw);
+    //var uploadUrl=dgejson.slaHost + dgejson.uploadUrl;
+    //var slaUrl=dgejson.slaHost + dgejson.slaUrl;
+    //var uploadUrl=RED.settings.slaHost +  RED.settings.uploadUrl;
+    //var slaUrl=RED.settings.slaHost + RED.settings.slaUrl;
+    var uploadUrl="";
+    var slaUrl="";
+    //console.log("Upload url: " + uploadUrl);
+
+    function dgstart(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.topic = n.topic;
+    }
+
+    function writeHtmlToFile(fileName,str){
+      var localfile = appDir + "/" + RED.settings.htmlPath + fileName;
+       try{
+          fs.writeFileSync(localfile,str);
+       }catch(e){
+               console.log("Error:" + e);
+       }
+    }   
+
+    function writeXmlToFile(fileName,str){
+      var localfile = appDir + "/" + RED.settings.xmlPath + fileName;
+       try{
+          fs.writeFileSync(localfile,str);
+       }catch(e){
+               console.log("Error:" + e);
+       }
+    }   
+
+    function sendXml(fileName,res) {
+      var needle, localfile, data;
+      needle = require('needle')
+      localfile = appDir + "/" + RED.settings.xmlPath + fileName;
+       console.log("localfile:" + localfile);
+      data={
+        uploadedfile: { file: localfile, content_type: 'text/xml' }
+      }
+      needle.post(uploadUrl, data, { multipart: true }, function(err, resp, body) {
+        //console.log(body)
+       if(resp != undefined && resp != null){
+               console.log("resp Code for sendXml:" + resp.statusCode);
+       }
+       fs.unlink(localfile, function (error) {
+           if (error) {
+                console.log("Error deleting file "+localfile);
+          }else{
+                //console.log("deleted file:" + localfile);
+          }    
+       });
+
+       if(err){
+               console.log("Error posting to slaUrl:" + slaUrl);       
+               console.log("Error:" +err);
+               res.json({"error":err});
+       }else{
+               //console.dir(resp);
+               //console.log("slaUrl:" + slaUrl);      
+               res.json({"url":slaUrl});
+        }
+
+      });
+    }   
+
+    function oldsendXml(fileName) {
+      console.log("In sendXML for file: " + fileName);
+      var fileStream, formdata, localfile;
+      localfile = appDir + "/" + RED.settings.xmlPath + fileName;
+
+      formdata = {
+        MAX_FILE_SIZE: "100000",
+        uploadedfile: {
+          options: {
+            contentType: 'audio/mpeg'
+          }
+        }
+
+      };
+
+      console.log("Attempting to upload file: " + localfile);
+      console.log("Sending to: " + uploadUrl);
+      formdata.uploadedfile.value = fs.createReadStream(localfile);
+      fileStream = formdata.uploadedfile.value;
+
+//console.log("Formdata:");
+//console.dir(formdata);
+
+      request.post({
+        url: uploadUrl,
+        proxy: false,
+        formData: formdata
+        }, function(err, resp, body) {
+        fileStream.close();
+        console.log("err: " + err);
+        return console.log("body: " + body);
+      });
+
+    };
+
+    RED.nodes.registerType("dgstart",dgstart);
+/*
+    RED.httpAdmin.post("/uploadxml", function(req,res) {
+       console.dir(req);
+       console.log("USER:" + req.user);
+      console.log("Got request to upload xml to SDN-C.");
+      console.log("Requested filename to upload: " + req.params.fileName);
+      console.log("Requested xml to upload: " + req.params.xmlStr);
+       writeToFile( req.params.fileName,req.params.xmlStr);
+       
+      sendXml(req.params.fileName,res);
+      // res.send("Attempt complete.");
+      // res.redirect(slaUrl);
+    });
+*/
+
+    RED.httpAdmin.post("/OldUploadxml", function(req,res) {
+       //console.dir(req);
+       //console.log("USER:" + req.user);
+       var qs = require('querystring');
+       var body = '';
+        req.on('data', function (data) {
+            body += data;
+            // Too much POST data, kill the connection!
+            /*if (body.length > 1e6)
+                request.connection.destroy();
+               */
+        });
+        req.on('end', function () {
+               //console.log("BODY:" + body);
+               var d = new Date().getTime();
+               var user = req.user;
+               var fileName= user + "_" + d +".xml";
+               var post = qs.parse(body);
+               //console.log(JSON.stringify(post));
+            // use post['blah'], etc.
+               var localfile = appDir + "/" + RED.settings.xmlPath + fileName;
+               //console.log("localfile:" + localfile);        
+               var xmlStr = post['flowXml'];
+               writeXmlToFile(fileName,xmlStr);
+               sendXml(fileName,res);
+               
+            });
+
+        });
+
+    RED.httpAdmin.post("/uploadxml", function(req,res) {
+       //console.dir(req);
+       //console.log("USER:" + req.user);
+       var qs = require('querystring');
+       var body = '';
+        req.on('data', function (data) {
+            body += data;
+            // Too much POST data, kill the connection!
+            /*if (body.length > 1e6)
+                request.connection.destroy();
+               */
+        });
+        req.on('end', function () {
+               //console.log("BODY:" + body);
+               var d = new Date().getTime();
+               var user = req.user;
+               var fileName= user + "_" + d +".xml";
+               var post = qs.parse(body);
+               //console.log(JSON.stringify(post));
+            // use post['blah'], etc.
+               var localfile = appDir + "/" + RED.settings.xmlPath + fileName;
+               //console.log("localfile:" + localfile);        
+               var xmlStr = post['flowXml'];
+               var moduleName = post['module'];
+               var rpc = post['rpc'];
+               writeXmlToFile(fileName,xmlStr);
+               uploadDG(localfile,moduleName,rpc,res);
+            });
+
+        });
+
+
+function uploadDG(filePath,moduleName,rpc,res){
+       console.log("called uploadDG...");
+       var exec = require('child_process').exec;
+       var commandToExec = appDir + "/svclogic/svclogic.sh load " + filePath + " " + userDir + "/conf/svclogic.properties";
+       console.log("commandToExec:" + commandToExec);
+        var child = exec(commandToExec ,function (error,stdout,stderr){
+               //console.log(error);
+               console.log("stdout:" + stdout);
+               console.log("stderr:" +  stderr);
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr});
+                       }else{
+                               res.send(500,{'error':error});
+                       }
+                       //console.log("stdout :" + stdout);
+                }else{
+                       if(stdout ){
+                               //console.log("output:" + stdout);
+                               if(stdout.indexOf('Compiler error') != -1){
+                                       //console.log("compileError occured.");
+                                       
+                                       var resp = {
+                                                       'stdout':stdout,
+                                                       'stderr':"COMPILE_ERROR",
+                                                       'url':dbHost,
+                                                       'module':moduleName,
+                                                       'rpc':rpc
+                                                  }            
+                                       res.send(500,resp);
+                               }else{
+                                       res.send(200,{'stdout':stdout,'stderr':stderr,"url":dbHost,"module" : moduleName,"rpc" : rpc});
+                               }
+                       }
+                       if(stderr && !stdout){
+                               //console.log("stderr:" + stderr);
+                               if(stderr.indexOf("Saving SvcLogicGraph to database") != -1){
+                                       res.send(200,{'error':error,'stdout' :'','stderr':stderr,"url":dbHost,"module" : moduleName,"rpc" : rpc});
+                               }else{
+                                       res.send(500,{'error':error,'stdout' :'','stderr':stderr});
+                               }
+                       }
+               }
+       });
+}
+
+    RED.httpAdmin.get("/displayXml", function(req,res) {
+                       var _module = req.query._module;
+                       var rpc = req.query.rpc;
+                       var version = req.query.version;
+                       var mode = req.query.mode;
+                       var d = new Date().getTime();
+                       displayXml(_module,rpc,version,mode,res);
+            });
+
+function displayXml(_module,rpc,version,mode,res){
+       var exec = require('child_process').exec;
+       var msg = {
+               '_module' : _module,
+               'rpc' : rpc,
+               'version' : version,
+               'mode' : mode
+       }
+       var commandToExec = appDir + "/svclogic/svclogic.sh get-source "   + _module + " " 
+                               + rpc + " " + mode + " " + version + " " + userDir + "/conf/svclogic.properties";
+       console.log("commandToExec:" + commandToExec);
+        var child = exec(commandToExec ,{'maxBuffer':16*1024*1024},function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr,'msg':msg});
+                       }else{
+                               res.send(500,{'error':error,'msg':msg});
+                       }
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                       }
+                       if(stdout){
+                               res.send({'xmldata' : "<xmp>" + stdout + "</xmp>"});
+                       }
+               }
+       });
+}
+
+
+    RED.httpAdmin.post("/downloadDGXml", function(req,res) {
+               //console.dir(req);
+               var qs = require('querystring');
+               var body = '';
+               req.on('data', function (data) {
+                       body += data;
+               });
+
+               req.on('end', function () {
+                       var post = qs.parse(body);
+                       var _module = post._module;
+                       var rpc = post.rpc;
+                       var version = post.version;
+                       var mode = post.mode;
+                       var d = new Date().getTime();
+                       downloadDGXml(_module,rpc,version,mode,res);
+               });
+            });
+
+function downloadDGXml(_module,rpc,version,mode,res){
+       var exec = require('child_process').exec;
+       var msg = {
+               '_module' : _module,
+               'rpc' : rpc,
+               'version' : version,
+               'mode' : mode
+       }
+       var commandToExec = appDir + "/svclogic/svclogic.sh get-source "   + _module + " " 
+                               + rpc + " " + mode + " " + version + " " + userDir + "/conf/svclogic.properties";
+       console.log("commandToExec:" + commandToExec);
+        var child = exec(commandToExec ,function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr,'msg':msg});
+                       }else{
+                               res.send(500,{'error':error,'msg':msg});
+                       }
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                       }
+                       if(stdout){
+                               //console.log("output:" + stdout);
+                               //var newOutput = "<pre>" + stdout.replace(/\n/g,'<br>') + "</pre>";
+                               //res.json({'stdout': stdout ,'stderr':stderr,"msg":msg});
+                               //res.set('Content-Type', 'text/xml');
+                               //res.set('Content-Type', 'application/octet-stream');
+                               //res.end("<code>" + stdout + "</code>" ); 
+                               //var newOutput ="<html><body>" + stdout  + "</body></html>";
+                               //res.send(new Buffer( "<code>" +  newOutput + "</code>" ) ); 
+                               //res.send(newOutput); 
+
+                               /*
+                               var xslStr = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' +
+                                       '<xsl:output omit-xml-declaration="yes" indent="yes"/>' + 
+                                       '<xsl:template match="node()|@*">' +
+                                       '<xsl:copy>' +
+                                       '<xsl:apply-templates select="node()|@*"/>' +
+                                       '</xsl:copy>' +
+                                       '</xsl:template>' +
+                                       '</xsl:stylesheet>';
+                               */
+
+                               var formatted_date = getCurrentDate();
+                               var fileName= "db_" + _module + "_" +rpc+ "_" + version + "_" +  formatted_date + ".html";
+                               var file = xmlDir + "/" + fileName;
+                               var xmlStr = '<xmp>' + stdout + "</xmp>";
+                               //var xmlStr =  "<![CDATA[" + stdout + "]]";
+                               //var xmlStr =   stdout.replace(/</g,"&lt;");
+                               //xmlStr =   xmlStr.replace(/>/g,"&gt;");
+                               //xmlStr =   xmlStr.replace(/\n>/g,"<br>");
+                               //xmlStr =   xmlStr.replace(/\t>/g,"&nbsp;&nbsp;&nbsp;");
+               
+                               writeToFile(file,"<html><body>" +xmlStr+ "</body></html>");
+                               //console.log("xmlStr:" + xmlStr);
+                               res.setHeader('Content-disposition', 'attachment; filename=' + file);
+                               //res.setHeader('Content-type', 'text/html');
+                               res.setHeader('Content-type', 'text/xml');
+                               res.download(file);
+                       }
+               }
+       });
+}
+
+
+    RED.httpAdmin.get("/displayAsGv", function(req,res) {
+               var _module = req.query._module;
+               var rpc = req.query.rpc;
+               var version = req.query.version;
+               var mode = req.query.mode;
+               var d = new Date().getTime();
+               displayAsGv(_module,rpc,version,mode,res);
+            });
+
+function displayAsGv(_module,rpc,version,mode,res){
+       var exec = require('child_process').exec;
+       var msg = {
+               '_module' : _module,
+               'rpc' : rpc,
+               'version' : version,
+               'mode' : mode
+       }
+       var commandToExec = appDir + "/svclogic/svclogic.sh print " +
+                _module + " " + rpc + " " + mode + " " + version + " "
+           //+ userDir + "/conf/svclogic.properties | dot -Tpng ";
+                               //the label="""" is giving an error so replacing it with "null" 
+           + userDir + "/conf/svclogic.properties |sed -e 's%label=\"\"\"\"%label=\"null\"%g'| dot -Tsvg ";
+       console.log("commandToExec:" + commandToExec);
+           //+ userDir + "/conf/svclogic.properties | dot -Tsvg ";
+        //var child = exec(commandToExec ,function (error,stdout,stderr){
+        //var child = exec(commandToExec ,{maxBuffer:16*1024*1024},function (error,stdout,stderr){
+        //var child = exec(commandToExec ,{encoding:'base64',maxBuffer:20*1024*1024},function (error,stdout,stderr){
+        var child = exec(commandToExec ,{maxBuffer:20*1024*1024},function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr,"msg":msg});
+                       }else{
+                               res.send(500,{'error':error,"msg":msg});
+                       }
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                               //To convert base64 to ascii
+                               //console.log(new Buffer(stderr, 'base64').toString('ascii'));
+                       }
+                       if(stdout){
+                               //console.log(stdout.length);
+                               //console.log("output:" + stdout);
+                               //var svg_html =  stdout ;
+                               //var image = "<img src='data:image/png;base64," + stdout + "'>";
+                               //var image = "<iframe width='1200' height='750' src='data:image/png;base64," + stdout + "'></frame>";
+                               //var image = "<iframe width='1200' height='750' src='data:image/svg+xml;base64," + stdout + "'></frame>";
+                               //var image = "<iframe width='1200' height='750' src='data:image/gif;base64," + stdout + "'></frame>";
+                               var image = "<iframe width='1200' height='750' src='data:image/svg+xml;UTF-8," + stdout + "'></frame>";
+                               //console.log(image);
+                               res.send({'svg_html':image});
+                       }
+               }
+       });
+}
+
+    RED.httpAdmin.post("/shareFlow", function(req,res) {
+       //console.dir(req);
+       //console.log("USER:" + req.user);
+       var qs = require('querystring');
+       var body = '';
+        req.on('data', function (data) {
+            body += data;
+            // Too much POST data, kill the connection!
+            /*if (body.length > 1e6)
+                request.connection.destroy();
+               */
+        });
+        req.on('end', function () {
+               var post = qs.parse(body);
+               
+               var nodeSet = JSON.parse(post['flowData']);
+               var activeWorkspace=post['activeWorkspace'];
+               var methodName = "";
+               var moduleName = "";
+               for(var i=0;nodeSet != null && i<nodeSet.length;i++){
+                       var node = nodeSet[i];  
+                       if(node.type == 'module' ){
+                               moduleName= node.name;
+                               moduleName=moduleName.replace(/ /g,"-");
+                       }
+                       if(node.type == 'method' ){
+                               methodName= node.name;
+                               methodName=methodName.replace(/ /g,"-");
+                       }
+               }
+               //console.log("BODY:" + body);
+               var d = new Date().getTime();
+               var user = req.user;
+               var fileName= moduleName + "_" +methodName+".json";
+               var localfile = sharedDir + "/" + fileName;
+               //console.log("localfile:" + localfile);        
+               
+               writeToFile(localfile,JSON.stringify(nodeSet));
+               res.send({"fileName": fileName}); 
+            });
+
+        });
+
+
+    RED.httpAdmin.post("/sendEmail", function(req,res) {
+       //console.dir(req);
+       console.log("USER:" + req.user);
+        var fromAddr = RED.settings.emailAddress;
+        var toAddr =  RED.settings.emailAddress;
+       var qs = require('querystring');
+       var body = '';
+        req.on('data', function (data) {
+            body += data;
+            // Too much POST data, kill the connection!
+            /*if (body.length > 1e6)
+                request.connection.destroy();
+               */
+        });
+        req.on('end', function () {
+               //console.log("BODY:" + body);
+               var d = new Date().getTime();
+               var user = req.user;
+               var fileName= user + "_" + d +".html";
+               var post = qs.parse(body);
+               //console.log(JSON.stringify(post));
+            // use post['blah'], etc.
+               var localfile = appDir + "/" + RED.settings.htmlPath + fileName;
+               //console.log("localfile:" + localfile);        
+               var nodemailer = require("nodemailer");
+               nodemailer.sendmail = true;
+               var transporter = nodemailer.createTransport();
+               var ua = req.headers['user-agent'];
+                       var host = req.headers.host;
+               var fullHtml="<!doctype html><html><head>" + post['flowHtml'];
+                       //fullHtml+="<div style='fill:both'></div>";
+                       fullHtml+="<div style='margin-left:10px;'><p>XML</p><br><textarea rows='50' cols='150'>" + post['flowXml'] + "</textarea>";
+                       fullHtml+="<p>JSON</p><br><textarea rows='50' cols='150'>" + post['flowJson'] + "</textarea></div>";
+                       fullHtml+="</body></html>";
+               writeHtmlToFile(fileName,fullHtml);
+               
+               transporter.sendMail({
+                       from: fromAddr,
+                       to: toAddr,
+                       html: "<p>DG Node Flow. click on the attachment to view</p>",
+                       subject: 'Node flow from  Host:<' + host + '>',
+                       attachments : [{'filename': fileName,
+                                       'contentType': "text/html",
+                                       /*'filePath': localfile*/
+                                       'content': fs.createReadStream(localfile)
+                                     }]
+
+            }, function(err, response) {
+                       var fullPathtoFileName = appDir + "/" + RED.settings.htmlPath + fileName;
+               fs.unlink(fullPathtoFileName, function (error) {
+                       if (error) {
+                               console.log("Error deleting file "+fullPathtoFileName);
+                       }else{
+                               //console.log("deleted file:" + fullPathtoFileName);
+                       }       
+               });
+
+                if(err){
+                       console.log("Error:" + err);
+                       res.json(err);
+                }else{
+                       res.json(response);
+               }
+               console.log(response);
+            });
+
+        });
+
+               
+       });
+/*
+    RED.httpAdmin.post("/doxml/:id", function(req,res) {
+            var node = RED.nodes.getNode(req.params.id);
+            if (node != null) {
+                try {
+                    // node.receive();
+                    //console.log("doxml was called for node: ");
+                    //console.dir(node);
+                    //console.log("calling getJson");
+                    var nrjson=dgxml.getJson();
+                    console.log("calling nodered2xml");
+                    var results=[];
+                    results=dgxml.nodered2xml(nrjson,node.id);
+                    var nrxml=results[0];
+                    fileName=results[1];
+                    console.log("Got this filename: " + fileName);
+                    // res.send(200);
+                    console.log("appDir: " + appDir);
+                    fs.writeFileSync(appDir + "/public/xml/"+fileName,nrxml);
+                    // res.send("XML generated! See help on right for link.");
+                    res.send(fileName);
+                } catch(err) {
+                    res.send(500);
+                    node.error("doxml failed:"+err);
+                    console.log(err.stack);
+                }
+            } else {
+                res.send(404);
+            }
+    });
+*/
+}
diff --git a/dgbuilder/nodes/dge/dgemain/method.html b/dgbuilder/nodes/dge/dgemain/method.html
new file mode 100644 (file)
index 0000000..134896e
--- /dev/null
@@ -0,0 +1,141 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="method">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show RPCs</b></a>
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+<script type="text/x-red" data-help-name="method">
+       <p>A method node.</p>
+       <p>Name can be anything.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('method',{
+        color:"#fdd0a2",
+        category: 'DGEmain',
+        defaults: {
+            name: {value:"method"},
+            xml: {value:"<method rpc='' mode='sync'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               //console.log("show Values clicked.");
+                               showRpcsValuesBox(that.editor,rpcValues);
+               });
+
+            });
+
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgemain/method.js b/dgbuilder/nodes/dge/dgemain/method.js
new file mode 100644 (file)
index 0000000..6a29bd8
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function method(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("method",method);
+    // RED.library.register("method");
+}
diff --git a/dgbuilder/nodes/dge/dgemain/serviceLogic.html b/dgbuilder/nodes/dge/dgemain/serviceLogic.html
new file mode 100644 (file)
index 0000000..ca8ac8c
--- /dev/null
@@ -0,0 +1,125 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="service-logic">
+    <div class="form-row">
+        <!--<label for="node-input-name"><i class="fa"></i> Name</label>-->
+        <input type="hidden" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <input type="hidden" id="node-input-xml">
+        <label for="node-input-module"><i class="fa"></i>Module</label>
+        <input type="text" id="node-input-module" autofocus="autofocus">
+        <label for="node-input-version"><i class="fa"></i>Version</label>
+        <input type="text" id="node-input-version">
+        <input type="hidden" id="node-input-comments">
+        <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    </div>
+    <!--<div class="form-tips">See the Info tab for help using this node.</div>-->
+</script>
+
+<script type="text/x-red" data-help-name="service-logic">
+       <p>A service-logic node.</p>
+       <p>Double click the node to configure the module name and the version</p>
+
+</script>
+
+<script type="text/javascript">
+    RED.nodes.registerType('service-logic',{
+        color:"#fdd0a2",
+        category: 'DGEmain',
+        defaults: {
+            name: {value:"service-logic"},
+            module: {value:""},
+            version: {value:""},
+           comments:{value:""},        
+            xml: {value:"<service-logic xmlns='http://www.onap.org/sdnc/svclogic' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://www.onap.org/sdnc/svclogic ./svclogic.xsd' module='' version=''>\n"},
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                //$("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+
+            $("#node-input-module").focus(); 
+
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+               var module = $("#node-input-module").val();
+               if(module == null){
+                       module='';
+               }
+               var version = $("#node-input-version").val();
+               if(version == null){
+                       version='';
+               }
+               console.log("module:" + module);
+               console.log("version:" + version);
+               //xmlStr= xmlStr.replace("$MODULE",module);
+               //xmlStr= xmlStr.replace("$VERSION",version);
+               var xmlVal = "<service-logic xmlns='http://www.onap.org/sdnc/svclogic' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://www.onap.org/sdnc/svclogic ./svclogic.xsd' module='" + module + "' version='" + version +  "'>"
+               $("#node-input-xml").val(xmlVal);
+               if(module == "" || version == ""){
+                       this.status = {fill:"red",shape:"dot",text:"Not configured"};
+               }else{
+                       this.status = {fill:"green",shape:"dot",text:"configured"};
+                       $("#node-input-name").val(module + " " + version);
+               }
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgemain/serviceLogic.js b/dgbuilder/nodes/dge/dgemain/serviceLogic.js
new file mode 100644 (file)
index 0000000..a5e77e4
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function serviceLogic(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("service-logic",serviceLogic);
+    // RED.library.register("service-logic");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/already-active.html b/dgbuilder/nodes/dge/dgeoutcome/already-active.html
new file mode 100644 (file)
index 0000000..914bda1
--- /dev/null
@@ -0,0 +1,144 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="already-active">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="already-active">
+       <p>A already-active outcome.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('already-active',{
+        color: "#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"already-active"},
+            xml: {value:"<outcome value='already-active'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/already-active.js b/dgbuilder/nodes/dge/dgeoutcome/already-active.js
new file mode 100644 (file)
index 0000000..f6ab4fa
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function alreadyActive(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("already-active",alreadyActive);
+    // RED.library.register("already-active");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/failure.html b/dgbuilder/nodes/dge/dgeoutcome/failure.html
new file mode 100644 (file)
index 0000000..cabfab4
--- /dev/null
@@ -0,0 +1,142 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="failure">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="failure">
+       <p>A failure outcome.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('failure',{
+        color:"#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"failure"},
+            xml: {value:"<outcome value='failure'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/failure.js b/dgbuilder/nodes/dge/dgeoutcome/failure.js
new file mode 100644 (file)
index 0000000..5abd1b7
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function failure(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("failure",failure);
+    // RED.library.register("failure");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/not-found.html b/dgbuilder/nodes/dge/dgeoutcome/not-found.html
new file mode 100644 (file)
index 0000000..0b6bb8f
--- /dev/null
@@ -0,0 +1,142 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="not-found">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="not-found">
+       <p>A not-found outcome.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('not-found',{
+        color: "#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"not-found"},
+            xml: {value:"<outcome value='not-found'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/not-found.js b/dgbuilder/nodes/dge/dgeoutcome/not-found.js
new file mode 100644 (file)
index 0000000..80e10af
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function notFound(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("not-found",notFound);
+    // RED.library.register("not-found");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/other.html b/dgbuilder/nodes/dge/dgeoutcome/other.html
new file mode 100644 (file)
index 0000000..7ceb2e7
--- /dev/null
@@ -0,0 +1,143 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="other">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="other">
+       <p>A other outcome.</p>
+       <p>Name can be anything.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('other',{
+        color: "#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"other"},
+            xml: {value:"<outcome value='Other'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/other.js b/dgbuilder/nodes/dge/dgeoutcome/other.js
new file mode 100644 (file)
index 0000000..97bad48
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function other(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("other",other);
+    // RED.library.register("other");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcome.html b/dgbuilder/nodes/dge/dgeoutcome/outcome.html
new file mode 100644 (file)
index 0000000..122f7d3
--- /dev/null
@@ -0,0 +1,143 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="outcome">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="outcome">
+       <p>A generic outcome node.</p>
+       <p>Use this node if you do not have a outcome value node in the node panel.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('outcome',{
+        color:"#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"outcome"},
+            xml: {value:"<outcome value=''>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcome.js b/dgbuilder/nodes/dge/dgeoutcome/outcome.js
new file mode 100644 (file)
index 0000000..33513e4
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function outcome(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("outcome",outcome);
+    // RED.library.register("outcome");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.html b/dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.html
new file mode 100644 (file)
index 0000000..d104420
--- /dev/null
@@ -0,0 +1,143 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="outcomeFalse">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="outcomeFalse">
+       <p>A false outcome.</p>
+       <p>Name can be anything.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('outcomeFalse',{
+        color:"#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"false"},
+            xml: {value:"<outcome value='false'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.js b/dgbuilder/nodes/dge/dgeoutcome/outcomeFalse.js
new file mode 100644 (file)
index 0000000..f4a9a77
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function outcomeFalse(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("outcomeFalse",outcomeFalse);
+    // RED.library.register("success");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.html b/dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.html
new file mode 100644 (file)
index 0000000..a080bbf
--- /dev/null
@@ -0,0 +1,142 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="outcomeTrue">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+    <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="outcomeTrue">
+       <p>A true outcome.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('outcomeTrue',{
+        color:"#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"true"},
+            xml: {value:"<outcome value='true'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.js b/dgbuilder/nodes/dge/dgeoutcome/outcomeTrue.js
new file mode 100644 (file)
index 0000000..f27310e
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function outcomeTrue(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("outcomeTrue",outcomeTrue);
+    // RED.library.register("success");
+}
diff --git a/dgbuilder/nodes/dge/dgeoutcome/success.html b/dgbuilder/nodes/dge/dgeoutcome/success.html
new file mode 100644 (file)
index 0000000..347d7d6
--- /dev/null
@@ -0,0 +1,141 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="success">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="success">
+       <p>A success outcome.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('success',{
+        color:"#ffccff",
+        category: 'DGEoutcome',
+        defaults: {
+            name: {value:"success"},
+            xml: {value:"<outcome value='success'>\n"},
+           comments:{value:""},        
+            outputs: {value:1}
+        },
+        inputs:1,
+        outputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+            $( "#node-input-outputs" ).spinner({
+                min:1
+            });
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgeoutcome/success.js b/dgbuilder/nodes/dge/dgeoutcome/success.js
new file mode 100644 (file)
index 0000000..4dbafbf
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function success(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("success",success);
+    // RED.library.register("success");
+}
diff --git a/dgbuilder/nodes/dge/dgereturn/returnFailure.html b/dgbuilder/nodes/dge/dgereturn/returnFailure.html
new file mode 100644 (file)
index 0000000..60ab229
--- /dev/null
@@ -0,0 +1,170 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="returnFailure">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="returnFailure">
+       <p>A returnFailure node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Return_node"></a>Return node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>return</b> node is used to return a status to the invoking MD-SAL application</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>status</b></td>
+<td align="left">Status value to return (<i>failure</i>)</td></tr></table></div>
+<div class="section">
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>The following optional parameters may be passed to convey more detailed status information.</p>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>error-code</b></td>
+<td align="left">A brief, usually numeric, code indicating the error condition</td></tr>
+<tr class="b">
+<td align="center"><b>error-message</b></td>
+<td align="left">A more detailed error message</td></tr></table></div>
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Not applicable. The <b>status</b> node has no outcomes.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;return status=&quot;failure&quot;&gt;
+  &lt;parameter name=&quot;error-code&quot; value=&quot;1542&quot; /&gt;
+  &lt;parameter name=&quot;error-message&quot; value=&quot;Activation failure&quot; /&gt;
+&lt;/return&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+    RED.nodes.registerType('returnFailure',{
+        color:"#ED0819",
+        category: 'DGEreturn',
+        defaults: {
+            name: {value:"return failure"},
+            xml: {value:"<return status='failure'>\n<parameter name='error-code' value='' />\n<parameter name='error-message' value='' />\n"},
+           comments:{value:""}
+        },
+        inputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgereturn/returnFailure.js b/dgbuilder/nodes/dge/dgereturn/returnFailure.js
new file mode 100644 (file)
index 0000000..da9fc74
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function returnFailure(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+    RED.nodes.registerType("returnFailure",returnFailure);
+    // RED.library.register("returnFailure");
+}
diff --git a/dgbuilder/nodes/dge/dgereturn/returnSuccess.html b/dgbuilder/nodes/dge/dgereturn/returnSuccess.html
new file mode 100644 (file)
index 0000000..e2d50f3
--- /dev/null
@@ -0,0 +1,174 @@
+<!--
+  Copyright 2013 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<script type="text/x-red" data-template-name="returnSuccess">
+    <div class="form-row">
+        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
+        <input type="text" id="node-input-name" placeholder="Name">
+    </div>
+    <div class="form-row">
+        <label for="node-input-xml"><i class="fa fa-wrench"></i> Node XML</label>
+        <input type="hidden" id="node-input-xml" autofocus="autofocus">
+        <div style="height: 450px;" class="node-text-editor" id="node-input-xml-editor" onkeyup="resetStatus()" ></div>
+    </div>
+    <div class="form-row">
+    <a href="#" class="btn btn-mini" id="node-input-validate" style="margin-top: 4px;"><b>Validate XML</b></a>
+     <a href="#" class="btn btn-mini" id="node-input-show-sli-values" style="margin-top: 4px;"><b>Show Values</b></a> 
+    <input type="hidden" id="node-input-comments">
+    <a href="#" class="btn btn-mini" id="node-input-btnComments" style="margin-top: 4px;"><b>Add Comments</b></a>
+    <div id="node-validate-result" class="form-tips" style="float:right;font-size:10px"></div>
+    </div>
+    <div class="form-tips">See the Info tab for help using this node.</div>
+</script>
+
+<script type="text/x-red" data-help-name="returnSuccess">
+       <p>A returnSuccess node.</p>
+       <p>First line of XML must contain opening tag.</p>
+       <p>Do not include closing tag - it will be automatically generated.</p>
+
+<div class="section">
+<h4><a name="Return_node"></a>Return node</h4>
+<div class="section">
+<h5><a name="Description"></a>Description</h5>
+<p>A <b>return</b> node is used to return a status to the invoking MD-SAL application</p></div>
+<div class="section">
+<h5><a name="Attributes"></a>Attributes</h5>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>status</b></td>
+<td align="left">Status value to return (<i>success</i>)</td></tr></table></div>
+<div class="section">
+<!--
+<h5><a name="Parameters"></a>Parameters</h5>
+<p>The following optional parameters may be passed to convey more detailed status information.</p>
+<table border="1" class="table table-striped">
+<tr class="a">
+<td align="center"><b>error-code</b></td>
+<td align="left">A brief, usually numeric, code indicating the error condition</td></tr>
+<tr class="b">
+<td align="center"><b>error-message</b></td>
+<td align="left">A more detailed error message</td></tr></table></div>
+-->
+<div class="section">
+<h5><a name="Outcomes"></a>Outcomes</h5>
+<p>Not applicable. The <b>status</b> node has no outcomes.</p></div>
+<div class="section">
+<h5><a name="Example"></a>Example</h5>
+<div class="source">
+<pre>&lt;return status=&quot;success&quot;&gt;
+    &lt;parameter name=&quot;uni-circuit-id&quot; value=&quot;$asePort.uni_circuit_id&quot; />
+&lt;/return&gt;</pre></div></div></div>
+
+</script>
+
+
+<script type="text/javascript">
+
+    RED.nodes.registerType('returnSuccess',{
+        color:"#9AE767",
+        category: 'DGEreturn',
+        defaults: {
+            name: {value:"return success"},
+            xml: {value:"<return status='success'>\n<parameter name='' value='' />\n",required:true},
+           comments:{value:""} 
+        },
+        inputs:1,
+        icon: "arrow-in.png",
+        label: function() {
+            return this.name;
+        },
+        oneditprepare: function() {
+
+
+            var comments = $( "#node-input-comments").val();
+            if(comments != null){
+               comments = comments.trim();
+               if(comments != ''){
+                       $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+               }
+            }
+
+            function functionDialogResize(ev,ui) {
+                $("#node-input-xml-editor").css("height",(ui.size.height-275)+"px");
+            };
+
+            $( "#dialog" ).dialog( "option", "width", 1200 );
+            $( "#dialog" ).dialog( "option", "height", 750 );
+            $( "#dialog" ).on("dialogresize", functionDialogResize);
+            $( "#dialog" ).one("dialogopen", function(ev) {
+                var size = $( "#dialog" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+            });
+
+           /* close dialog when ESC is pressed and released */ 
+            $( "#dialog" ).keyup(function(event){
+               if(event.which == 27 ) {
+                       $("#node-dialog-cancel").click();
+               }
+           }); 
+
+
+            $( "#dialog" ).one("dialogclose", function(ev,ui) {
+                var height = $( "#dialog" ).dialog('option','height');
+                $( "#dialog" ).off("dialogresize",functionDialogResize);
+            });
+
+            var that = this;
+            require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('node-input-xml-editor'),
+                    lang:"html",
+                    contents: $("#node-input-xml").val()
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                $("#node-input-name").focus();
+               $("#node-input-validate").click(function(){
+                               console.log("validate clicked.");
+                               //console.dir(that.editor);
+                               //console.log("getText:" + that.editor.getText());
+                               var val = that.editor.getText();
+                               validateXML(val); 
+               });
+               $("#node-input-show-sli-values").click(function(){
+                               console.log("SLIValues clicked.");
+                               showValuesBox(that.editor,sliValuesObj);
+               });
+            });
+           //for click of add comments button
+           $("#node-input-btnComments").click(function(e){
+                       showCommentsBox();
+           }); 
+
+        },
+        oneditsave: function() {
+            $("#node-input-xml").val(this.editor.getText());
+               var resp=validateXML(this.editor.getText());
+               if(resp){
+                       this.status = {fill:"green",shape:"dot",text:"OK"};
+               }else{
+                       this.status = {fill:"red",shape:"dot",text:"ERROR"};
+               }       
+               delete this.editor;
+        }
+    });
+</script>
diff --git a/dgbuilder/nodes/dge/dgereturn/returnSuccess.js b/dgbuilder/nodes/dge/dgereturn/returnSuccess.js
new file mode 100644 (file)
index 0000000..d6c41c9
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var util = require("util");
+    var vm = require("vm");
+
+    function returnSuccess(n) {
+        RED.nodes.createNode(this,n);
+        this.name = n.name;
+        this.xml = n.xml;
+        this.topic = n.topic;
+    }
+
+
+    RED.nodes.registerType("returnSuccess",returnSuccess);
+    // RED.library.register("ret-success");
+}
diff --git a/dgbuilder/package.json b/dgbuilder/package.json
new file mode 100644 (file)
index 0000000..64114b3
--- /dev/null
@@ -0,0 +1,104 @@
+{
+  "name": "node-red",
+  "version": "0.9.1",
+  "description": "A visual tool for wiring the Internet of Things",
+  "homepage": "http://nodered.org",
+  "license": "Apache",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/node-red/node-red.git"
+  },
+  "main": "red/red.js",
+  "scripts": {
+    "start": "node red.js",
+    "test": "grunt"
+  },
+  "contributors": [
+    {
+      "name": "Nick O'Leary"
+    },
+    {
+      "name": "Dave Conway-Jones"
+    }
+  ],
+  "keywords": [
+    "editor",
+    "messaging",
+    "iot",
+    "m2m",
+    "pi",
+    "arduino",
+    "beaglebone",
+    "ibm",
+    "flow"
+  ],
+  "dependencies": {
+    "express": "3.17.2",
+    "when": "3.4.6",
+    "nopt": "3.0.1",
+    "mqtt": "0.3.x",
+    "ws": "0.4.32",
+    "fs-extra": "0.11.1",
+    "clone": "0.1.18",
+    "mustache": "0.8.2",
+    "cron": "1.0.4",
+    "raw-body": "1.3.0",
+    "twitter-ng": "0.6.2",
+    "oauth": "0.9.12",
+    "xml2js": "0.4.4",
+    "sentiment": "0.2.3",
+    "irc": "0.3.7",
+    "follow-redirects": "0.0.3",
+    "cors": "2.4.2",
+    "mkdirp": "0.5.0",
+    "cheerio": "0.17.0",
+    "uglify-js": "2.4.15",
+    "nodemailer": "1.3.0",
+    "imap": "0.8.13",
+    "request": "2.42.0",
+    "colors": "0.6.2",
+    "glob" : "5.0.15",
+    "lodash" : "3.7.0",
+    "multer" : "1.1.0",
+    "mysql" : "2.7.0",
+    "needle" : "0.9.2",
+    "pretty-data" : "0.40.0"
+  },
+  "devDependencies": {
+    "grunt": "0.4.5",
+    "grunt-cli": "0.1.13",
+    "grunt-simple-mocha": "0.4.0",
+    "grunt-contrib-jshint": "0.10.0",
+    "mocha": "1.21.4",
+    "should": "4.0.4",
+    "sinon": "1.10.3",
+    "supertest": "^0.13.0"
+  },
+  "engines": {
+    "node": ">=0.8"
+  },
+  "bugs": {
+    "url": "https://github.com/node-red/node-red/issues"
+  },
+  "_id": "node-red@0.9.1",
+  "dist": {
+    "shasum": "1c5f7ae2ef3dbcd090ca7db2e9c080968adc2f73",
+    "tarball": "http://registry.npmjs.org/node-red/-/node-red-0.9.1.tgz"
+  },
+  "_from": "node-red@0.9.1",
+  "_npmVersion": "1.4.6",
+  "_npmUser": {
+    "name": "knolleary",
+    "email": "nick.oleary@gmail.com"
+  },
+  "maintainers": [
+    {
+      "name": "knolleary",
+      "email": "nick.oleary@gmail.com"
+    }
+  ],
+  "directories": {},
+  "_shasum": "1c5f7ae2ef3dbcd090ca7db2e9c080968adc2f73",
+  "_resolved": "https://registry.npmjs.org/node-red/-/node-red-0.9.1.tgz",
+  "readme": "ERROR: No README data found!"
+}
diff --git a/dgbuilder/pom.xml b/dgbuilder/pom.xml
new file mode 100644 (file)
index 0000000..8830031
--- /dev/null
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+       <groupId>org.onap.ccsdk.distribution</groupId>
+       <artifactId>distribution-root</artifactId>
+       <version>0.1.0-SNAPSHOT</version>
+    </parent>
+
+       <modelVersion>4.0.0</modelVersion>
+       <packaging>pom</packaging>
+       <groupId>org.onap.ccsdk.distribution</groupId>
+       <artifactId>dgbuilder</artifactId>
+
+       <version>0.1.0-SNAPSHOT</version>
+
+       <name>Directed Graph Builder</name>
+       <description>Directed Graph Builder</description>
+
+       <properties>
+               <application.name>dgbuilder</application.name>
+               <skip.SWM>true</skip.SWM>
+               <adm.base>/opt/app/dgbuilder</adm.base>
+               <maven.build.timestamp.format>yyMMdd-HHmmss</maven.build.timestamp.format>
+               <build.number>${maven.build.timestamp}</build.number>
+               <SWM_VERSION>${project.version}-${build.number}</SWM_VERSION>
+       </properties>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.onap.ccsdk.sli.core</groupId>
+                       <artifactId>sli-common</artifactId>
+                       <version>${sdnctl.sli.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>mysql</groupId>
+                       <artifactId>mysql-connector-java</artifactId>
+                       <version>5.1.31</version>
+                       <type>jar</type>
+               </dependency>
+               <dependency>
+                       <groupId>org.antlr</groupId>
+                       <artifactId>antlr4</artifactId>
+                       <version>${antlr.version}</version>
+                       <type>jar</type>
+                       <scope>compile</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-api</artifactId>
+                       <version>${slf4j.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-simple</artifactId>
+                       <version>1.7.5</version>
+                       <scope>compile</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.commons</groupId>
+                       <artifactId>commons-lang3</artifactId>
+                       <version>${commons.lang3.version}</version>
+               </dependency>
+       </dependencies>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-assembly-plugin</artifactId>
+                               <version>2.6</version>
+                               <executions>
+                                       <execution>
+                                               <id>create-zip</id>
+                                               <goals>
+                                                       <goal>single</goal>
+                                               </goals>
+                                               <phase>package</phase>
+                                               <configuration>
+                                                       <finalName>${application.name}.${project.version}</finalName>
+                                                       <attach>true</attach>
+                                                       <descriptors>
+                                                               <descriptor>src/assembly/assemble_zip.xml</descriptor>
+                                                       </descriptors>
+                                                       <appendAssemblyId>false</appendAssemblyId>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <id>copy-dependencies</id>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                               <phase>prepare-package</phase>
+                                               <configuration>
+                                                       <transitive>false</transitive>
+                                                       <outputDirectory>${project.build.directory}/svclogic/lib</outputDirectory>
+                                                       <overWriteReleases>false</overWriteReleases>
+                                                       <overWriteSnapshots>true</overWriteSnapshots>
+                                                       <overWriteIfNewer>true</overWriteIfNewer>
+                                                       <useRepositoryLayout>false</useRepositoryLayout>
+                                                       <addParentPoms>false</addParentPoms>
+                                                       <copyPom>false</copyPom>
+                                                       <scope>provided</scope>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-antrun-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                       <phase>generate-sources</phase>
+                                       <configuration>
+                                       <tasks>
+                                               <exec executable="${project.basedir}/build_pom_for_yang_compile">
+                                                       <arg value="${project.parent.version}"/>
+                                               </exec>
+                                       </tasks>
+                                       </configuration>
+                                       <goals>
+                                               <goal>run</goal>
+                               </goals>
+                               </execution>
+                       </executions>
+                       </plugin>
+               </plugins>
+       </build>
+       <organization>
+               <name>ONAP</name>
+       </organization>
+</project>
+
diff --git a/dgbuilder/public/bootstrap/css/bootstrap.min.css b/dgbuilder/public/bootstrap/css/bootstrap.min.css
new file mode 100644 (file)
index 0000000..df96c86
--- /dev/null
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.2
+ *
+ * Copyright 2013 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
diff --git a/dgbuilder/public/bootstrap/img/glyphicons-halflings-white.png b/dgbuilder/public/bootstrap/img/glyphicons-halflings-white.png
new file mode 100644 (file)
index 0000000..3bf6484
Binary files /dev/null and b/dgbuilder/public/bootstrap/img/glyphicons-halflings-white.png differ
diff --git a/dgbuilder/public/bootstrap/img/glyphicons-halflings.png b/dgbuilder/public/bootstrap/img/glyphicons-halflings.png
new file mode 100644 (file)
index 0000000..a996999
Binary files /dev/null and b/dgbuilder/public/bootstrap/img/glyphicons-halflings.png differ
diff --git a/dgbuilder/public/bootstrap/js/bootstrap.min.js b/dgbuilder/public/bootstrap/js/bootstrap.min.js
new file mode 100644 (file)
index 0000000..848258d
--- /dev/null
@@ -0,0 +1,6 @@
+/*!
+* Bootstrap.js by @fat & @mdo
+* Copyright 2013 Twitter, Inc.
+* http://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('<div class="dropdown-backdrop"/>').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
diff --git a/dgbuilder/public/d3.v3.min.js b/dgbuilder/public/d3.v3.min.js
new file mode 100644 (file)
index 0000000..2542ced
--- /dev/null
@@ -0,0 +1,4 @@
+(function(){function t(t){return t.target}function n(t){return t.source}function e(t,n){try{for(var e in n)Object.defineProperty(t.prototype,e,{value:n[e],enumerable:!1})}catch(r){t.prototype=n}}function r(t){for(var n=-1,e=t.length,r=[];e>++n;)r.push(t[n]);return r}function i(t){return Array.prototype.slice.call(t)}function u(){}function a(t){return t}function o(){return!0}function c(t){return"function"==typeof t?t:function(){return t}}function l(t,n,e){return function(){var r=e.apply(n,arguments);return arguments.length?t:r}}function s(t){return null!=t&&!isNaN(t)}function f(t){return t.length}function h(t){return t.trim().replace(/\s+/g," ")}function d(t){for(var n=1;t*n%1;)n*=10;return n}function g(t){return 1===t.length?function(n,e){t(null==n?e:null)}:t}function p(t){return t.responseText}function m(t){return JSON.parse(t.responseText)}function v(t){var n=document.createRange();return n.selectNode(document.body),n.createContextualFragment(t.responseText)}function y(t){return t.responseXML}function M(){}function b(t){function n(){for(var n,r=e,i=-1,u=r.length;u>++i;)(n=r[i].on)&&n.apply(this,arguments);return t}var e=[],r=new u;return n.on=function(n,i){var u,a=r.get(n);return 2>arguments.length?a&&a.on:(a&&(a.on=null,e=e.slice(0,u=e.indexOf(a)).concat(e.slice(u+1)),r.remove(n)),i&&e.push(r.set(n,{on:i})),t)},n}function x(t,n){return n-(t?1+Math.floor(Math.log(t+Math.pow(10,1+Math.floor(Math.log(t)/Math.LN10)-n))/Math.LN10):1)}function _(t){return t+""}function w(t,n){var e=Math.pow(10,3*Math.abs(8-n));return{scale:n>8?function(t){return t/e}:function(t){return t*e},symbol:t}}function S(t){return function(n){return 0>=n?0:n>=1?1:t(n)}}function k(t){return function(n){return 1-t(1-n)}}function E(t){return function(n){return.5*(.5>n?t(2*n):2-t(2-2*n))}}function A(t){return t*t}function N(t){return t*t*t}function T(t){if(0>=t)return 0;if(t>=1)return 1;var n=t*t,e=n*t;return 4*(.5>t?e:3*(t-n)+e-.75)}function q(t){return function(n){return Math.pow(n,t)}}function C(t){return 1-Math.cos(t*Ru/2)}function z(t){return Math.pow(2,10*(t-1))}function D(t){return 1-Math.sqrt(1-t*t)}function L(t,n){var e;return 2>arguments.length&&(n=.45),arguments.length?e=n/(2*Ru)*Math.asin(1/t):(t=1,e=n/4),function(r){return 1+t*Math.pow(2,10*-r)*Math.sin(2*(r-e)*Ru/n)}}function F(t){return t||(t=1.70158),function(n){return n*n*((t+1)*n-t)}}function H(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}function R(){d3.event.stopPropagation(),d3.event.preventDefault()}function P(){for(var t,n=d3.event;t=n.sourceEvent;)n=t;return n}function j(t){for(var n=new M,e=0,r=arguments.length;r>++e;)n[arguments[e]]=b(n);return n.of=function(e,r){return function(i){try{var u=i.sourceEvent=d3.event;i.target=t,d3.event=i,n[i.type].apply(e,r)}finally{d3.event=u}}},n}function O(t){var n=[t.a,t.b],e=[t.c,t.d],r=U(n),i=Y(n,e),u=U(I(e,n,-i))||0;n[0]*e[1]<e[0]*n[1]&&(n[0]*=-1,n[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(n[1],n[0]):Math.atan2(-e[0],e[1]))*Ou,this.translate=[t.e,t.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Ou:0}function Y(t,n){return t[0]*n[0]+t[1]*n[1]}function U(t){var n=Math.sqrt(Y(t,t));return n&&(t[0]/=n,t[1]/=n),n}function I(t,n,e){return t[0]+=e*n[0],t[1]+=e*n[1],t}function V(t){return"transform"==t?d3.interpolateTransform:d3.interpolate}function X(t,n){return n=n-(t=+t)?1/(n-t):0,function(e){return(e-t)*n}}function Z(t,n){return n=n-(t=+t)?1/(n-t):0,function(e){return Math.max(0,Math.min(1,(e-t)*n))}}function B(){}function $(t,n,e){return new J(t,n,e)}function J(t,n,e){this.r=t,this.g=n,this.b=e}function G(t){return 16>t?"0"+Math.max(0,t).toString(16):Math.min(255,t).toString(16)}function K(t,n,e){var r,i,u,a=0,o=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(t))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return n(nn(i[0]),nn(i[1]),nn(i[2]))}return(u=aa.get(t))?n(u.r,u.g,u.b):(null!=t&&"#"===t.charAt(0)&&(4===t.length?(a=t.charAt(1),a+=a,o=t.charAt(2),o+=o,c=t.charAt(3),c+=c):7===t.length&&(a=t.substring(1,3),o=t.substring(3,5),c=t.substring(5,7)),a=parseInt(a,16),o=parseInt(o,16),c=parseInt(c,16)),n(a,o,c))}function W(t,n,e){var r,i,u=Math.min(t/=255,n/=255,e/=255),a=Math.max(t,n,e),o=a-u,c=(a+u)/2;return o?(i=.5>c?o/(a+u):o/(2-a-u),r=t==a?(n-e)/o+(e>n?6:0):n==a?(e-t)/o+2:(t-n)/o+4,r*=60):i=r=0,en(r,i,c)}function Q(t,n,e){t=tn(t),n=tn(n),e=tn(e);var r=gn((.4124564*t+.3575761*n+.1804375*e)/sa),i=gn((.2126729*t+.7151522*n+.072175*e)/fa),u=gn((.0193339*t+.119192*n+.9503041*e)/ha);return ln(116*i-16,500*(r-i),200*(i-u))}function tn(t){return.04045>=(t/=255)?t/12.92:Math.pow((t+.055)/1.055,2.4)}function nn(t){var n=parseFloat(t);return"%"===t.charAt(t.length-1)?Math.round(2.55*n):n}function en(t,n,e){return new rn(t,n,e)}function rn(t,n,e){this.h=t,this.s=n,this.l=e}function un(t,n,e){function r(t){return t>360?t-=360:0>t&&(t+=360),60>t?u+(a-u)*t/60:180>t?a:240>t?u+(a-u)*(240-t)/60:u}function i(t){return Math.round(255*r(t))}var u,a;return t%=360,0>t&&(t+=360),n=0>n?0:n>1?1:n,e=0>e?0:e>1?1:e,a=.5>=e?e*(1+n):e+n-e*n,u=2*e-a,$(i(t+120),i(t),i(t-120))}function an(t,n,e){return new on(t,n,e)}function on(t,n,e){this.h=t,this.c=n,this.l=e}function cn(t,n,e){return ln(e,Math.cos(t*=ju)*n,Math.sin(t)*n)}function ln(t,n,e){return new sn(t,n,e)}function sn(t,n,e){this.l=t,this.a=n,this.b=e}function fn(t,n,e){var r=(t+16)/116,i=r+n/500,u=r-e/200;return i=dn(i)*sa,r=dn(r)*fa,u=dn(u)*ha,$(pn(3.2404542*i-1.5371385*r-.4985314*u),pn(-.969266*i+1.8760108*r+.041556*u),pn(.0556434*i-.2040259*r+1.0572252*u))}function hn(t,n,e){return an(180*(Math.atan2(e,n)/Ru),Math.sqrt(n*n+e*e),t)}function dn(t){return t>.206893034?t*t*t:(t-4/29)/7.787037}function gn(t){return t>.008856?Math.pow(t,1/3):7.787037*t+4/29}function pn(t){return Math.round(255*(.00304>=t?12.92*t:1.055*Math.pow(t,1/2.4)-.055))}function mn(t){return Iu(t,Ma),t}function vn(t){return function(){return ga(t,this)}}function yn(t){return function(){return pa(t,this)}}function Mn(t,n){function e(){this.removeAttribute(t)}function r(){this.removeAttributeNS(t.space,t.local)}function i(){this.setAttribute(t,n)}function u(){this.setAttributeNS(t.space,t.local,n)}function a(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}function o(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}return t=d3.ns.qualify(t),null==n?t.local?r:e:"function"==typeof n?t.local?o:a:t.local?u:i}function bn(t){return RegExp("(?:^|\\s+)"+d3.requote(t)+"(?:\\s+|$)","g")}function xn(t,n){function e(){for(var e=-1;i>++e;)t[e](this,n)}function r(){for(var e=-1,r=n.apply(this,arguments);i>++e;)t[e](this,r)}t=t.trim().split(/\s+/).map(_n);var i=t.length;return"function"==typeof n?r:e}function _n(t){var n=bn(t);return function(e,r){if(i=e.classList)return r?i.add(t):i.remove(t);var i=e.className,u=null!=i.baseVal,a=u?i.baseVal:i;r?(n.lastIndex=0,n.test(a)||(a=h(a+" "+t),u?i.baseVal=a:e.className=a)):a&&(a=h(a.replace(n," ")),u?i.baseVal=a:e.className=a)}}function wn(t,n,e){function r(){this.style.removeProperty(t)}function i(){this.style.setProperty(t,n,e)}function u(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}return null==n?r:"function"==typeof n?u:i}function Sn(t,n){function e(){delete this[t]}function r(){this[t]=n}function i(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}return null==n?e:"function"==typeof n?i:r}function kn(t){return{__data__:t}}function En(t){return function(){return ya(this,t)}}function An(t){return arguments.length||(t=d3.ascending),function(n,e){return t(n&&n.__data__,e&&e.__data__)}}function Nn(t,n,e){function r(){var n=this[u];n&&(this.removeEventListener(t,n,n.$),delete this[u])}function i(){function i(t){var e=d3.event;d3.event=t,o[0]=a.__data__;try{n.apply(a,o)}finally{d3.event=e}}var a=this,o=Yu(arguments);r.call(this),this.addEventListener(t,this[u]=i,i.$=e),i._=n}var u="__on"+t,a=t.indexOf(".");return a>0&&(t=t.substring(0,a)),n?i:r}function Tn(t,n){for(var e=0,r=t.length;r>e;e++)for(var i,u=t[e],a=0,o=u.length;o>a;a++)(i=u[a])&&n(i,a,e);return t}function qn(t){return Iu(t,xa),t}function Cn(t,n){return Iu(t,wa),t.id=n,t}function zn(t,n,e,r){var i=t.__transition__||(t.__transition__={active:0,count:0}),a=i[e];if(!a){var o=r.time;return a=i[e]={tween:new u,event:d3.dispatch("start","end"),time:o,ease:r.ease,delay:r.delay,duration:r.duration},++i.count,d3.timer(function(r){function u(r){return i.active>e?l():(i.active=e,h.start.call(t,s,n),a.tween.forEach(function(e,r){(r=r.call(t,s,n))&&p.push(r)}),c(r)||d3.timer(c,0,o),1)}function c(r){if(i.active!==e)return l();for(var u=(r-d)/g,a=f(u),o=p.length;o>0;)p[--o].call(t,a);return u>=1?(l(),h.end.call(t,s,n),1):void 0}function l(){return--i.count?delete i[e]:delete t.__transition__,1}var s=t.__data__,f=a.ease,h=a.event,d=a.delay,g=a.duration,p=[];return r>=d?u(r):d3.timer(u,d,o),1},0,o),a}}function Dn(t){return null==t&&(t=""),function(){this.textContent=t}}function Ln(t,n,e,r){var i=t.id;return Tn(t,"function"==typeof e?function(t,u,a){t.__transition__[i].tween.set(n,r(e.call(t,t.__data__,u,a)))}:(e=r(e),function(t){t.__transition__[i].tween.set(n,e)}))}function Fn(){for(var t,n=Date.now(),e=qa;e;)t=n-e.then,t>=e.delay&&(e.flush=e.callback(t)),e=e.next;var r=Hn()-n;r>24?(isFinite(r)&&(clearTimeout(Aa),Aa=setTimeout(Fn,r)),Ea=0):(Ea=1,Ca(Fn))}function Hn(){for(var t=null,n=qa,e=1/0;n;)n.flush?(delete Ta[n.callback.id],n=t?t.next=n.next:qa=n.next):(e=Math.min(e,n.then+n.delay),n=(t=n).next);return e}function Rn(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>za&&(window.scrollX||window.scrollY)){e=d3.select(document.body).append("svg").style("position","absolute").style("top",0).style("left",0);var i=e[0][0].getScreenCTM();za=!(i.f||i.e),e.remove()}return za?(r.x=n.pageX,r.y=n.pageY):(r.x=n.clientX,r.y=n.clientY),r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var u=t.getBoundingClientRect();return[n.clientX-u.left-t.clientLeft,n.clientY-u.top-t.clientTop]}function Pn(){}function jn(t){var n=t[0],e=t[t.length-1];return e>n?[n,e]:[e,n]}function On(t){return t.rangeExtent?t.rangeExtent():jn(t.range())}function Yn(t,n){var e,r=0,i=t.length-1,u=t[r],a=t[i];return u>a&&(e=r,r=i,i=e,e=u,u=a,a=e),(n=n(a-u))&&(t[r]=n.floor(u),t[i]=n.ceil(a)),t}function Un(){return Math}function In(t,n,e,r){function i(){var i=Math.min(t.length,n.length)>2?Gn:Jn,c=r?Z:X;return a=i(t,n,c,e),o=i(n,t,c,d3.interpolate),u}function u(t){return a(t)}var a,o;return u.invert=function(t){return o(t)},u.domain=function(n){return arguments.length?(t=n.map(Number),i()):t},u.range=function(t){return arguments.length?(n=t,i()):n},u.rangeRound=function(t){return u.range(t).interpolate(d3.interpolateRound)},u.clamp=function(t){return arguments.length?(r=t,i()):r},u.interpolate=function(t){return arguments.length?(e=t,i()):e},u.ticks=function(n){return Bn(t,n)},u.tickFormat=function(n){return $n(t,n)},u.nice=function(){return Yn(t,Xn),i()},u.copy=function(){return In(t,n,e,r)},i()}function Vn(t,n){return d3.rebind(t,n,"range","rangeRound","interpolate","clamp")}function Xn(t){return t=Math.pow(10,Math.round(Math.log(t)/Math.LN10)-1),t&&{floor:function(n){return Math.floor(n/t)*t},ceil:function(n){return Math.ceil(n/t)*t}}}function Zn(t,n){var e=jn(t),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/n)/Math.LN10)),u=n/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Bn(t,n){return d3.range.apply(d3,Zn(t,n))}function $n(t,n){return d3.format(",."+Math.max(0,-Math.floor(Math.log(Zn(t,n)[2])/Math.LN10+.01))+"f")}function Jn(t,n,e,r){var i=e(t[0],t[1]),u=r(n[0],n[1]);return function(t){return u(i(t))}}function Gn(t,n,e,r){var i=[],u=[],a=0,o=Math.min(t.length,n.length)-1;for(t[o]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());o>=++a;)i.push(e(t[a-1],t[a])),u.push(r(n[a-1],n[a]));return function(n){var e=d3.bisect(t,n,1,o)-1;return u[e](i[e](n))}}function Kn(t,n){function e(e){return t(n(e))}var r=n.pow;return e.invert=function(n){return r(t.invert(n))},e.domain=function(i){return arguments.length?(n=0>i[0]?Qn:Wn,r=n.pow,t.domain(i.map(n)),e):t.domain().map(r)},e.nice=function(){return t.domain(Yn(t.domain(),Un)),e},e.ticks=function(){var e=jn(t.domain()),i=[];if(e.every(isFinite)){var u=Math.floor(e[0]),a=Math.ceil(e[1]),o=r(e[0]),c=r(e[1]);if(n===Qn)for(i.push(r(u));a>u++;)for(var l=9;l>0;l--)i.push(r(u)*l);else{for(;a>u;u++)for(var l=1;10>l;l++)i.push(r(u)*l);i.push(r(u))}for(u=0;o>i[u];u++);for(a=i.length;i[a-1]>c;a--);i=i.slice(u,a)}return i},e.tickFormat=function(t,i){if(2>arguments.length&&(i=Da),!arguments.length)return i;var u,a=Math.max(.1,t/e.ticks().length),o=n===Qn?(u=-1e-12,Math.floor):(u=1e-12,Math.ceil);return function(t){return a>=t/r(o(n(t)+u))?i(t):""}},e.copy=function(){return Kn(t.copy(),n)},Vn(e,t)}function Wn(t){return Math.log(0>t?0:t)/Math.LN10}function Qn(t){return-Math.log(t>0?0:-t)/Math.LN10}function te(t,n){function e(n){return t(r(n))}var r=ne(n),i=ne(1/n);return e.invert=function(n){return i(t.invert(n))},e.domain=function(n){return arguments.length?(t.domain(n.map(r)),e):t.domain().map(i)},e.ticks=function(t){return Bn(e.domain(),t)},e.tickFormat=function(t){return $n(e.domain(),t)},e.nice=function(){return e.domain(Yn(e.domain(),Xn))},e.exponent=function(t){if(!arguments.length)return n;var u=e.domain();return r=ne(n=t),i=ne(1/n),e.domain(u)},e.copy=function(){return te(t.copy(),n)},Vn(e,t)}function ne(t){return function(n){return 0>n?-Math.pow(-n,t):Math.pow(n,t)}}function ee(t,n){function e(n){return a[((i.get(n)||i.set(n,t.push(n)))-1)%a.length]}function r(n,e){return d3.range(t.length).map(function(t){return n+e*t})}var i,a,o;return e.domain=function(r){if(!arguments.length)return t;t=[],i=new u;for(var a,o=-1,c=r.length;c>++o;)i.has(a=r[o])||i.set(a,t.push(a));return e[n.t].apply(e,n.a)},e.range=function(t){return arguments.length?(a=t,o=0,n={t:"range",a:arguments},e):a},e.rangePoints=function(i,u){2>arguments.length&&(u=0);var c=i[0],l=i[1],s=(l-c)/(Math.max(1,t.length-1)+u);return a=r(2>t.length?(c+l)/2:c+s*u/2,s),o=0,n={t:"rangePoints",a:arguments},e},e.rangeBands=function(i,u,c){2>arguments.length&&(u=0),3>arguments.length&&(c=u);var l=i[1]<i[0],s=i[l-0],f=i[1-l],h=(f-s)/(t.length-u+2*c);return a=r(s+h*c,h),l&&a.reverse(),o=h*(1-u),n={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,u,c){2>arguments.length&&(u=0),3>arguments.length&&(c=u);var l=i[1]<i[0],s=i[l-0],f=i[1-l],h=Math.floor((f-s)/(t.length-u+2*c)),d=f-s-(t.length-u)*h;return a=r(s+Math.round(d/2),h),l&&a.reverse(),o=Math.round(h*(1-u)),n={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return jn(n.a[0])},e.copy=function(){return ee(t,n)},e.domain(t)}function re(t,n){function e(){var e=0,u=n.length;for(i=[];u>++e;)i[e-1]=d3.quantile(t,e/u);return r}function r(t){return isNaN(t=+t)?0/0:n[d3.bisect(i,t)]}var i;return r.domain=function(n){return arguments.length?(t=n.filter(function(t){return!isNaN(t)}).sort(d3.ascending),e()):t},r.range=function(t){return arguments.length?(n=t,e()):n},r.quantiles=function(){return i},r.copy=function(){return re(t,n)},e()}function ie(t,n,e){function r(n){return e[Math.max(0,Math.min(a,Math.floor(u*(n-t))))]}function i(){return u=e.length/(n-t),a=e.length-1,r}var u,a;return r.domain=function(e){return arguments.length?(t=+e[0],n=+e[e.length-1],i()):[t,n]},r.range=function(t){return arguments.length?(e=t,i()):e},r.copy=function(){return ie(t,n,e)},i()}function ue(t,n){function e(e){return n[d3.bisect(t,e)]}return e.domain=function(n){return arguments.length?(t=n,e):t},e.range=function(t){return arguments.length?(n=t,e):n},e.copy=function(){return ue(t,n)},e}function ae(t){function n(t){return+t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=e.map(n),n):t},n.ticks=function(n){return Bn(t,n)},n.tickFormat=function(n){return $n(t,n)},n.copy=function(){return ae(t)},n}function oe(t){return t.innerRadius}function ce(t){return t.outerRadius}function le(t){return t.startAngle}function se(t){return t.endAngle}function fe(t){function n(n){function a(){s.push("M",u(t(f),l))}for(var o,s=[],f=[],h=-1,d=n.length,g=c(e),p=c(r);d>++h;)i.call(this,o=n[h],h)?f.push([+g.call(this,o,h),+p.call(this,o,h)]):f.length&&(a(),f=[]);return f.length&&a(),s.length?s.join(""):null}var e=he,r=de,i=o,u=ge,a=u.key,l=.7;return n.x=function(t){return arguments.length?(e=t,n):e},n.y=function(t){return arguments.length?(r=t,n):r},n.defined=function(t){return arguments.length?(i=t,n):i},n.interpolate=function(t){return arguments.length?(a="function"==typeof t?u=t:(u=Oa.get(t)||ge).key,n):a},n.tension=function(t){return arguments.length?(l=t,n):l},n}function he(t){return t[0]}function de(t){return t[1]}function ge(t){return t.join("L")}function pe(t){return ge(t)+"Z"}function me(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];e>++n;)i.push("V",(r=t[n])[1],"H",r[0]);return i.join("")}function ve(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];e>++n;)i.push("H",(r=t[n])[0],"V",r[1]);return i.join("")}function ye(t,n){return 4>t.length?ge(t):t[1]+xe(t.slice(1,t.length-1),_e(t,n))}function Me(t,n){return 3>t.length?ge(t):t[0]+xe((t.push(t[0]),t),_e([t[t.length-2]].concat(t,[t[1]]),n))}function be(t,n){return 3>t.length?ge(t):t[0]+xe(t,_e(t,n))}function xe(t,n){if(1>n.length||t.length!=n.length&&t.length!=n.length+2)return ge(t);var e=t.length!=n.length,r="",i=t[0],u=t[1],a=n[0],o=a,c=1;if(e&&(r+="Q"+(u[0]-2*a[0]/3)+","+(u[1]-2*a[1]/3)+","+u[0]+","+u[1],i=t[1],c=2),n.length>1){o=n[1],u=t[c],c++,r+="C"+(i[0]+a[0])+","+(i[1]+a[1])+","+(u[0]-o[0])+","+(u[1]-o[1])+","+u[0]+","+u[1];for(var l=2;n.length>l;l++,c++)u=t[c],o=n[l],r+="S"+(u[0]-o[0])+","+(u[1]-o[1])+","+u[0]+","+u[1]}if(e){var s=t[c];r+="Q"+(u[0]+2*o[0]/3)+","+(u[1]+2*o[1]/3)+","+s[0]+","+s[1]}return r}function _e(t,n){for(var e,r=[],i=(1-n)/2,u=t[0],a=t[1],o=1,c=t.length;c>++o;)e=u,u=a,a=t[o],r.push([i*(a[0]-e[0]),i*(a[1]-e[1])]);return r}function we(t){if(3>t.length)return ge(t);var n=1,e=t.length,r=t[0],i=r[0],u=r[1],a=[i,i,i,(r=t[1])[0]],o=[u,u,u,r[1]],c=[i,",",u];for(Ne(c,a,o);e>++n;)r=t[n],a.shift(),a.push(r[0]),o.shift(),o.push(r[1]),Ne(c,a,o);for(n=-1;2>++n;)a.shift(),a.push(r[0]),o.shift(),o.push(r[1]),Ne(c,a,o);return c.join("")}function Se(t){if(4>t.length)return ge(t);for(var n,e=[],r=-1,i=t.length,u=[0],a=[0];3>++r;)n=t[r],u.push(n[0]),a.push(n[1]);for(e.push(Ae(Ia,u)+","+Ae(Ia,a)),--r;i>++r;)n=t[r],u.shift(),u.push(n[0]),a.shift(),a.push(n[1]),Ne(e,u,a);return e.join("")}function ke(t){for(var n,e,r=-1,i=t.length,u=i+4,a=[],o=[];4>++r;)e=t[r%i],a.push(e[0]),o.push(e[1]);for(n=[Ae(Ia,a),",",Ae(Ia,o)],--r;u>++r;)e=t[r%i],a.shift(),a.push(e[0]),o.shift(),o.push(e[1]),Ne(n,a,o);return n.join("")}function Ee(t,n){var e=t.length-1;if(e)for(var r,i,u=t[0][0],a=t[0][1],o=t[e][0]-u,c=t[e][1]-a,l=-1;e>=++l;)r=t[l],i=l/e,r[0]=n*r[0]+(1-n)*(u+i*o),r[1]=n*r[1]+(1-n)*(a+i*c);return we(t)}function Ae(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function Ne(t,n,e){t.push("C",Ae(Ya,n),",",Ae(Ya,e),",",Ae(Ua,n),",",Ae(Ua,e),",",Ae(Ia,n),",",Ae(Ia,e))}function Te(t,n){return(n[1]-t[1])/(n[0]-t[0])}function qe(t){for(var n=0,e=t.length-1,r=[],i=t[0],u=t[1],a=r[0]=Te(i,u);e>++n;)r[n]=(a+(a=Te(i=u,u=t[n+1])))/2;return r[n]=a,r}function Ce(t){for(var n,e,r,i,u=[],a=qe(t),o=-1,c=t.length-1;c>++o;)n=Te(t[o],t[o+1]),1e-6>Math.abs(n)?a[o]=a[o+1]=0:(e=a[o]/n,r=a[o+1]/n,i=e*e+r*r,i>9&&(i=3*n/Math.sqrt(i),a[o]=i*e,a[o+1]=i*r));for(o=-1;c>=++o;)i=(t[Math.min(c,o+1)][0]-t[Math.max(0,o-1)][0])/(6*(1+a[o]*a[o])),u.push([i||0,a[o]*i||0]);return u}function ze(t){return 3>t.length?ge(t):t[0]+xe(t,Ce(t))}function De(t){for(var n,e,r,i=-1,u=t.length;u>++i;)n=t[i],e=n[0],r=n[1]+Pa,n[0]=e*Math.cos(r),n[1]=e*Math.sin(r);return t}function Le(t){function n(n){function o(){m.push("M",l(t(y),d),h,f(t(v.reverse()),d),"Z")}for(var s,g,p,m=[],v=[],y=[],M=-1,b=n.length,x=c(e),_=c(i),w=e===r?function(){return g}:c(r),S=i===u?function(){return p}:c(u);b>++M;)a.call(this,s=n[M],M)?(v.push([g=+x.call(this,s,M),p=+_.call(this,s,M)]),y.push([+w.call(this,s,M),+S.call(this,s,M)])):v.length&&(o(),v=[],y=[]);return v.length&&o(),m.length?m.join(""):null}var e=he,r=he,i=0,u=de,a=o,l=ge,s=l.key,f=l,h="L",d=.7;return n.x=function(t){return arguments.length?(e=r=t,n):r},n.x0=function(t){return arguments.length?(e=t,n):e},n.x1=function(t){return arguments.length?(r=t,n):r},n.y=function(t){return arguments.length?(i=u=t,n):u},n.y0=function(t){return arguments.length?(i=t,n):i},n.y1=function(t){return arguments.length?(u=t,n):u},n.defined=function(t){return arguments.length?(a=t,n):a},n.interpolate=function(t){return arguments.length?(s="function"==typeof t?l=t:(l=Oa.get(t)||ge).key,f=l.reverse||l,h=l.closed?"M":"L",n):s},n.tension=function(t){return arguments.length?(d=t,n):d},n}function Fe(t){return t.radius}function He(t){return[t.x,t.y]}function Re(t){return function(){var n=t.apply(this,arguments),e=n[0],r=n[1]+Pa;return[e*Math.cos(r),e*Math.sin(r)]}}function Pe(){return 64}function je(){return"circle"}function Oe(t){var n=Math.sqrt(t/Ru);return"M0,"+n+"A"+n+","+n+" 0 1,1 0,"+-n+"A"+n+","+n+" 0 1,1 0,"+n+"Z"}function Ye(t,n){t.attr("transform",function(t){return"translate("+n(t)+",0)"})}function Ue(t,n){t.attr("transform",function(t){return"translate(0,"+n(t)+")"})}function Ie(t,n,e){if(r=[],e&&n.length>1){for(var r,i,u,a=jn(t.domain()),o=-1,c=n.length,l=(n[1]-n[0])/++e;c>++o;)for(i=e;--i>0;)(u=+n[o]-i*l)>=a[0]&&r.push(u);for(--o,i=0;e>++i&&(u=+n[o]+i*l)<a[1];)r.push(u)}return r}function Ve(){Ja||(Ja=d3.select("body").append("div").style("visibility","hidden").style("top",0).style("height",0).style("width",0).style("overflow-y","scroll").append("div").style("height","2000px").node().parentNode);var t,n=d3.event;try{Ja.scrollTop=1e3,Ja.dispatchEvent(n),t=1e3-Ja.scrollTop}catch(e){t=n.wheelDelta||5*-n.detail}return t}function Xe(t){for(var n=t.source,e=t.target,r=Be(n,e),i=[n];n!==r;)n=n.parent,i.push(n);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Ze(t){for(var n=[],e=t.parent;null!=e;)n.push(t),t=e,e=e.parent;return n.push(t),n}function Be(t,n){if(t===n)return t;for(var e=Ze(t),r=Ze(n),i=e.pop(),u=r.pop(),a=null;i===u;)a=i,i=e.pop(),u=r.pop();return a}function $e(t){t.fixed|=2}function Je(t){t.fixed&=1}function Ge(t){t.fixed|=4,t.px=t.x,t.py=t.y}function Ke(t){t.fixed&=3}function We(t,n,e){var r=0,i=0;if(t.charge=0,!t.leaf)for(var u,a=t.nodes,o=a.length,c=-1;o>++c;)u=a[c],null!=u&&(We(u,n,e),t.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(t.point){t.leaf||(t.point.x+=Math.random()-.5,t.point.y+=Math.random()-.5);var l=n*e[t.point.index];t.charge+=t.pointCharge=l,r+=l*t.point.x,i+=l*t.point.y}t.cx=r/t.charge,t.cy=i/t.charge}function Qe(){return 20}function tr(){return 1}function nr(t){return t.x}function er(t){return t.y}function rr(t,n,e){t.y0=n,t.y=e}function ir(t){return d3.range(t.length)}function ur(t){for(var n=-1,e=t[0].length,r=[];e>++n;)r[n]=0;return r}function ar(t){for(var n,e=1,r=0,i=t[0][1],u=t.length;u>e;++e)(n=t[e][1])>i&&(r=e,i=n);return r}function or(t){return t.reduce(cr,0)}function cr(t,n){return t+n[1]}function lr(t,n){return sr(t,Math.ceil(Math.log(n.length)/Math.LN2+1))}function sr(t,n){for(var e=-1,r=+t[0],i=(t[1]-r)/n,u=[];n>=++e;)u[e]=i*e+r;return u}function fr(t){return[d3.min(t),d3.max(t)]}function hr(t,n){return d3.rebind(t,n,"sort","children","value"),t.nodes=t,t.links=mr,t}function dr(t){return t.children}function gr(t){return t.value}function pr(t,n){return n.value-t.value}function mr(t){return d3.merge(t.map(function(t){return(t.children||[]).map(function(n){return{source:t,target:n}})}))}function vr(t,n){return t.value-n.value}function yr(t,n){var e=t._pack_next;t._pack_next=n,n._pack_prev=t,n._pack_next=e,e._pack_prev=n}function Mr(t,n){t._pack_next=n,n._pack_prev=t}function br(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-e*e-r*r>.001}function xr(t){function n(t){s=Math.min(t.x-t.r,s),f=Math.max(t.x+t.r,f),h=Math.min(t.y-t.r,h),d=Math.max(t.y+t.r,d)}if((e=t.children)&&(l=e.length)){var e,r,i,u,a,o,c,l,s=1/0,f=-1/0,h=1/0,d=-1/0;if(e.forEach(_r),r=e[0],r.x=-r.r,r.y=0,n(r),l>1&&(i=e[1],i.x=i.r,i.y=0,n(i),l>2))for(u=e[2],kr(r,i,u),n(u),yr(r,u),r._pack_prev=u,yr(u,i),i=r._pack_next,a=3;l>a;a++){kr(r,i,u=e[a]);var g=0,p=1,m=1;for(o=i._pack_next;o!==i;o=o._pack_next,p++)if(br(o,u)){g=1;break}if(1==g)for(c=r._pack_prev;c!==o._pack_prev&&!br(c,u);c=c._pack_prev,m++);g?(m>p||p==m&&i.r<r.r?Mr(r,i=o):Mr(r=c,i),a--):(yr(r,u),i=u,n(u))}var v=(s+f)/2,y=(h+d)/2,M=0;for(a=0;l>a;a++)u=e[a],u.x-=v,u.y-=y,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));t.r=M,e.forEach(wr)}}function _r(t){t._pack_next=t._pack_prev=t}function wr(t){delete t._pack_next,delete t._pack_prev}function Sr(t,n,e,r){var i=t.children;if(t.x=n+=r*t.x,t.y=e+=r*t.y,t.r*=r,i)for(var u=-1,a=i.length;a>++u;)Sr(i[u],n,e,r)}function kr(t,n,e){var r=t.r+e.r,i=n.x-t.x,u=n.y-t.y;if(r&&(i||u)){var a=n.r+e.r,o=i*i+u*u;a*=a,r*=r;var c=.5+(r-a)/(2*o),l=Math.sqrt(Math.max(0,2*a*(r+o)-(r-=o)*r-a*a))/(2*o);e.x=t.x+c*i+l*u,e.y=t.y+c*u-l*i}else e.x=t.x+r,e.y=t.y}function Er(t){return 1+d3.max(t,function(t){return t.y})}function Ar(t){return t.reduce(function(t,n){return t+n.x},0)/t.length}function Nr(t){var n=t.children;return n&&n.length?Nr(n[0]):t}function Tr(t){var n,e=t.children;return e&&(n=e.length)?Tr(e[n-1]):t}function qr(t,n){return t.parent==n.parent?1:2}function Cr(t){var n=t.children;return n&&n.length?n[0]:t._tree.thread}function zr(t){var n,e=t.children;return e&&(n=e.length)?e[n-1]:t._tree.thread}function Dr(t,n){var e=t.children;if(e&&(i=e.length))for(var r,i,u=-1;i>++u;)n(r=Dr(e[u],n),t)>0&&(t=r);return t}function Lr(t,n){return t.x-n.x}function Fr(t,n){return n.x-t.x}function Hr(t,n){return t.depth-n.depth}function Rr(t,n){function e(t,r){var i=t.children;if(i&&(a=i.length))for(var u,a,o=null,c=-1;a>++c;)u=i[c],e(u,o),o=u;n(t,r)}e(t,null)}function Pr(t){for(var n,e=0,r=0,i=t.children,u=i.length;--u>=0;)n=i[u]._tree,n.prelim+=e,n.mod+=e,e+=n.shift+(r+=n.change)}function jr(t,n,e){t=t._tree,n=n._tree;var r=e/(n.number-t.number);t.change+=r,n.change-=r,n.shift+=e,n.prelim+=e,n.mod+=e}function Or(t,n,e){return t._tree.ancestor.parent==n.parent?t._tree.ancestor:e}function Yr(t){return{x:t.x,y:t.y,dx:t.dx,dy:t.dy}}function Ur(t,n){var e=t.x+n[3],r=t.y+n[0],i=t.dx-n[1]-n[3],u=t.dy-n[0]-n[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Ir(t,n){function e(t,e){return d3.xhr(t,n,e).response(r)}function r(t){return e.parse(t.responseText)}function i(n){return n.map(u).join(t)}function u(t){return a.test(t)?'"'+t.replace(/\"/g,'""')+'"':t}var a=RegExp('["'+t+"\n]"),o=t.charCodeAt(0);return e.parse=function(t){var n;return e.parseRows(t,function(t){return n?n(t):(n=Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}"),void 0)})},e.parseRows=function(t,n){function e(){if(s>=l)return a;if(i)return i=!1,u;var n=s;if(34===t.charCodeAt(n)){for(var e=n;l>e++;)if(34===t.charCodeAt(e)){if(34!==t.charCodeAt(e+1))break;++e}s=e+2;var r=t.charCodeAt(e+1);return 13===r?(i=!0,10===t.charCodeAt(e+2)&&++s):10===r&&(i=!0),t.substring(n+1,e).replace(/""/g,'"')}for(;l>s;){var r=t.charCodeAt(s++),c=1;if(10===r)i=!0;else if(13===r)i=!0,10===t.charCodeAt(s)&&(++s,++c);else if(r!==o)continue;return t.substring(n,s-c)}return t.substring(n)}for(var r,i,u={},a={},c=[],l=t.length,s=0,f=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();(!n||(h=n(h,f++)))&&c.push(h)}return c},e.format=function(t){return t.map(i).join("\n")},e}function Vr(t,n){no.hasOwnProperty(t.type)&&no[t.type](t,n)}function Xr(t,n,e){var r,i=-1,u=t.length-e;for(n.lineStart();u>++i;)r=t[i],n.point(r[0],r[1]);n.lineEnd()}function Zr(t,n){var e=-1,r=t.length;for(n.polygonStart();r>++e;)Xr(t[e],n,1);n.polygonEnd()}function Br(t){return[Math.atan2(t[1],t[0]),Math.asin(Math.max(-1,Math.min(1,t[2])))]}function $r(t,n){return Pu>Math.abs(t[0]-n[0])&&Pu>Math.abs(t[1]-n[1])}function Jr(t){var n=t[0],e=t[1],r=Math.cos(e);return[r*Math.cos(n),r*Math.sin(n),Math.sin(e)]}function Gr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Kr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Wr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Qr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function ti(t){var n=Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function ni(t){function n(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function u(){s=0/0,p.point=a,n.lineStart()}function a(r,u){var a=Jr([r,u]),o=t(r,u);e(s,f,l,h,d,g,s=o[0],f=o[1],l=r,h=a[0],d=a[1],g=a[2],i,n),n.point(s,f)}function o(){p.point=r,n.lineEnd()}function c(){var t,r,c,m,v,y,M;u(),p.point=function(n,e){a(t=n,r=e),c=s,m=f,v=h,y=d,M=g,p.point=a},p.lineEnd=function(){e(s,f,l,h,d,g,c,m,t,v,y,M,i,n),p.lineEnd=o,o()}}var l,s,f,h,d,g,p={point:r,lineStart:u,lineEnd:o,polygonStart:function(){n.polygonStart(),p.lineStart=c},polygonEnd:function(){n.polygonEnd(),p.lineStart=u}};return p}function e(n,i,u,a,o,c,l,s,f,h,d,g,p,m){var v=l-n,y=s-i,M=v*v+y*y;if(M>4*r&&p--){var b=a+h,x=o+d,_=c+g,w=Math.sqrt(b*b+x*x+_*_),S=Math.asin(_/=w),k=Pu>Math.abs(Math.abs(_)-1)?(u+f)/2:Math.atan2(x,b),E=t(k,S),A=E[0],N=E[1],T=A-n,q=N-i,C=y*T-v*q;(C*C/M>r||Math.abs((v*T+y*q)/M-.5)>.3)&&(e(n,i,u,a,o,c,A,N,k,b/=w,x/=w,_,p,m),m.point(A,N),e(A,N,k,b,x,_,l,s,f,h,d,g,p,m))}}var r=.5,i=16;return n.precision=function(t){return arguments.length?(i=(r=t*t)>0&&16,n):Math.sqrt(r)},n}function ei(t,n){function e(t,n){var e=Math.sqrt(u-2*i*Math.sin(n))/i;return[e*Math.sin(t*=i),a-e*Math.cos(t)]}var r=Math.sin(t),i=(r+Math.sin(n))/2,u=1+r*(2*i-r),a=Math.sqrt(u)/i;return e.invert=function(t,n){var e=a-n;return[Math.atan2(t,e)/i,Math.asin((u-(t*t+e*e)*i*i)/(2*i))]},e}function ri(t){function n(t,n){r>t&&(r=t),t>u&&(u=t),i>n&&(i=n),n>a&&(a=n)}function e(){o.point=o.lineEnd=Pn}var r,i,u,a,o={point:n,lineStart:Pn,lineEnd:Pn,polygonStart:function(){o.lineEnd=e},polygonEnd:function(){o.point=n}};return function(n){return a=u=-(r=i=1/0),d3.geo.stream(n,t(o)),[[r,i],[u,a]]}}function ii(t,n){if(!io){++uo,t*=ju;var e=Math.cos(n*=ju);ao+=(e*Math.cos(t)-ao)/uo,oo+=(e*Math.sin(t)-oo)/uo,co+=(Math.sin(n)-co)/uo}}function ui(){var t,n;io=1,ai(),io=2;var e=lo.point;lo.point=function(r,i){e(t=r,n=i)},lo.lineEnd=function(){lo.point(t,n),oi(),lo.lineEnd=oi}}function ai(){function t(t,i){t*=ju;var u=Math.cos(i*=ju),a=u*Math.cos(t),o=u*Math.sin(t),c=Math.sin(i),l=Math.atan2(Math.sqrt((l=e*c-r*o)*l+(l=r*a-n*c)*l+(l=n*o-e*a)*l),n*a+e*o+r*c);uo+=l,ao+=l*(n+(n=a)),oo+=l*(e+(e=o)),co+=l*(r+(r=c))}var n,e,r;io>1||(1>io&&(io=1,uo=ao=oo=co=0),lo.point=function(i,u){i*=ju;var a=Math.cos(u*=ju);n=a*Math.cos(i),e=a*Math.sin(i),r=Math.sin(u),lo.point=t})}function oi(){lo.point=ii}function ci(t,n){var e=Math.cos(t),r=Math.sin(t);return function(i,u,a,o){null!=i?(i=li(e,i),u=li(e,u),(a>0?u>i:i>u)&&(i+=2*a*Ru)):(i=t+2*a*Ru,u=t);for(var c,l=a*n,s=i;a>0?s>u:u>s;s-=l)o.point((c=Br([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],c[1])}}function li(t,n){var e=Jr(n);e[0]-=t,ti(e);var r=Math.acos(Math.max(-1,Math.min(1,-e[1])));return((0>-e[2]?-r:r)+2*Math.PI-Pu)%(2*Math.PI)}function si(t,n,e){return function(r){function i(n,e){t(n,e)&&r.point(n,e)}function u(t,n){m.point(t,n)}function a(){v.point=u,m.lineStart()}function o(){v.point=i,m.lineEnd()}function c(t,n){M.point(t,n),p.push([t,n])}function l(){M.lineStart(),p=[]}function s(){c(p[0][0],p[0][1]),M.lineEnd();var t,n=M.clean(),e=y.buffer(),i=e.length;if(!i)return g=!0,d+=mi(p,-1),p=null,void 0;if(p=null,1&n){t=e[0],h+=mi(t,1);var u,i=t.length-1,a=-1;for(r.lineStart();i>++a;)r.point((u=t[a])[0],u[1]);return r.lineEnd(),void 0}i>1&&2&n&&e.push(e.pop().concat(e.shift())),f.push(e.filter(gi))}var f,h,d,g,p,m=n(r),v={point:i,lineStart:a,lineEnd:o,polygonStart:function(){v.point=c,v.lineStart=l,v.lineEnd=s,g=!1,d=h=0,f=[],r.polygonStart()
+},polygonEnd:function(){v.point=i,v.lineStart=a,v.lineEnd=o,f=d3.merge(f),f.length?fi(f,e,r):(-Pu>h||g&&-Pu>d)&&(r.lineStart(),e(null,null,1,r),r.lineEnd()),r.polygonEnd(),f=null},sphere:function(){r.polygonStart(),r.lineStart(),e(null,null,1,r),r.lineEnd(),r.polygonEnd()}},y=pi(),M=n(y);return v}}function fi(t,n,e){var r=[],i=[];if(t.forEach(function(t){var n=t.length;if(!(1>=n)){var e=t[0],u=t[n-1],a={point:e,points:t,other:null,visited:!1,entry:!0,subject:!0},o={point:e,points:[e],other:a,visited:!1,entry:!1,subject:!1};a.other=o,r.push(a),i.push(o),a={point:u,points:[u],other:null,visited:!1,entry:!1,subject:!0},o={point:u,points:[u],other:a,visited:!1,entry:!0,subject:!1},a.other=o,r.push(a),i.push(o)}}),i.sort(di),hi(r),hi(i),r.length)for(var u,a,o,c=r[0];;){for(u=c;u.visited;)if((u=u.next)===c)return;a=u.points,e.lineStart();do{if(u.visited=u.other.visited=!0,u.entry){if(u.subject)for(var l=0;a.length>l;l++)e.point((o=a[l])[0],o[1]);else n(u.point,u.next.point,1,e);u=u.next}else{if(u.subject){a=u.prev.points;for(var l=a.length;--l>=0;)e.point((o=a[l])[0],o[1])}else n(u.point,u.prev.point,-1,e);u=u.prev}u=u.other,a=u.points}while(!u.visited);e.lineEnd()}}function hi(t){if(n=t.length){for(var n,e,r=0,i=t[0];n>++r;)i.next=e=t[r],e.prev=i,i=e;i.next=e=t[0],e.prev=i}}function di(t,n){return(0>(t=t.point)[0]?t[1]-Ru/2-Pu:Ru/2-t[1])-(0>(n=n.point)[0]?n[1]-Ru/2-Pu:Ru/2-n[1])}function gi(t){return t.length>1}function pi(){var t,n=[];return{lineStart:function(){n.push(t=[])},point:function(n,e){t.push([n,e])},lineEnd:Pn,buffer:function(){var e=n;return n=[],t=null,e}}}function mi(t,n){if(!(e=t.length))return 0;for(var e,r,i,u=0,a=0,o=t[0],c=o[0],l=o[1],s=Math.cos(l),f=Math.atan2(n*Math.sin(c)*s,Math.sin(l)),h=1-n*Math.cos(c)*s,d=f;e>++u;)o=t[u],s=Math.cos(l=o[1]),r=Math.atan2(n*Math.sin(c=o[0])*s,Math.sin(l)),i=1-n*Math.cos(c)*s,Pu>Math.abs(h-2)&&Pu>Math.abs(i-2)||(Pu>Math.abs(i)||Pu>Math.abs(h)||(Pu>Math.abs(Math.abs(r-f)-Ru)?i+h>2&&(a+=4*(r-f)):a+=Pu>Math.abs(h-2)?4*(r-d):((3*Ru+r-f)%(2*Ru)-Ru)*(h+i)),d=f,f=r,h=i);return a}function vi(t){var n,e=0/0,r=0/0,i=0/0;return{lineStart:function(){t.lineStart(),n=1},point:function(u,a){var o=u>0?Ru:-Ru,c=Math.abs(u-e);Pu>Math.abs(c-Ru)?(t.point(e,r=(r+a)/2>0?Ru/2:-Ru/2),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(o,r),t.point(u,r),n=0):i!==o&&c>=Ru&&(Pu>Math.abs(e-i)&&(e-=i*Pu),Pu>Math.abs(u-o)&&(u-=o*Pu),r=yi(e,r,u,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(o,r),n=0),t.point(e=u,r=a),i=o},lineEnd:function(){t.lineEnd(),e=r=0/0},clean:function(){return 2-n}}}function yi(t,n,e,r){var i,u,a=Math.sin(t-e);return Math.abs(a)>Pu?Math.atan((Math.sin(n)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(n))*Math.sin(t))/(i*u*a)):(n+r)/2}function Mi(t,n,e,r){var i;if(null==t)i=e*Ru/2,r.point(-Ru,i),r.point(0,i),r.point(Ru,i),r.point(Ru,0),r.point(Ru,-i),r.point(0,-i),r.point(-Ru,-i),r.point(-Ru,0),r.point(-Ru,i);else if(Math.abs(t[0]-n[0])>Pu){var u=(t[0]<n[0]?1:-1)*Ru;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(n[0],n[1])}function bi(t){function n(t,n){return Math.cos(t)*Math.cos(n)>u}function e(t){var e,i,u,a;return{lineStart:function(){u=i=!1,a=1},point:function(o,c){var l,s=[o,c],f=n(o,c);!e&&(u=i=f)&&t.lineStart(),f!==i&&(l=r(e,s),($r(e,l)||$r(s,l))&&(s[0]+=Pu,s[1]+=Pu,f=n(s[0],s[1]))),f!==i&&(a=0,(i=f)?(t.lineStart(),l=r(s,e),t.point(l[0],l[1])):(l=r(e,s),t.point(l[0],l[1]),t.lineEnd()),e=l),!f||e&&$r(e,s)||t.point(s[0],s[1]),e=s},lineEnd:function(){i&&t.lineEnd(),e=null},clean:function(){return a|(u&&i)<<1}}}function r(t,n){var e=Jr(t,0),r=Jr(n,0),i=[1,0,0],a=Kr(e,r),o=Gr(a,a),c=a[0],l=o-c*c;if(!l)return t;var s=u*o/l,f=-u*c/l,h=Kr(i,a),d=Qr(i,s),g=Qr(a,f);Wr(d,g);var p=h,m=Gr(d,p),v=Gr(p,p),y=Math.sqrt(m*m-v*(Gr(d,d)-1)),M=Qr(p,(-m-y)/v);return Wr(M,d),Br(M)}var i=t*ju,u=Math.cos(i),a=ci(i,6*ju);return si(n,e,a)}function xi(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return e=n.invert(e,r),e&&t.invert(e[0],e[1])}),e}function _i(t,n){return[t,n]}function wi(t,n,e){var r=d3.range(t,n-Pu,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Si(t,n,e){var r=d3.range(t,n-Pu,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ki(t,n,e,r){function i(t){var n=Math.sin(t*=d)*g,e=Math.sin(d-t)*g,r=e*l+n*f,i=e*s+n*h,u=e*a+n*c;return[Math.atan2(i,r)/ju,Math.atan2(u,Math.sqrt(r*r+i*i))/ju]}var u=Math.cos(n),a=Math.sin(n),o=Math.cos(r),c=Math.sin(r),l=u*Math.cos(t),s=u*Math.sin(t),f=o*Math.cos(e),h=o*Math.sin(e),d=Math.acos(Math.max(-1,Math.min(1,a*c+u*o*Math.cos(e-t)))),g=1/Math.sin(d);return i.distance=d,i}function Ei(t,n){return[t/(2*Ru),Math.max(-.5,Math.min(.5,Math.log(Math.tan(Ru/4+n/2))/(2*Ru)))]}function Ai(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Ni(t){var n=ni(function(n,e){return t([n*Ou,e*Ou])});return function(t){return t=n(t),{point:function(n,e){t.point(n*ju,e*ju)},sphere:function(){t.sphere()},lineStart:function(){t.lineStart()},lineEnd:function(){t.lineEnd()},polygonStart:function(){t.polygonStart()},polygonEnd:function(){t.polygonEnd()}}}}function Ti(){function t(t,n){a.push("M",t,",",n,u)}function n(t,n){a.push("M",t,",",n),o.point=e}function e(t,n){a.push("L",t,",",n)}function r(){o.point=t}function i(){a.push("Z")}var u=Ai(4.5),a=[],o={point:t,lineStart:function(){o.point=n},lineEnd:r,polygonStart:function(){o.lineEnd=i},polygonEnd:function(){o.lineEnd=r,o.point=t},pointRadius:function(t){return u=Ai(t),o},result:function(){if(a.length){var t=a.join("");return a=[],t}}};return o}function qi(t){function n(n,e){t.moveTo(n,e),t.arc(n,e,a,0,2*Ru)}function e(n,e){t.moveTo(n,e),o.point=r}function r(n,e){t.lineTo(n,e)}function i(){o.point=n}function u(){t.closePath()}var a=4.5,o={point:n,lineStart:function(){o.point=e},lineEnd:i,polygonStart:function(){o.lineEnd=u},polygonEnd:function(){o.lineEnd=i,o.point=n},pointRadius:function(t){return a=t,o},result:Pn};return o}function Ci(){function t(t,n){po+=i*t-r*n,r=t,i=n}var n,e,r,i;mo.point=function(u,a){mo.point=t,n=r=u,e=i=a},mo.lineEnd=function(){t(n,e)}}function zi(t,n){io||(ao+=t,oo+=n,++co)}function Di(){function t(t,r){var i=t-n,u=r-e,a=Math.sqrt(i*i+u*u);ao+=a*(n+t)/2,oo+=a*(e+r)/2,co+=a,n=t,e=r}var n,e;if(1!==io){if(!(1>io))return;io=1,ao=oo=co=0}vo.point=function(r,i){vo.point=t,n=r,e=i}}function Li(){vo.point=zi}function Fi(){function t(t,n){var e=i*t-r*n;ao+=e*(r+t),oo+=e*(i+n),co+=3*e,r=t,i=n}var n,e,r,i;2>io&&(io=2,ao=oo=co=0),vo.point=function(u,a){vo.point=t,n=r=u,e=i=a},vo.lineEnd=function(){t(n,e)}}function Hi(){function t(t,n){if(t*=ju,n*=ju,!(Pu>Math.abs(Math.abs(u)-Ru/2)&&Pu>Math.abs(Math.abs(n)-Ru/2))){var e=Math.cos(n),c=Math.sin(n);if(Pu>Math.abs(u-Ru/2))Mo+=2*(t-r);else{var l=t-i,s=Math.cos(l),f=Math.atan2(Math.sqrt((f=e*Math.sin(l))*f+(f=a*c-o*e*s)*f),o*c+a*e*s),h=(f+Ru+u+n)/4;Mo+=(0>l&&l>-Ru||l>Ru?-4:4)*Math.atan(Math.sqrt(Math.abs(Math.tan(h)*Math.tan(h-f/2)*Math.tan(h-Ru/4-u/2)*Math.tan(h-Ru/4-n/2))))}r=i,i=t,u=n,a=e,o=c}}var n,e,r,i,u,a,o;bo.point=function(c,l){bo.point=t,r=i=(n=c)*ju,u=(e=l)*ju,a=Math.cos(u),o=Math.sin(u)},bo.lineEnd=function(){t(n,e)}}function Ri(t){return Pi(function(){return t})()}function Pi(t){function n(t){return t=a(t[0]*ju,t[1]*ju),[t[0]*s+o,c-t[1]*s]}function e(t){return t=a.invert((t[0]-o)/s,(c-t[1])/s),t&&[t[0]*Ou,t[1]*Ou]}function r(){a=xi(u=Oi(p,m,v),i);var t=i(d,g);return o=f-t[0]*s,c=h+t[1]*s,n}var i,u,a,o,c,l=ni(function(t,n){return t=i(t,n),[t[0]*s+o,c-t[1]*s]}),s=150,f=480,h=250,d=0,g=0,p=0,m=0,v=0,y=so,M=null;return n.stream=function(t){return ji(u,y(l(t)))},n.clipAngle=function(t){return arguments.length?(y=null==t?(M=t,so):bi(M=+t),n):M},n.scale=function(t){return arguments.length?(s=+t,r()):s},n.translate=function(t){return arguments.length?(f=+t[0],h=+t[1],r()):[f,h]},n.center=function(t){return arguments.length?(d=t[0]%360*ju,g=t[1]%360*ju,r()):[d*Ou,g*Ou]},n.rotate=function(t){return arguments.length?(p=t[0]%360*ju,m=t[1]%360*ju,v=t.length>2?t[2]%360*ju:0,r()):[p*Ou,m*Ou,v*Ou]},d3.rebind(n,l,"precision"),function(){return i=t.apply(this,arguments),n.invert=i.invert&&e,r()}}function ji(t,n){return{point:function(e,r){r=t(e*ju,r*ju),e=r[0],n.point(e>Ru?e-2*Ru:-Ru>e?e+2*Ru:e,r[1])},sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function Oi(t,n,e){return t?n||e?xi(Ui(t),Ii(n,e)):Ui(t):n||e?Ii(n,e):_i}function Yi(t){return function(n,e){return n+=t,[n>Ru?n-2*Ru:-Ru>n?n+2*Ru:n,e]}}function Ui(t){var n=Yi(t);return n.invert=Yi(-t),n}function Ii(t,n){function e(t,n){var e=Math.cos(n),o=Math.cos(t)*e,c=Math.sin(t)*e,l=Math.sin(n),s=l*r+o*i;return[Math.atan2(c*u-s*a,o*r-l*i),Math.asin(Math.max(-1,Math.min(1,s*u+c*a)))]}var r=Math.cos(t),i=Math.sin(t),u=Math.cos(n),a=Math.sin(n);return e.invert=function(t,n){var e=Math.cos(n),o=Math.cos(t)*e,c=Math.sin(t)*e,l=Math.sin(n),s=l*u-c*a;return[Math.atan2(c*u+l*a,o*r+s*i),Math.asin(Math.max(-1,Math.min(1,s*r-o*i)))]},e}function Vi(t,n){function e(n,e){var r=Math.cos(n),i=Math.cos(e),u=t(r*i);return[u*i*Math.sin(n),u*Math.sin(e)]}return e.invert=function(t,e){var r=Math.sqrt(t*t+e*e),i=n(r),u=Math.sin(i),a=Math.cos(i);return[Math.atan2(t*u,r*a),Math.asin(r&&e*u/r)]},e}function Xi(t,n,e,r){var i,u,a,o,c,l,s;return i=r[t],u=i[0],a=i[1],i=r[n],o=i[0],c=i[1],i=r[e],l=i[0],s=i[1],(s-a)*(o-u)-(c-a)*(l-u)>0}function Zi(t,n,e){return(e[0]-n[0])*(t[1]-n[1])<(e[1]-n[1])*(t[0]-n[0])}function Bi(t,n,e,r){var i=t[0],u=e[0],a=n[0]-i,o=r[0]-u,c=t[1],l=e[1],s=n[1]-c,f=r[1]-l,h=(o*(c-l)-f*(i-u))/(f*a-o*s);return[i+h*a,c+h*s]}function $i(t,n){var e={list:t.map(function(t,n){return{index:n,x:t[0],y:t[1]}}).sort(function(t,n){return t.y<n.y?-1:t.y>n.y?1:t.x<n.x?-1:t.x>n.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,"l"),r.rightEnd=r.createHalfEdge(null,"l"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(t,n){return{edge:t,side:n,vertex:null,l:null,r:null}},insert:function(t,n){n.l=t,n.r=t.r,t.r.l=n,t.r=n},leftBound:function(t){var n=r.leftEnd;do n=n.r;while(n!=r.rightEnd&&i.rightOf(n,t));return n=n.l},del:function(t){t.l.r=t.r,t.r.l=t.l,t.edge=null},right:function(t){return t.r},left:function(t){return t.l},leftRegion:function(t){return null==t.edge?e.bottomSite:t.edge.region[t.side]},rightRegion:function(t){return null==t.edge?e.bottomSite:t.edge.region[_o[t.side]]}},i={bisect:function(t,n){var e={region:{l:t,r:n},ep:{l:null,r:null}},r=n.x-t.x,i=n.y-t.y,u=r>0?r:-r,a=i>0?i:-i;return e.c=t.x*r+t.y*i+.5*(r*r+i*i),u>a?(e.a=1,e.b=i/r,e.c/=r):(e.b=1,e.a=r/i,e.c/=i),e},intersect:function(t,n){var e=t.edge,r=n.edge;if(!e||!r||e.region.r==r.region.r)return null;var i=e.a*r.b-e.b*r.a;if(1e-10>Math.abs(i))return null;var u,a,o=(e.c*r.b-r.c*e.b)/i,c=(r.c*e.a-e.c*r.a)/i,l=e.region.r,s=r.region.r;l.y<s.y||l.y==s.y&&l.x<s.x?(u=t,a=e):(u=n,a=r);var f=o>=a.region.r.x;return f&&"l"===u.side||!f&&"r"===u.side?null:{x:o,y:c}},rightOf:function(t,n){var e=t.edge,r=e.region.r,i=n.x>r.x;if(i&&"l"===t.side)return 1;if(!i&&"r"===t.side)return 0;if(1===e.a){var u=n.y-r.y,a=n.x-r.x,o=0,c=0;if(!i&&0>e.b||i&&e.b>=0?c=o=u>=e.b*a:(c=n.x+n.y*e.b>e.c,0>e.b&&(c=!c),c||(o=1)),!o){var l=r.x-e.region.l.x;c=e.b*(a*a-u*u)<l*u*(1+2*a/l+e.b*e.b),0>e.b&&(c=!c)}}else{var s=e.c-e.a*n.x,f=n.y-s,h=n.x-r.x,d=s-r.y;c=f*f>h*h+d*d}return"l"===t.side?c:!c},endPoint:function(t,e,r){t.ep[e]=r,t.ep[_o[e]]&&n(t)},distance:function(t,n){var e=t.x-n.x,r=t.y-n.y;return Math.sqrt(e*e+r*r)}},u={list:[],insert:function(t,n,e){t.vertex=n,t.ystar=n.y+e;for(var r=0,i=u.list,a=i.length;a>r;r++){var o=i[r];if(!(t.ystar>o.ystar||t.ystar==o.ystar&&n.x>o.vertex.x))break}i.splice(r,0,t)},del:function(t){for(var n=0,e=u.list,r=e.length;r>n&&e[n]!=t;++n);e.splice(n,1)},empty:function(){return 0===u.list.length},nextEvent:function(t){for(var n=0,e=u.list,r=e.length;r>n;++n)if(e[n]==t)return e[n+1];return null},min:function(){var t=u.list[0];return{x:t.vertex.x,y:t.ystar}},extractMin:function(){return u.list.shift()}};r.init(),e.bottomSite=e.list.shift();for(var a,o,c,l,s,f,h,d,g,p,m,v,y,M=e.list.shift();;)if(u.empty()||(a=u.min()),M&&(u.empty()||M.y<a.y||M.y==a.y&&M.x<a.x))o=r.leftBound(M),c=r.right(o),h=r.rightRegion(o),v=i.bisect(h,M),f=r.createHalfEdge(v,"l"),r.insert(o,f),p=i.intersect(o,f),p&&(u.del(o),u.insert(o,p,i.distance(p,M))),o=f,f=r.createHalfEdge(v,"r"),r.insert(o,f),p=i.intersect(f,c),p&&u.insert(f,p,i.distance(p,M)),M=e.list.shift();else{if(u.empty())break;o=u.extractMin(),l=r.left(o),c=r.right(o),s=r.right(c),h=r.leftRegion(o),d=r.rightRegion(c),m=o.vertex,i.endPoint(o.edge,o.side,m),i.endPoint(c.edge,c.side,m),r.del(o),u.del(c),r.del(c),y="l",h.y>d.y&&(g=h,h=d,d=g,y="r"),v=i.bisect(h,d),f=r.createHalfEdge(v,y),r.insert(l,f),i.endPoint(v,_o[y],m),p=i.intersect(l,f),p&&(u.del(l),u.insert(l,p,i.distance(p,h))),p=i.intersect(f,s),p&&u.insert(f,p,i.distance(p,h))}for(o=r.right(r.leftEnd);o!=r.rightEnd;o=r.right(o))n(o.edge)}function Ji(){return{leaf:!0,nodes:[],point:null}}function Gi(t,n,e,r,i,u){if(!t(n,e,r,i,u)){var a=.5*(e+i),o=.5*(r+u),c=n.nodes;c[0]&&Gi(t,c[0],e,r,a,o),c[1]&&Gi(t,c[1],a,r,i,o),c[2]&&Gi(t,c[2],e,o,a,u),c[3]&&Gi(t,c[3],a,o,i,u)}}function Ki(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Wi(t,n,e,r){for(var i,u,a=0,o=n.length,c=e.length;o>a;){if(r>=c)return-1;if(i=n.charCodeAt(a++),37===i){if(u=Yo[n.charAt(a++)],!u||0>(r=u(t,e,r)))return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function Qi(t){return RegExp("^(?:"+t.map(d3.requote).join("|")+")","i")}function tu(t){for(var n=new u,e=-1,r=t.length;r>++e;)n.set(t[e].toLowerCase(),e);return n}function nu(t,n,e){t+="";var r=t.length;return e>r?Array(e-r+1).join(n)+t:t}function eu(t,n,e){Lo.lastIndex=0;var r=Lo.exec(n.substring(e));return r?e+=r[0].length:-1}function ru(t,n,e){Do.lastIndex=0;var r=Do.exec(n.substring(e));return r?e+=r[0].length:-1}function iu(t,n,e){Ro.lastIndex=0;var r=Ro.exec(n.substring(e));return r?(t.m=Po.get(r[0].toLowerCase()),e+=r[0].length):-1}function uu(t,n,e){Fo.lastIndex=0;var r=Fo.exec(n.substring(e));return r?(t.m=Ho.get(r[0].toLowerCase()),e+=r[0].length):-1}function au(t,n,e){return Wi(t,""+Oo.c,n,e)}function ou(t,n,e){return Wi(t,""+Oo.x,n,e)}function cu(t,n,e){return Wi(t,""+Oo.X,n,e)}function lu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+4));return r?(t.y=+r[0],e+=r[0].length):-1}function su(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.y=fu(+r[0]),e+=r[0].length):-1}function fu(t){return t+(t>68?1900:2e3)}function hu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.m=r[0]-1,e+=r[0].length):-1}function du(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.d=+r[0],e+=r[0].length):-1}function gu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.H=+r[0],e+=r[0].length):-1}function pu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.M=+r[0],e+=r[0].length):-1}function mu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+2));return r?(t.S=+r[0],e+=r[0].length):-1}function vu(t,n,e){Uo.lastIndex=0;var r=Uo.exec(n.substring(e,e+3));return r?(t.L=+r[0],e+=r[0].length):-1}function yu(t,n,e){var r=Io.get(n.substring(e,e+=2).toLowerCase());return null==r?-1:(t.p=r,e)}function Mu(t){var n=t.getTimezoneOffset(),e=n>0?"-":"+",r=~~(Math.abs(n)/60),i=Math.abs(n)%60;return e+nu(r,"0",2)+nu(i,"0",2)}function bu(t){return t.toISOString()}function xu(t,n,e){function r(n){var e=t(n),r=u(e,1);return r-n>n-e?e:r}function i(e){return n(e=t(new wo(e-1)),1),e}function u(t,e){return n(t=new wo(+t),e),t}function a(t,r,u){var a=i(t),o=[];if(u>1)for(;r>a;)e(a)%u||o.push(new Date(+a)),n(a,1);else for(;r>a;)o.push(new Date(+a)),n(a,1);return o}function o(t,n,e){try{wo=Ki;var r=new Ki;return r._=t,a(r,n,e)}finally{wo=Date}}t.floor=t,t.round=r,t.ceil=i,t.offset=u,t.range=a;var c=t.utc=_u(t);return c.floor=c,c.round=_u(r),c.ceil=_u(i),c.offset=_u(u),c.range=o,t}function _u(t){return function(n,e){try{wo=Ki;var r=new Ki;return r._=n,t(r,e)._}finally{wo=Date}}}function wu(t,n,e){function r(n){return t(n)}return r.invert=function(n){return ku(t.invert(n))},r.domain=function(n){return arguments.length?(t.domain(n),r):t.domain().map(ku)},r.nice=function(t){return r.domain(Yn(r.domain(),function(){return t}))},r.ticks=function(e,i){var u=Su(r.domain());if("function"!=typeof e){var a=u[1]-u[0],o=a/e,c=d3.bisect(Xo,o);if(c==Xo.length)return n.year(u,e);if(!c)return t.ticks(e).map(ku);Math.log(o/Xo[c-1])<Math.log(Xo[c]/o)&&--c,e=n[c],i=e[1],e=e[0].range}return e(u[0],new Date(+u[1]+1),i)},r.tickFormat=function(){return e},r.copy=function(){return wu(t.copy(),n,e)},d3.rebind(r,t,"range","rangeRound","interpolate","clamp")}function Su(t){var n=t[0],e=t[t.length-1];return e>n?[n,e]:[e,n]}function ku(t){return new Date(t)}function Eu(t){return function(n){for(var e=t.length-1,r=t[e];!r[1](n);)r=t[--e];return r[0](n)}}function Au(t){var n=new Date(t,0,1);return n.setFullYear(t),n}function Nu(t){var n=t.getFullYear(),e=Au(n),r=Au(n+1);return n+(t-e)/(r-e)}function Tu(t){var n=new Date(Date.UTC(t,0,1));return n.setUTCFullYear(t),n}function qu(t){var n=t.getUTCFullYear(),e=Tu(n),r=Tu(n+1);return n+(t-e)/(r-e)}var Cu=".",zu=",",Du=[3,3];Date.now||(Date.now=function(){return+new Date});try{document.createElement("div").style.setProperty("opacity",0,"")}catch(Lu){var Fu=CSSStyleDeclaration.prototype,Hu=Fu.setProperty;Fu.setProperty=function(t,n,e){Hu.call(this,t,n+"",e)}}d3={version:"3.0.3"};var Ru=Math.PI,Pu=1e-6,ju=Ru/180,Ou=180/Ru,Yu=i;try{Yu(document.documentElement.childNodes)[0].nodeType}catch(Uu){Yu=r}var Iu=[].__proto__?function(t,n){t.__proto__=n}:function(t,n){for(var e in n)t[e]=n[e]};d3.map=function(t){var n=new u;for(var e in t)n.set(e,t[e]);return n},e(u,{has:function(t){return Vu+t in this},get:function(t){return this[Vu+t]},set:function(t,n){return this[Vu+t]=n},remove:function(t){return t=Vu+t,t in this&&delete this[t]},keys:function(){var t=[];return this.forEach(function(n){t.push(n)}),t},values:function(){var t=[];return this.forEach(function(n,e){t.push(e)}),t},entries:function(){var t=[];return this.forEach(function(n,e){t.push({key:n,value:e})}),t},forEach:function(t){for(var n in this)n.charCodeAt(0)===Xu&&t.call(this,n.substring(1),this[n])}});var Vu="\0",Xu=Vu.charCodeAt(0);d3.functor=c,d3.rebind=function(t,n){for(var e,r=1,i=arguments.length;i>++r;)t[e=arguments[r]]=l(t,n,n[e]);return t},d3.ascending=function(t,n){return n>t?-1:t>n?1:t>=n?0:0/0},d3.descending=function(t,n){return t>n?-1:n>t?1:n>=t?0:0/0},d3.mean=function(t,n){var e,r=t.length,i=0,u=-1,a=0;if(1===arguments.length)for(;r>++u;)s(e=t[u])&&(i+=(e-i)/++a);else for(;r>++u;)s(e=n.call(t,t[u],u))&&(i+=(e-i)/++a);return a?i:void 0},d3.median=function(t,n){return arguments.length>1&&(t=t.map(n)),t=t.filter(s),t.length?d3.quantile(t.sort(d3.ascending),.5):void 0},d3.min=function(t,n){var e,r,i=-1,u=t.length;if(1===arguments.length){for(;u>++i&&(null==(e=t[i])||e!=e);)e=void 0;for(;u>++i;)null!=(r=t[i])&&e>r&&(e=r)}else{for(;u>++i&&(null==(e=n.call(t,t[i],i))||e!=e);)e=void 0;for(;u>++i;)null!=(r=n.call(t,t[i],i))&&e>r&&(e=r)}return e},d3.max=function(t,n){var e,r,i=-1,u=t.length;if(1===arguments.length){for(;u>++i&&(null==(e=t[i])||e!=e);)e=void 0;for(;u>++i;)null!=(r=t[i])&&r>e&&(e=r)}else{for(;u>++i&&(null==(e=n.call(t,t[i],i))||e!=e);)e=void 0;for(;u>++i;)null!=(r=n.call(t,t[i],i))&&r>e&&(e=r)}return e},d3.extent=function(t,n){var e,r,i,u=-1,a=t.length;if(1===arguments.length){for(;a>++u&&(null==(e=i=t[u])||e!=e);)e=i=void 0;for(;a>++u;)null!=(r=t[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;a>++u&&(null==(e=i=n.call(t,t[u],u))||e!=e);)e=void 0;for(;a>++u;)null!=(r=n.call(t,t[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},d3.random={normal:function(t,n){var e=arguments.length;return 2>e&&(n=1),1>e&&(t=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return t+n*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(t,n){var e=arguments.length;2>e&&(n=1),1>e&&(t=0);var r=d3.random.normal();return function(){return Math.exp(t+n*r())}},irwinHall:function(t){return function(){for(var n=0,e=0;t>e;e++)n+=Math.random();return n/t}}},d3.sum=function(t,n){var e,r=0,i=t.length,u=-1;if(1===arguments.length)for(;i>++u;)isNaN(e=+t[u])||(r+=e);else for(;i>++u;)isNaN(e=+n.call(t,t[u],u))||(r+=e);return r},d3.quantile=function(t,n){var e=(t.length-1)*n+1,r=Math.floor(e),i=+t[r-1],u=e-r;return u?i+u*(t[r]-i):i},d3.shuffle=function(t){for(var n,e,r=t.length;r;)e=0|Math.random()*r--,n=t[r],t[r]=t[e],t[e]=n;return t},d3.transpose=function(t){return d3.zip.apply(d3,t)},d3.zip=function(){if(!(r=arguments.length))return[];for(var t=-1,n=d3.min(arguments,f),e=Array(n);n>++t;)for(var r,i=-1,u=e[t]=Array(r);r>++i;)u[i]=arguments[i][t];return e},d3.bisector=function(t){return{left:function(n,e,r,i){for(3>arguments.length&&(r=0),4>arguments.length&&(i=n.length);i>r;){var u=r+i>>>1;e>t.call(n,n[u],u)?r=u+1:i=u}return r},right:function(n,e,r,i){for(3>arguments.length&&(r=0),4>arguments.length&&(i=n.length);i>r;){var u=r+i>>>1;t.call(n,n[u],u)>e?i=u:r=u+1}return r}}};var Zu=d3.bisector(function(t){return t});d3.bisectLeft=Zu.left,d3.bisect=d3.bisectRight=Zu.right,d3.nest=function(){function t(n,o){if(o>=a.length)return r?r.call(i,n):e?n.sort(e):n;for(var c,l,s,f=-1,h=n.length,d=a[o++],g=new u,p={};h>++f;)(s=g.get(c=d(l=n[f])))?s.push(l):g.set(c,[l]);return g.forEach(function(n,e){p[n]=t(e,o)}),p}function n(t,e){if(e>=a.length)return t;var r,i=[],u=o[e++];for(r in t)i.push({key:r,values:n(t[r],e)});return u&&i.sort(function(t,n){return u(t.key,n.key)}),i}var e,r,i={},a=[],o=[];return i.map=function(n){return t(n,0)},i.entries=function(e){return n(t(e,0),0)},i.key=function(t){return a.push(t),i},i.sortKeys=function(t){return o[a.length-1]=t,i},i.sortValues=function(t){return e=t,i},i.rollup=function(t){return r=t,i},i},d3.keys=function(t){var n=[];for(var e in t)n.push(e);return n},d3.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},d3.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},d3.permute=function(t,n){for(var e=[],r=-1,i=n.length;i>++r;)e[r]=t[n[r]];return e},d3.merge=function(t){return Array.prototype.concat.apply([],t)},d3.range=function(t,n,e){if(3>arguments.length&&(e=1,2>arguments.length&&(n=t,t=0)),1/0===(n-t)/e)throw Error("infinite range");var r,i=[],u=d(Math.abs(e)),a=-1;if(t*=u,n*=u,e*=u,0>e)for(;(r=t+e*++a)>n;)i.push(r/u);else for(;n>(r=t+e*++a);)i.push(r/u);return i},d3.requote=function(t){return t.replace(Bu,"\\$&")};var Bu=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;d3.round=function(t,n){return n?Math.round(t*(n=Math.pow(10,n)))/n:Math.round(t)},d3.xhr=function(t,n,e){function r(){var t=l.status;!t&&l.responseText||t>=200&&300>t||304===t?u.load.call(i,c.call(i,l)):u.error.call(i,l)}var i={},u=d3.dispatch("progress","load","error"),o={},c=a,l=new(window.XDomainRequest&&/^(http(s)?:)?\/\//.test(t)?XDomainRequest:XMLHttpRequest);return"onload"in l?l.onload=l.onerror=r:l.onreadystatechange=function(){l.readyState>3&&r()},l.onprogress=function(t){var n=d3.event;d3.event=t;try{u.progress.call(i,l)}finally{d3.event=n}},i.header=function(t,n){return t=(t+"").toLowerCase(),2>arguments.length?o[t]:(null==n?delete o[t]:o[t]=n+"",i)},i.mimeType=function(t){return arguments.length?(n=null==t?null:t+"",i):n},i.response=function(t){return c=t,i},["get","post"].forEach(function(t){i[t]=function(){return i.send.apply(i,[t].concat(Yu(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),l.open(e,t,!0),null==n||"accept"in o||(o.accept=n+",*/*"),l.setRequestHeader)for(var a in o)l.setRequestHeader(a,o[a]);return null!=n&&l.overrideMimeType&&l.overrideMimeType(n),null!=u&&i.on("error",u).on("load",function(t){u(null,t)}),l.send(null==r?null:r),i},i.abort=function(){return l.abort(),i},d3.rebind(i,u,"on"),2===arguments.length&&"function"==typeof n&&(e=n,n=null),null==e?i:i.get(g(e))},d3.text=function(){return d3.xhr.apply(d3,arguments).response(p)},d3.json=function(t,n){return d3.xhr(t,"application/json",n).response(m)},d3.html=function(t,n){return d3.xhr(t,"text/html",n).response(v)},d3.xml=function(){return d3.xhr.apply(d3,arguments).response(y)};var $u={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};d3.ns={prefix:$u,qualify:function(t){var n=t.indexOf(":"),e=t;return n>=0&&(e=t.substring(0,n),t=t.substring(n+1)),$u.hasOwnProperty(e)?{space:$u[e],local:t}:t}},d3.dispatch=function(){for(var t=new M,n=-1,e=arguments.length;e>++n;)t[arguments[n]]=b(t);return t},M.prototype.on=function(t,n){var e=t.indexOf("."),r="";return e>0&&(r=t.substring(e+1),t=t.substring(0,e)),2>arguments.length?this[t].on(r):this[t].on(r,n)},d3.format=function(t){var n=Ju.exec(t),e=n[1]||" ",r=n[2]||">",i=n[3]||"",u=n[4]||"",a=n[5],o=+n[6],c=n[7],l=n[8],s=n[9],f=1,h="",d=!1;switch(l&&(l=+l.substring(1)),(a||"0"===e&&"="===r)&&(a=e="0",r="=",c&&(o-=Math.floor((o-1)/4))),s){case"n":c=!0,s="g";break;case"%":f=100,h="%",s="f";break;case"p":f=100,h="%",s="r";break;case"b":case"o":case"x":case"X":u&&(u="0"+s.toLowerCase());case"c":case"d":d=!0,l=0;break;case"s":f=-1,s="r"}"#"===u&&(u=""),"r"!=s||l||(s="g"),s=Gu.get(s)||_;var g=a&&c;return function(t){if(d&&t%1)return"";var n=0>t||0===t&&0>1/t?(t=-t,"-"):i;if(0>f){var p=d3.formatPrefix(t,l);t=p.scale(t),h=p.symbol}else t*=f;t=s(t,l),!a&&c&&(t=Ku(t));var m=u.length+t.length+(g?0:n.length),v=o>m?Array(m=o-m+1).join(e):"";return g&&(t=Ku(v+t)),Cu&&t.replace(".",Cu),n+=u,("<"===r?n+t+v:">"===r?v+n+t:"^"===r?v.substring(0,m>>=1)+n+t+v.substring(m):n+(g?t:v+t))+h}};var Ju=/(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/,Gu=d3.map({b:function(t){return t.toString(2)},c:function(t){return String.fromCharCode(t)},o:function(t){return t.toString(8)},x:function(t){return t.toString(16)},X:function(t){return t.toString(16).toUpperCase()},g:function(t,n){return t.toPrecision(n)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},r:function(t,n){return d3.round(t,n=x(t,n)).toFixed(Math.max(0,Math.min(20,n)))}}),Ku=a;if(Du){var Wu=Du.length;Ku=function(t){for(var n=t.lastIndexOf("."),e=n>=0?"."+t.substring(n+1):(n=t.length,""),r=[],i=0,u=Du[0];n>0&&u>0;)r.push(t.substring(n-=u,n+u)),u=Du[i=(i+1)%Wu];return r.reverse().join(zu||"")+e}}var Qu=["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(w);d3.formatPrefix=function(t,n){var e=0;return t&&(0>t&&(t*=-1),n&&(t=d3.round(t,x(t,n))),e=1+Math.floor(1e-12+Math.log(t)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),Qu[8+e/3]};var ta=function(){return a},na=d3.map({linear:ta,poly:q,quad:function(){return A},cubic:function(){return N},sin:function(){return C},exp:function(){return z},circle:function(){return D},elastic:L,back:F,bounce:function(){return H}}),ea=d3.map({"in":a,out:k,"in-out":E,"out-in":function(t){return E(k(t))}});d3.ease=function(t){var n=t.indexOf("-"),e=n>=0?t.substring(0,n):t,r=n>=0?t.substring(n+1):"in";return e=na.get(e)||ta,r=ea.get(r)||a,S(r(e.apply(null,Array.prototype.slice.call(arguments,1))))},d3.event=null,d3.transform=function(t){var n=document.createElementNS(d3.ns.prefix.svg,"g");return(d3.transform=function(t){n.setAttribute("transform",t);var e=n.transform.baseVal.consolidate();return new O(e?e.matrix:ra)})(t)},O.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var ra={a:1,b:0,c:0,d:1,e:0,f:0};d3.interpolate=function(t,n){for(var e,r=d3.interpolators.length;--r>=0&&!(e=d3.interpolators[r](t,n)););return e},d3.interpolateNumber=function(t,n){return n-=t,function(e){return t+n*e}},d3.interpolateRound=function(t,n){return n-=t,function(e){return Math.round(t+n*e)}},d3.interpolateString=function(t,n){var e,r,i,u,a,o=0,c=0,l=[],s=[];for(ia.lastIndex=0,r=0;e=ia.exec(n);++r)e.index&&l.push(n.substring(o,c=e.index)),s.push({i:l.length,x:e[0]}),l.push(null),o=ia.lastIndex;for(n.length>o&&l.push(n.substring(o)),r=0,u=s.length;(e=ia.exec(t))&&u>r;++r)if(a=s[r],a.x==e[0]){if(a.i)if(null==l[a.i+1])for(l[a.i-1]+=a.x,l.splice(a.i,1),i=r+1;u>i;++i)s[i].i--;else for(l[a.i-1]+=a.x+l[a.i+1],l.splice(a.i,2),i=r+1;u>i;++i)s[i].i-=2;else if(null==l[a.i+1])l[a.i]=a.x;else for(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1),i=r+1;u>i;++i)s[i].i--;s.splice(r,1),u--,r--}else a.x=d3.interpolateNumber(parseFloat(e[0]),parseFloat(a.x));for(;u>r;)a=s.pop(),null==l[a.i+1]?l[a.i]=a.x:(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1)),u--;return 1===l.length?null==l[0]?s[0].x:function(){return n}:function(t){for(r=0;u>r;++r)l[(a=s[r]).i]=a.x(t);return l.join("")}},d3.interpolateTransform=function(t,n){var e,r=[],i=[],u=d3.transform(t),a=d3.transform(n),o=u.translate,c=a.translate,l=u.rotate,s=a.rotate,f=u.skew,h=a.skew,d=u.scale,g=a.scale;return o[0]!=c[0]||o[1]!=c[1]?(r.push("translate(",null,",",null,")"),i.push({i:1,x:d3.interpolateNumber(o[0],c[0])},{i:3,x:d3.interpolateNumber(o[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),i.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:d3.interpolateNumber(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?i.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:d3.interpolateNumber(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),d[0]!=g[0]||d[1]!=g[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),i.push({i:e-4,x:d3.interpolateNumber(d[0],g[0])},{i:e-2,x:d3.interpolateNumber(d[1],g[1])})):(1!=g[0]||1!=g[1])&&r.push(r.pop()+"scale("+g+")"),e=i.length,function(t){for(var n,u=-1;e>++u;)r[(n=i[u]).i]=n.x(t);return r.join("")}},d3.interpolateRgb=function(t,n){t=d3.rgb(t),n=d3.rgb(n);var e=t.r,r=t.g,i=t.b,u=n.r-e,a=n.g-r,o=n.b-i;return function(t){return"#"+G(Math.round(e+u*t))+G(Math.round(r+a*t))+G(Math.round(i+o*t))}},d3.interpolateHsl=function(t,n){t=d3.hsl(t),n=d3.hsl(n);var e=t.h,r=t.s,i=t.l,u=n.h-e,a=n.s-r,o=n.l-i;return u>180?u-=360:-180>u&&(u+=360),function(t){return un(e+u*t,r+a*t,i+o*t)+""}},d3.interpolateLab=function(t,n){t=d3.lab(t),n=d3.lab(n);var e=t.l,r=t.a,i=t.b,u=n.l-e,a=n.a-r,o=n.b-i;return function(t){return fn(e+u*t,r+a*t,i+o*t)+""}},d3.interpolateHcl=function(t,n){t=d3.hcl(t),n=d3.hcl(n);var e=t.h,r=t.c,i=t.l,u=n.h-e,a=n.c-r,o=n.l-i;return u>180?u-=360:-180>u&&(u+=360),function(t){return cn(e+u*t,r+a*t,i+o*t)+""}},d3.interpolateArray=function(t,n){var e,r=[],i=[],u=t.length,a=n.length,o=Math.min(t.length,n.length);for(e=0;o>e;++e)r.push(d3.interpolate(t[e],n[e]));for(;u>e;++e)i[e]=t[e];for(;a>e;++e)i[e]=n[e];return function(t){for(e=0;o>e;++e)i[e]=r[e](t);return i}},d3.interpolateObject=function(t,n){var e,r={},i={};for(e in t)e in n?r[e]=V(e)(t[e],n[e]):i[e]=t[e];for(e in n)e in t||(i[e]=n[e]);return function(t){for(e in r)i[e]=r[e](t);return i}};var ia=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;d3.interpolators=[d3.interpolateObject,function(t,n){return n instanceof Array&&d3.interpolateArray(t,n)},function(t,n){return("string"==typeof t||"string"==typeof n)&&d3.interpolateString(t+"",n+"")},function(t,n){return("string"==typeof n?aa.has(n)||/^(#|rgb\(|hsl\()/.test(n):n instanceof B)&&d3.interpolateRgb(t,n)},function(t,n){return!isNaN(t=+t)&&!isNaN(n=+n)&&d3.interpolateNumber(t,n)}],B.prototype.toString=function(){return this.rgb()+""},d3.rgb=function(t,n,e){return 1===arguments.length?t instanceof J?$(t.r,t.g,t.b):K(""+t,$,un):$(~~t,~~n,~~e)};var ua=J.prototype=new B;ua.brighter=function(t){t=Math.pow(.7,arguments.length?t:1);var n=this.r,e=this.g,r=this.b,i=30;return n||e||r?(n&&i>n&&(n=i),e&&i>e&&(e=i),r&&i>r&&(r=i),$(Math.min(255,Math.floor(n/t)),Math.min(255,Math.floor(e/t)),Math.min(255,Math.floor(r/t)))):$(i,i,i)},ua.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),$(Math.floor(t*this.r),Math.floor(t*this.g),Math.floor(t*this.b))
+},ua.hsl=function(){return W(this.r,this.g,this.b)},ua.toString=function(){return"#"+G(this.r)+G(this.g)+G(this.b)};var aa=d3.map({aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"});aa.forEach(function(t,n){aa.set(t,K(n,$,un))}),d3.hsl=function(t,n,e){return 1===arguments.length?t instanceof rn?en(t.h,t.s,t.l):K(""+t,W,en):en(+t,+n,+e)};var oa=rn.prototype=new B;oa.brighter=function(t){return t=Math.pow(.7,arguments.length?t:1),en(this.h,this.s,this.l/t)},oa.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),en(this.h,this.s,t*this.l)},oa.rgb=function(){return un(this.h,this.s,this.l)},d3.hcl=function(t,n,e){return 1===arguments.length?t instanceof on?an(t.h,t.c,t.l):t instanceof sn?hn(t.l,t.a,t.b):hn((t=Q((t=d3.rgb(t)).r,t.g,t.b)).l,t.a,t.b):an(+t,+n,+e)};var ca=on.prototype=new B;ca.brighter=function(t){return an(this.h,this.c,Math.min(100,this.l+la*(arguments.length?t:1)))},ca.darker=function(t){return an(this.h,this.c,Math.max(0,this.l-la*(arguments.length?t:1)))},ca.rgb=function(){return cn(this.h,this.c,this.l).rgb()},d3.lab=function(t,n,e){return 1===arguments.length?t instanceof sn?ln(t.l,t.a,t.b):t instanceof on?cn(t.l,t.c,t.h):Q((t=d3.rgb(t)).r,t.g,t.b):ln(+t,+n,+e)};var la=18,sa=.95047,fa=1,ha=1.08883,da=sn.prototype=new B;da.brighter=function(t){return ln(Math.min(100,this.l+la*(arguments.length?t:1)),this.a,this.b)},da.darker=function(t){return ln(Math.max(0,this.l-la*(arguments.length?t:1)),this.a,this.b)},da.rgb=function(){return fn(this.l,this.a,this.b)};var ga=function(t,n){return n.querySelector(t)},pa=function(t,n){return n.querySelectorAll(t)},ma=document.documentElement,va=ma.matchesSelector||ma.webkitMatchesSelector||ma.mozMatchesSelector||ma.msMatchesSelector||ma.oMatchesSelector,ya=function(t,n){return va.call(t,n)};"function"==typeof Sizzle&&(ga=function(t,n){return Sizzle(t,n)[0]||null},pa=function(t,n){return Sizzle.uniqueSort(Sizzle(t,n))},ya=Sizzle.matchesSelector);var Ma=[];d3.selection=function(){return ba},d3.selection.prototype=Ma,Ma.select=function(t){var n,e,r,i,u=[];"function"!=typeof t&&(t=vn(t));for(var a=-1,o=this.length;o>++a;){u.push(n=[]),n.parentNode=(r=this[a]).parentNode;for(var c=-1,l=r.length;l>++c;)(i=r[c])?(n.push(e=t.call(i,i.__data__,c)),e&&"__data__"in i&&(e.__data__=i.__data__)):n.push(null)}return mn(u)},Ma.selectAll=function(t){var n,e,r=[];"function"!=typeof t&&(t=yn(t));for(var i=-1,u=this.length;u>++i;)for(var a=this[i],o=-1,c=a.length;c>++o;)(e=a[o])&&(r.push(n=Yu(t.call(e,e.__data__,o))),n.parentNode=e);return mn(r)},Ma.attr=function(t,n){if(2>arguments.length){if("string"==typeof t){var e=this.node();return t=d3.ns.qualify(t),t.local?e.getAttributeNS(t.space,t.local):e.getAttribute(t)}for(n in t)this.each(Mn(n,t[n]));return this}return this.each(Mn(t,n))},Ma.classed=function(t,n){if(2>arguments.length){if("string"==typeof t){var e=this.node(),r=(t=t.trim().split(/^|\s+/g)).length,i=-1;if(n=e.classList){for(;r>++i;)if(!n.contains(t[i]))return!1}else for(n=e.className,null!=n.baseVal&&(n=n.baseVal);r>++i;)if(!bn(t[i]).test(n))return!1;return!0}for(n in t)this.each(xn(n,t[n]));return this}return this.each(xn(t,n))},Ma.style=function(t,n,e){var r=arguments.length;if(3>r){if("string"!=typeof t){2>r&&(n="");for(e in t)this.each(wn(e,t[e],n));return this}if(2>r)return getComputedStyle(this.node(),null).getPropertyValue(t);e=""}return this.each(wn(t,n,e))},Ma.property=function(t,n){if(2>arguments.length){if("string"==typeof t)return this.node()[t];for(n in t)this.each(Sn(n,t[n]));return this}return this.each(Sn(t,n))},Ma.text=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}:null==t?function(){this.textContent=""}:function(){this.textContent=t}):this.node().textContent},Ma.html=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}:null==t?function(){this.innerHTML=""}:function(){this.innerHTML=t}):this.node().innerHTML},Ma.append=function(t){function n(){return this.appendChild(document.createElementNS(this.namespaceURI,t))}function e(){return this.appendChild(document.createElementNS(t.space,t.local))}return t=d3.ns.qualify(t),this.select(t.local?e:n)},Ma.insert=function(t,n){function e(){return this.insertBefore(document.createElementNS(this.namespaceURI,t),ga(n,this))}function r(){return this.insertBefore(document.createElementNS(t.space,t.local),ga(n,this))}return t=d3.ns.qualify(t),this.select(t.local?r:e)},Ma.remove=function(){return this.each(function(){var t=this.parentNode;t&&t.removeChild(this)})},Ma.data=function(t,n){function e(t,e){var r,i,a,o=t.length,f=e.length,h=Math.min(o,f),d=Array(f),g=Array(f),p=Array(o);if(n){var m,v=new u,y=new u,M=[];for(r=-1;o>++r;)m=n.call(i=t[r],i.__data__,r),v.has(m)?p[r]=i:v.set(m,i),M.push(m);for(r=-1;f>++r;)m=n.call(e,a=e[r],r),(i=v.get(m))?(d[r]=i,i.__data__=a):y.has(m)||(g[r]=kn(a)),y.set(m,a),v.remove(m);for(r=-1;o>++r;)v.has(M[r])&&(p[r]=t[r])}else{for(r=-1;h>++r;)i=t[r],a=e[r],i?(i.__data__=a,d[r]=i):g[r]=kn(a);for(;f>r;++r)g[r]=kn(e[r]);for(;o>r;++r)p[r]=t[r]}g.update=d,g.parentNode=d.parentNode=p.parentNode=t.parentNode,c.push(g),l.push(d),s.push(p)}var r,i,a=-1,o=this.length;if(!arguments.length){for(t=Array(o=(r=this[0]).length);o>++a;)(i=r[a])&&(t[a]=i.__data__);return t}var c=qn([]),l=mn([]),s=mn([]);if("function"==typeof t)for(;o>++a;)e(r=this[a],t.call(r,r.parentNode.__data__,a));else for(;o>++a;)e(r=this[a],t);return l.enter=function(){return c},l.exit=function(){return s},l},Ma.datum=function(t){return arguments.length?this.property("__data__",t):this.property("__data__")},Ma.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=En(t));for(var u=0,a=this.length;a>u;u++){i.push(n=[]),n.parentNode=(e=this[u]).parentNode;for(var o=0,c=e.length;c>o;o++)(r=e[o])&&t.call(r,r.__data__,o)&&n.push(r)}return mn(i)},Ma.order=function(){for(var t=-1,n=this.length;n>++t;)for(var e,r=this[t],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Ma.sort=function(t){t=An.apply(this,arguments);for(var n=-1,e=this.length;e>++n;)this[n].sort(t);return this.order()},Ma.on=function(t,n,e){var r=arguments.length;if(3>r){if("string"!=typeof t){2>r&&(n=!1);for(e in t)this.each(Nn(e,t[e],n));return this}if(2>r)return(r=this.node()["__on"+t])&&r._;e=!1}return this.each(Nn(t,n,e))},Ma.each=function(t){return Tn(this,function(n,e,r){t.call(n,n.__data__,e,r)})},Ma.call=function(t){var n=Yu(arguments);return t.apply(n[0]=this,n),this},Ma.empty=function(){return!this.node()},Ma.node=function(){for(var t=0,n=this.length;n>t;t++)for(var e=this[t],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Ma.transition=function(){var t,n,e=_a||++Sa,r=[],i=Object.create(ka);i.time=Date.now();for(var u=-1,a=this.length;a>++u;){r.push(t=[]);for(var o=this[u],c=-1,l=o.length;l>++c;)(n=o[c])&&zn(n,c,e,i),t.push(n)}return Cn(r,e)};var ba=mn([[document]]);ba[0].parentNode=ma,d3.select=function(t){return"string"==typeof t?ba.select(t):mn([[t]])},d3.selectAll=function(t){return"string"==typeof t?ba.selectAll(t):mn([Yu(t)])};var xa=[];d3.selection.enter=qn,d3.selection.enter.prototype=xa,xa.append=Ma.append,xa.insert=Ma.insert,xa.empty=Ma.empty,xa.node=Ma.node,xa.select=function(t){for(var n,e,r,i,u,a=[],o=-1,c=this.length;c>++o;){r=(i=this[o]).update,a.push(n=[]),n.parentNode=i.parentNode;for(var l=-1,s=i.length;s>++l;)(u=i[l])?(n.push(r[l]=e=t.call(i.parentNode,u.__data__,l)),e.__data__=u.__data__):n.push(null)}return mn(a)};var _a,wa=[],Sa=0,ka={ease:T,delay:0,duration:250};wa.call=Ma.call,wa.empty=Ma.empty,wa.node=Ma.node,d3.transition=function(t){return arguments.length?_a?t.transition():t:ba.transition()},d3.transition.prototype=wa,wa.select=function(t){var n,e,r,i=this.id,u=[];"function"!=typeof t&&(t=vn(t));for(var a=-1,o=this.length;o>++a;){u.push(n=[]);for(var c=this[a],l=-1,s=c.length;s>++l;)(r=c[l])&&(e=t.call(r,r.__data__,l))?("__data__"in r&&(e.__data__=r.__data__),zn(e,l,i,r.__transition__[i]),n.push(e)):n.push(null)}return Cn(u,i)},wa.selectAll=function(t){var n,e,r,i,u,a=this.id,o=[];"function"!=typeof t&&(t=yn(t));for(var c=-1,l=this.length;l>++c;)for(var s=this[c],f=-1,h=s.length;h>++f;)if(r=s[f]){u=r.__transition__[a],e=t.call(r,r.__data__,f),o.push(n=[]);for(var d=-1,g=e.length;g>++d;)zn(i=e[d],d,a,u),n.push(i)}return Cn(o,a)},wa.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=En(t));for(var u=0,a=this.length;a>u;u++){i.push(n=[]);for(var e=this[u],o=0,c=e.length;c>o;o++)(r=e[o])&&t.call(r,r.__data__,o)&&n.push(r)}return Cn(i,this.id,this.time).ease(this.ease())},wa.attr=function(t,n){function e(){this.removeAttribute(u)}function r(){this.removeAttributeNS(u.space,u.local)}if(2>arguments.length){for(n in t)this.attr(n,t[n]);return this}var i=V(t),u=d3.ns.qualify(t);return Ln(this,"attr."+t,n,function(t){function n(){var n,e=this.getAttribute(u);return e!==t&&(n=i(e,t),function(t){this.setAttribute(u,n(t))})}function a(){var n,e=this.getAttributeNS(u.space,u.local);return e!==t&&(n=i(e,t),function(t){this.setAttributeNS(u.space,u.local,n(t))})}return null==t?u.local?r:e:(t+="",u.local?a:n)})},wa.attrTween=function(t,n){function e(t,e){var r=n.call(this,t,e,this.getAttribute(i));return r&&function(t){this.setAttribute(i,r(t))}}function r(t,e){var r=n.call(this,t,e,this.getAttributeNS(i.space,i.local));return r&&function(t){this.setAttributeNS(i.space,i.local,r(t))}}var i=d3.ns.qualify(t);return this.tween("attr."+t,i.local?r:e)},wa.style=function(t,n,e){function r(){this.style.removeProperty(t)}var i=arguments.length;if(3>i){if("string"!=typeof t){2>i&&(n="");for(e in t)this.style(e,t[e],n);return this}e=""}var u=V(t);return Ln(this,"style."+t,n,function(n){function i(){var r,i=getComputedStyle(this,null).getPropertyValue(t);return i!==n&&(r=u(i,n),function(n){this.style.setProperty(t,r(n),e)})}return null==n?r:(n+="",i)})},wa.styleTween=function(t,n,e){return 3>arguments.length&&(e=""),this.tween("style."+t,function(r,i){var u=n.call(this,r,i,getComputedStyle(this,null).getPropertyValue(t));return u&&function(n){this.style.setProperty(t,u(n),e)}})},wa.text=function(t){return Ln(this,"text",t,Dn)},wa.remove=function(){return this.each("end.transition",function(){var t;!this.__transition__&&(t=this.parentNode)&&t.removeChild(this)})},wa.ease=function(t){var n=this.id;return 1>arguments.length?this.node().__transition__[n].ease:("function"!=typeof t&&(t=d3.ease.apply(d3,arguments)),Tn(this,function(e){e.__transition__[n].ease=t}))},wa.delay=function(t){var n=this.id;return Tn(this,"function"==typeof t?function(e,r,i){e.__transition__[n].delay=0|t.call(e,e.__data__,r,i)}:(t|=0,function(e){e.__transition__[n].delay=t}))},wa.duration=function(t){var n=this.id;return Tn(this,"function"==typeof t?function(e,r,i){e.__transition__[n].duration=Math.max(1,0|t.call(e,e.__data__,r,i))}:(t=Math.max(1,0|t),function(e){e.__transition__[n].duration=t}))},wa.each=function(t,n){var e=this.id;if(2>arguments.length){var r=ka,i=_a;_a=e,Tn(this,function(n,r,i){ka=n.__transition__[e],t.call(n,n.__data__,r,i)}),ka=r,_a=i}else Tn(this,function(r){r.__transition__[e].event.on(t,n)});return this},wa.transition=function(){for(var t,n,e,r,i=this.id,u=++Sa,a=[],o=0,c=this.length;c>o;o++){a.push(t=[]);for(var n=this[o],l=0,s=n.length;s>l;l++)(e=n[l])&&(r=Object.create(e.__transition__[i]),r.delay+=r.duration,zn(e,l,u,r)),t.push(e)}return Cn(a,u)},wa.tween=function(t,n){var e=this.id;return 2>arguments.length?this.node().__transition__[e].tween.get(t):Tn(this,null==n?function(n){n.__transition__[e].tween.remove(t)}:function(r){r.__transition__[e].tween.set(t,n)})};var Ea,Aa,Na=0,Ta={},qa=null;d3.timer=function(t,n,e){if(3>arguments.length){if(2>arguments.length)n=0;else if(!isFinite(n))return;e=Date.now()}var r=Ta[t.id];r&&r.callback===t?(r.then=e,r.delay=n):Ta[t.id=++Na]=qa={callback:t,then:e,delay:n,next:qa},Ea||(Aa=clearTimeout(Aa),Ea=1,Ca(Fn))},d3.timer.flush=function(){for(var t,n=Date.now(),e=qa;e;)t=n-e.then,e.delay||(e.flush=e.callback(t)),e=e.next;Hn()};var Ca=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){setTimeout(t,17)};d3.mouse=function(t){return Rn(t,P())};var za=/WebKit/.test(navigator.userAgent)?-1:0;d3.touches=function(t,n){return 2>arguments.length&&(n=P().touches),n?Yu(n).map(function(n){var e=Rn(t,n);return e.identifier=n.identifier,e}):[]},d3.scale={},d3.scale.linear=function(){return In([0,1],[0,1],d3.interpolate,!1)},d3.scale.log=function(){return Kn(d3.scale.linear(),Wn)};var Da=d3.format(".0e");Wn.pow=function(t){return Math.pow(10,t)},Qn.pow=function(t){return-Math.pow(10,-t)},d3.scale.pow=function(){return te(d3.scale.linear(),1)},d3.scale.sqrt=function(){return d3.scale.pow().exponent(.5)},d3.scale.ordinal=function(){return ee([],{t:"range",a:[[]]})},d3.scale.category10=function(){return d3.scale.ordinal().range(La)},d3.scale.category20=function(){return d3.scale.ordinal().range(Fa)},d3.scale.category20b=function(){return d3.scale.ordinal().range(Ha)},d3.scale.category20c=function(){return d3.scale.ordinal().range(Ra)};var La=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"],Fa=["#1f77b4","#aec7e8","#ff7f0e","#ffbb78","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"],Ha=["#393b79","#5254a3","#6b6ecf","#9c9ede","#637939","#8ca252","#b5cf6b","#cedb9c","#8c6d31","#bd9e39","#e7ba52","#e7cb94","#843c39","#ad494a","#d6616b","#e7969c","#7b4173","#a55194","#ce6dbd","#de9ed6"],Ra=["#3182bd","#6baed6","#9ecae1","#c6dbef","#e6550d","#fd8d3c","#fdae6b","#fdd0a2","#31a354","#74c476","#a1d99b","#c7e9c0","#756bb1","#9e9ac8","#bcbddc","#dadaeb","#636363","#969696","#bdbdbd","#d9d9d9"];d3.scale.quantile=function(){return re([],[])},d3.scale.quantize=function(){return ie(0,1,[0,1])},d3.scale.threshold=function(){return ue([.5],[0,1])},d3.scale.identity=function(){return ae([0,1])},d3.svg={},d3.svg.arc=function(){function t(){var t=n.apply(this,arguments),u=e.apply(this,arguments),a=r.apply(this,arguments)+Pa,o=i.apply(this,arguments)+Pa,c=(a>o&&(c=a,a=o,o=c),o-a),l=Ru>c?"0":"1",s=Math.cos(a),f=Math.sin(a),h=Math.cos(o),d=Math.sin(o);return c>=ja?t?"M0,"+u+"A"+u+","+u+" 0 1,1 0,"+-u+"A"+u+","+u+" 0 1,1 0,"+u+"M0,"+t+"A"+t+","+t+" 0 1,0 0,"+-t+"A"+t+","+t+" 0 1,0 0,"+t+"Z":"M0,"+u+"A"+u+","+u+" 0 1,1 0,"+-u+"A"+u+","+u+" 0 1,1 0,"+u+"Z":t?"M"+u*s+","+u*f+"A"+u+","+u+" 0 "+l+",1 "+u*h+","+u*d+"L"+t*h+","+t*d+"A"+t+","+t+" 0 "+l+",0 "+t*s+","+t*f+"Z":"M"+u*s+","+u*f+"A"+u+","+u+" 0 "+l+",1 "+u*h+","+u*d+"L0,0"+"Z"}var n=oe,e=ce,r=le,i=se;return t.innerRadius=function(e){return arguments.length?(n=c(e),t):n},t.outerRadius=function(n){return arguments.length?(e=c(n),t):e},t.startAngle=function(n){return arguments.length?(r=c(n),t):r},t.endAngle=function(n){return arguments.length?(i=c(n),t):i},t.centroid=function(){var t=(n.apply(this,arguments)+e.apply(this,arguments))/2,u=(r.apply(this,arguments)+i.apply(this,arguments))/2+Pa;return[Math.cos(u)*t,Math.sin(u)*t]},t};var Pa=-Ru/2,ja=2*Ru-1e-6;d3.svg.line=function(){return fe(a)};var Oa=d3.map({linear:ge,"linear-closed":pe,"step-before":me,"step-after":ve,basis:we,"basis-open":Se,"basis-closed":ke,bundle:Ee,cardinal:be,"cardinal-open":ye,"cardinal-closed":Me,monotone:ze});Oa.forEach(function(t,n){n.key=t,n.closed=/-closed$/.test(t)});var Ya=[0,2/3,1/3,0],Ua=[0,1/3,2/3,0],Ia=[0,1/6,2/3,1/6];d3.svg.line.radial=function(){var t=fe(De);return t.radius=t.x,delete t.x,t.angle=t.y,delete t.y,t},me.reverse=ve,ve.reverse=me,d3.svg.area=function(){return Le(a)},d3.svg.area.radial=function(){var t=Le(De);return t.radius=t.x,delete t.x,t.innerRadius=t.x0,delete t.x0,t.outerRadius=t.x1,delete t.x1,t.angle=t.y,delete t.y,t.startAngle=t.y0,delete t.y0,t.endAngle=t.y1,delete t.y1,t},d3.svg.chord=function(){function e(t,n){var e=r(this,o,t,n),c=r(this,l,t,n);return"M"+e.p0+u(e.r,e.p1,e.a1-e.a0)+(i(e,c)?a(e.r,e.p1,e.r,e.p0):a(e.r,e.p1,c.r,c.p0)+u(c.r,c.p1,c.a1-c.a0)+a(c.r,c.p1,e.r,e.p0))+"Z"}function r(t,n,e,r){var i=n.call(t,e,r),u=s.call(t,i,r),a=f.call(t,i,r)+Pa,o=h.call(t,i,r)+Pa;return{r:u,a0:a,a1:o,p0:[u*Math.cos(a),u*Math.sin(a)],p1:[u*Math.cos(o),u*Math.sin(o)]}}function i(t,n){return t.a0==n.a0&&t.a1==n.a1}function u(t,n,e){return"A"+t+","+t+" 0 "+ +(e>Ru)+",1 "+n}function a(t,n,e,r){return"Q 0,0 "+r}var o=n,l=t,s=Fe,f=le,h=se;return e.radius=function(t){return arguments.length?(s=c(t),e):s},e.source=function(t){return arguments.length?(o=c(t),e):o},e.target=function(t){return arguments.length?(l=c(t),e):l},e.startAngle=function(t){return arguments.length?(f=c(t),e):f},e.endAngle=function(t){return arguments.length?(h=c(t),e):h},e},d3.svg.diagonal=function(){function e(t,n){var e=r.call(this,t,n),a=i.call(this,t,n),o=(e.y+a.y)/2,c=[e,{x:e.x,y:o},{x:a.x,y:o},a];return c=c.map(u),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var r=n,i=t,u=He;return e.source=function(t){return arguments.length?(r=c(t),e):r},e.target=function(t){return arguments.length?(i=c(t),e):i},e.projection=function(t){return arguments.length?(u=t,e):u},e},d3.svg.diagonal.radial=function(){var t=d3.svg.diagonal(),n=He,e=t.projection;return t.projection=function(t){return arguments.length?e(Re(n=t)):n},t},d3.svg.symbol=function(){function t(t,r){return(Va.get(n.call(this,t,r))||Oe)(e.call(this,t,r))}var n=je,e=Pe;return t.type=function(e){return arguments.length?(n=c(e),t):n},t.size=function(n){return arguments.length?(e=c(n),t):e},t};var Va=d3.map({circle:Oe,cross:function(t){var n=Math.sqrt(t/5)/2;return"M"+-3*n+","+-n+"H"+-n+"V"+-3*n+"H"+n+"V"+-n+"H"+3*n+"V"+n+"H"+n+"V"+3*n+"H"+-n+"V"+n+"H"+-3*n+"Z"},diamond:function(t){var n=Math.sqrt(t/(2*Za)),e=n*Za;return"M0,"+-n+"L"+e+",0"+" 0,"+n+" "+-e+",0"+"Z"},square:function(t){var n=Math.sqrt(t)/2;return"M"+-n+","+-n+"L"+n+","+-n+" "+n+","+n+" "+-n+","+n+"Z"},"triangle-down":function(t){var n=Math.sqrt(t/Xa),e=n*Xa/2;return"M0,"+e+"L"+n+","+-e+" "+-n+","+-e+"Z"},"triangle-up":function(t){var n=Math.sqrt(t/Xa),e=n*Xa/2;return"M0,"+-e+"L"+n+","+e+" "+-n+","+e+"Z"}});d3.svg.symbolTypes=Va.keys();var Xa=Math.sqrt(3),Za=Math.tan(30*ju);d3.svg.axis=function(){function t(t){t.each(function(){var t,f=d3.select(this),h=null==l?e.ticks?e.ticks.apply(e,c):e.domain():l,d=null==n?e.tickFormat?e.tickFormat.apply(e,c):String:n,g=Ie(e,h,s),p=f.selectAll(".minor").data(g,String),m=p.enter().insert("line","g").attr("class","tick minor").style("opacity",1e-6),v=d3.transition(p.exit()).style("opacity",1e-6).remove(),y=d3.transition(p).style("opacity",1),M=f.selectAll("g").data(h,String),b=M.enter().insert("g","path").style("opacity",1e-6),x=d3.transition(M.exit()).style("opacity",1e-6).remove(),_=d3.transition(M).style("opacity",1),w=On(e),S=f.selectAll(".domain").data([0]),k=d3.transition(S),E=e.copy(),A=this.__chart__||E;this.__chart__=E,S.enter().append("path").attr("class","domain"),b.append("line").attr("class","tick"),b.append("text");var N=b.select("line"),T=_.select("line"),q=M.select("text").text(d),C=b.select("text"),z=_.select("text");switch(r){case"bottom":t=Ye,m.attr("y2",u),y.attr("x2",0).attr("y2",u),N.attr("y2",i),C.attr("y",Math.max(i,0)+o),T.attr("x2",0).attr("y2",i),z.attr("x",0).attr("y",Math.max(i,0)+o),q.attr("dy",".71em").style("text-anchor","middle"),k.attr("d","M"+w[0]+","+a+"V0H"+w[1]+"V"+a);break;case"top":t=Ye,m.attr("y2",-u),y.attr("x2",0).attr("y2",-u),N.attr("y2",-i),C.attr("y",-(Math.max(i,0)+o)),T.attr("x2",0).attr("y2",-i),z.attr("x",0).attr("y",-(Math.max(i,0)+o)),q.attr("dy","0em").style("text-anchor","middle"),k.attr("d","M"+w[0]+","+-a+"V0H"+w[1]+"V"+-a);break;case"left":t=Ue,m.attr("x2",-u),y.attr("x2",-u).attr("y2",0),N.attr("x2",-i),C.attr("x",-(Math.max(i,0)+o)),T.attr("x2",-i).attr("y2",0),z.attr("x",-(Math.max(i,0)+o)).attr("y",0),q.attr("dy",".32em").style("text-anchor","end"),k.attr("d","M"+-a+","+w[0]+"H0V"+w[1]+"H"+-a);break;case"right":t=Ue,m.attr("x2",u),y.attr("x2",u).attr("y2",0),N.attr("x2",i),C.attr("x",Math.max(i,0)+o),T.attr("x2",i).attr("y2",0),z.attr("x",Math.max(i,0)+o).attr("y",0),q.attr("dy",".32em").style("text-anchor","start"),k.attr("d","M"+a+","+w[0]+"H0V"+w[1]+"H"+a)}if(e.ticks)b.call(t,A),_.call(t,E),x.call(t,E),m.call(t,A),y.call(t,E),v.call(t,E);else{var D=E.rangeBand()/2,L=function(t){return E(t)+D};b.call(t,L),_.call(t,L)}})}var n,e=d3.scale.linear(),r="bottom",i=6,u=6,a=6,o=3,c=[10],l=null,s=0;return t.scale=function(n){return arguments.length?(e=n,t):e},t.orient=function(n){return arguments.length?(r=n,t):r},t.ticks=function(){return arguments.length?(c=arguments,t):c},t.tickValues=function(n){return arguments.length?(l=n,t):l},t.tickFormat=function(e){return arguments.length?(n=e,t):n},t.tickSize=function(n,e){if(!arguments.length)return i;var r=arguments.length-1;return i=+n,u=r>1?+e:i,a=r>0?+arguments[r]:i,t},t.tickPadding=function(n){return arguments.length?(o=+n,t):o},t.tickSubdivide=function(n){return arguments.length?(s=+n,t):s},t},d3.svg.brush=function(){function t(u){u.each(function(){var u,a=d3.select(this),s=a.selectAll(".background").data([0]),f=a.selectAll(".extent").data([0]),h=a.selectAll(".resize").data(l,String);a.style("pointer-events","all").on("mousedown.brush",i).on("touchstart.brush",i),s.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),f.enter().append("rect").attr("class","extent").style("cursor","move"),h.enter().append("g").attr("class",function(t){return"resize "+t}).style("cursor",function(t){return Ba[t]}).append("rect").attr("x",function(t){return/[ew]$/.test(t)?-3:null}).attr("y",function(t){return/^[ns]/.test(t)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),h.style("display",t.empty()?"none":null),h.exit().remove(),o&&(u=On(o),s.attr("x",u[0]).attr("width",u[1]-u[0]),e(a)),c&&(u=On(c),s.attr("y",u[0]).attr("height",u[1]-u[0]),r(a)),n(a)})}function n(t){t.selectAll(".resize").attr("transform",function(t){return"translate("+s[+/e$/.test(t)][0]+","+s[+/^s/.test(t)][1]+")"})}function e(t){t.select(".extent").attr("x",s[0][0]),t.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1][0]-s[0][0])}function r(t){t.select(".extent").attr("y",s[0][1]),t.selectAll(".extent,.e>rect,.w>rect").attr("height",s[1][1]-s[0][1])}function i(){function i(){var t=d3.event.changedTouches;return t?d3.touches(v,t)[0]:d3.mouse(v)}function l(){32==d3.event.keyCode&&(S||(p=null,k[0]-=s[1][0],k[1]-=s[1][1],S=2),R())}function f(){32==d3.event.keyCode&&2==S&&(k[0]+=s[1][0],k[1]+=s[1][1],S=0,R())}function h(){var t=i(),u=!1;m&&(t[0]+=m[0],t[1]+=m[1]),S||(d3.event.altKey?(p||(p=[(s[0][0]+s[1][0])/2,(s[0][1]+s[1][1])/2]),k[0]=s[+(t[0]<p[0])][0],k[1]=s[+(t[1]<p[1])][1]):p=null),_&&d(t,o,0)&&(e(b),u=!0),w&&d(t,c,1)&&(r(b),u=!0),u&&(n(b),M({type:"brush",mode:S?"move":"resize"}))}function d(t,n,e){var r,i,a=On(n),o=a[0],c=a[1],l=k[e],f=s[1][e]-s[0][e];return S&&(o-=l,c-=f+l),r=Math.max(o,Math.min(c,t[e])),S?i=(r+=l)+f:(p&&(l=Math.max(o,Math.min(c,2*p[e]-r))),r>l?(i=r,r=l):i=l),s[0][e]!==r||s[1][e]!==i?(u=null,s[0][e]=r,s[1][e]=i,!0):void 0}function g(){h(),b.style("pointer-events","all").selectAll(".resize").style("display",t.empty()?"none":null),d3.select("body").style("cursor",null),E.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),M({type:"brushend"}),R()}var p,m,v=this,y=d3.select(d3.event.target),M=a.of(v,arguments),b=d3.select(v),x=y.datum(),_=!/^(n|s)$/.test(x)&&o,w=!/^(e|w)$/.test(x)&&c,S=y.classed("extent"),k=i(),E=d3.select(window).on("mousemove.brush",h).on("mouseup.brush",g).on("touchmove.brush",h).on("touchend.brush",g).on("keydown.brush",l).on("keyup.brush",f);if(S)k[0]=s[0][0]-k[0],k[1]=s[0][1]-k[1];else if(x){var A=+/w$/.test(x),N=+/^n/.test(x);m=[s[1-A][0]-k[0],s[1-N][1]-k[1]],k[0]=s[A][0],k[1]=s[N][1]}else d3.event.altKey&&(p=k.slice());b.style("pointer-events","none").selectAll(".resize").style("display",null),d3.select("body").style("cursor",y.style("cursor")),M({type:"brushstart"}),h(),R()}var u,a=j(t,"brushstart","brush","brushend"),o=null,c=null,l=$a[0],s=[[0,0],[0,0]];return t.x=function(n){return arguments.length?(o=n,l=$a[!o<<1|!c],t):o},t.y=function(n){return arguments.length?(c=n,l=$a[!o<<1|!c],t):c},t.extent=function(n){var e,r,i,a,l;return arguments.length?(u=[[0,0],[0,0]],o&&(e=n[0],r=n[1],c&&(e=e[0],r=r[0]),u[0][0]=e,u[1][0]=r,o.invert&&(e=o(e),r=o(r)),e>r&&(l=e,e=r,r=l),s[0][0]=0|e,s[1][0]=0|r),c&&(i=n[0],a=n[1],o&&(i=i[1],a=a[1]),u[0][1]=i,u[1][1]=a,c.invert&&(i=c(i),a=c(a)),i>a&&(l=i,i=a,a=l),s[0][1]=0|i,s[1][1]=0|a),t):(n=u||s,o&&(e=n[0][0],r=n[1][0],u||(e=s[0][0],r=s[1][0],o.invert&&(e=o.invert(e),r=o.invert(r)),e>r&&(l=e,e=r,r=l))),c&&(i=n[0][1],a=n[1][1],u||(i=s[0][1],a=s[1][1],c.invert&&(i=c.invert(i),a=c.invert(a)),i>a&&(l=i,i=a,a=l))),o&&c?[[e,i],[r,a]]:o?[e,r]:c&&[i,a])},t.clear=function(){return u=null,s[0][0]=s[0][1]=s[1][0]=s[1][1]=0,t},t.empty=function(){return o&&s[0][0]===s[1][0]||c&&s[0][1]===s[1][1]},d3.rebind(t,a,"on")};var Ba={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},$a=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]];d3.behavior={},d3.behavior.drag=function(){function t(){this.on("mousedown.drag",n).on("touchstart.drag",n)}function n(){function t(){var t=o.parentNode;return null!=s?d3.touches(t).filter(function(t){return t.identifier===s})[0]:d3.mouse(t)}function n(){if(!o.parentNode)return i();var n=t(),e=n[0]-f[0],r=n[1]-f[1];h|=e|r,f=n,R(),c({type:"drag",x:n[0]+a[0],y:n[1]+a[1],dx:e,dy:r})}function i(){c({type:"dragend"}),h&&(R(),d3.event.target===l&&d.on("click.drag",u,!0)),d.on(null!=s?"touchmove.drag-"+s:"mousemove.drag",null).on(null!=s?"touchend.drag-"+s:"mouseup.drag",null)}function u(){R(),d.on("click.drag",null)}var a,o=this,c=e.of(o,arguments),l=d3.event.target,s=d3.event.touches?d3.event.changedTouches[0].identifier:null,f=t(),h=0,d=d3.select(window).on(null!=s?"touchmove.drag-"+s:"mousemove.drag",n).on(null!=s?"touchend.drag-"+s:"mouseup.drag",i,!0);r?(a=r.apply(o,arguments),a=[a.x-f[0],a.y-f[1]]):a=[0,0],null==s&&R(),c({type:"dragstart"})}var e=j(t,"drag","dragstart","dragend"),r=null;return t.origin=function(n){return arguments.length?(r=n,t):r},d3.rebind(t,e,"on")},d3.behavior.zoom=function(){function t(){this.on("mousedown.zoom",o).on("mousewheel.zoom",c).on("mousemove.zoom",l).on("DOMMouseScroll.zoom",c).on("dblclick.zoom",s).on("touchstart.zoom",f).on("touchmove.zoom",h).on("touchend.zoom",f)}function n(t){return[(t[0]-b[0])/x,(t[1]-b[1])/x]}function e(t){return[t[0]*x+b[0],t[1]*x+b[1]]}function r(t){x=Math.max(_[0],Math.min(_[1],t))}function i(t,n){n=e(n),b[0]+=t[0]-n[0],b[1]+=t[1]-n[1]}function u(){m&&m.domain(p.range().map(function(t){return(t-b[0])/x}).map(p.invert)),y&&y.domain(v.range().map(function(t){return(t-b[1])/x}).map(v.invert))}function a(t){u(),d3.event.preventDefault(),t({type:"zoom",scale:x,translate:b})}function o(){function t(){l=1,i(d3.mouse(u),f),a(o)}function e(){l&&R(),s.on("mousemove.zoom",null).on("mouseup.zoom",null),l&&d3.event.target===c&&s.on("click.zoom",r,!0)}function r(){R(),s.on("click.zoom",null)}var u=this,o=w.of(u,arguments),c=d3.event.target,l=0,s=d3.select(window).on("mousemove.zoom",t).on("mouseup.zoom",e),f=n(d3.mouse(u));window.focus(),R()}function c(){d||(d=n(d3.mouse(this))),r(Math.pow(2,.002*Ve())*x),i(d3.mouse(this),d),a(w.of(this,arguments))}function l(){d=null}function s(){var t=d3.mouse(this),e=n(t),u=Math.log(x)/Math.LN2;r(Math.pow(2,d3.event.shiftKey?Math.ceil(u)-1:Math.floor(u)+1)),i(t,e),a(w.of(this,arguments))}function f(){var t=d3.touches(this),e=Date.now();if(g=x,d={},t.forEach(function(t){d[t.identifier]=n(t)}),R(),1===t.length){if(500>e-M){var u=t[0],o=n(t[0]);r(2*x),i(u,o),a(w.of(this,arguments))}M=e}}function h(){var t=d3.touches(this),n=t[0],e=d[n.identifier];if(u=t[1]){var u,o=d[u.identifier];n=[(n[0]+u[0])/2,(n[1]+u[1])/2],e=[(e[0]+o[0])/2,(e[1]+o[1])/2],r(d3.event.scale*g)}i(n,e),M=null,a(w.of(this,arguments))}var d,g,p,m,v,y,M,b=[0,0],x=1,_=Ga,w=j(t,"zoom");return t.translate=function(n){return arguments.length?(b=n.map(Number),u(),t):b},t.scale=function(n){return arguments.length?(x=+n,u(),t):x},t.scaleExtent=function(n){return arguments.length?(_=null==n?Ga:n.map(Number),t):_},t.x=function(n){return arguments.length?(m=n,p=n.copy(),b=[0,0],x=1,t):m},t.y=function(n){return arguments.length?(y=n,v=n.copy(),b=[0,0],x=1,t):y},d3.rebind(t,w,"on")};var Ja,Ga=[0,1/0];d3.layout={},d3.layout.bundle=function(){return function(t){for(var n=[],e=-1,r=t.length;r>++e;)n.push(Xe(t[e]));return n}},d3.layout.chord=function(){function t(){var t,l,f,h,d,g={},p=[],m=d3.range(u),v=[];for(e=[],r=[],t=0,h=-1;u>++h;){for(l=0,d=-1;u>++d;)l+=i[h][d];p.push(l),v.push(d3.range(u)),t+=l}for(a&&m.sort(function(t,n){return a(p[t],p[n])}),o&&v.forEach(function(t,n){t.sort(function(t,e){return o(i[n][t],i[n][e])
+})}),t=(2*Ru-s*u)/t,l=0,h=-1;u>++h;){for(f=l,d=-1;u>++d;){var y=m[h],M=v[y][d],b=i[y][M],x=l,_=l+=b*t;g[y+"-"+M]={index:y,subindex:M,startAngle:x,endAngle:_,value:b}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/t},l+=s}for(h=-1;u>++h;)for(d=h-1;u>++d;){var w=g[h+"-"+d],S=g[d+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&n()}function n(){e.sort(function(t,n){return c((t.source.value+t.target.value)/2,(n.source.value+n.target.value)/2)})}var e,r,i,u,a,o,c,l={},s=0;return l.matrix=function(t){return arguments.length?(u=(i=t)&&i.length,e=r=null,l):i},l.padding=function(t){return arguments.length?(s=t,e=r=null,l):s},l.sortGroups=function(t){return arguments.length?(a=t,e=r=null,l):a},l.sortSubgroups=function(t){return arguments.length?(o=t,e=null,l):o},l.sortChords=function(t){return arguments.length?(c=t,e&&n(),l):c},l.chords=function(){return e||t(),e},l.groups=function(){return r||t(),r},l},d3.layout.force=function(){function t(t){return function(n,e,r,i){if(n.point!==t){var u=n.cx-t.x,a=n.cy-t.y,o=1/Math.sqrt(u*u+a*a);if(v>(i-e)*o){var c=n.charge*o*o;return t.px-=u*c,t.py-=a*c,!0}if(n.point&&isFinite(o)){var c=n.pointCharge*o*o;t.px-=u*c,t.py-=a*c}}return!n.charge}}function n(t){t.px=d3.event.x,t.py=d3.event.y,l.resume()}var e,r,i,u,o,l={},s=d3.dispatch("start","tick","end"),f=[1,1],h=.9,d=Qe,g=tr,p=-30,m=.1,v=.8,y=[],M=[];return l.tick=function(){if(.005>(r*=.99))return s.end({type:"end",alpha:r=0}),!0;var n,e,a,c,l,d,g,v,b,x=y.length,_=M.length;for(e=0;_>e;++e)a=M[e],c=a.source,l=a.target,v=l.x-c.x,b=l.y-c.y,(d=v*v+b*b)&&(d=r*u[e]*((d=Math.sqrt(d))-i[e])/d,v*=d,b*=d,l.x-=v*(g=c.weight/(l.weight+c.weight)),l.y-=b*g,c.x+=v*(g=1-g),c.y+=b*g);if((g=r*m)&&(v=f[0]/2,b=f[1]/2,e=-1,g))for(;x>++e;)a=y[e],a.x+=(v-a.x)*g,a.y+=(b-a.y)*g;if(p)for(We(n=d3.geom.quadtree(y),r,o),e=-1;x>++e;)(a=y[e]).fixed||n.visit(t(a));for(e=-1;x>++e;)a=y[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*h,a.y-=(a.py-(a.py=a.y))*h);s.tick({type:"tick",alpha:r})},l.nodes=function(t){return arguments.length?(y=t,l):y},l.links=function(t){return arguments.length?(M=t,l):M},l.size=function(t){return arguments.length?(f=t,l):f},l.linkDistance=function(t){return arguments.length?(d=c(t),l):d},l.distance=l.linkDistance,l.linkStrength=function(t){return arguments.length?(g=c(t),l):g},l.friction=function(t){return arguments.length?(h=t,l):h},l.charge=function(t){return arguments.length?(p="function"==typeof t?t:+t,l):p},l.gravity=function(t){return arguments.length?(m=t,l):m},l.theta=function(t){return arguments.length?(v=t,l):v},l.alpha=function(t){return arguments.length?(r?r=t>0?t:0:t>0&&(s.start({type:"start",alpha:r=t}),d3.timer(l.tick)),l):r},l.start=function(){function t(t,r){for(var i,u=n(e),a=-1,o=u.length;o>++a;)if(!isNaN(i=u[a][t]))return i;return Math.random()*r}function n(){if(!a){for(a=[],r=0;s>r;++r)a[r]=[];for(r=0;h>r;++r){var t=M[r];a[t.source.index].push(t.target),a[t.target.index].push(t.source)}}return a[e]}var e,r,a,c,s=y.length,h=M.length,m=f[0],v=f[1];for(e=0;s>e;++e)(c=y[e]).index=e,c.weight=0;for(i=[],u=[],e=0;h>e;++e)c=M[e],"number"==typeof c.source&&(c.source=y[c.source]),"number"==typeof c.target&&(c.target=y[c.target]),i[e]=d.call(this,c,e),u[e]=g.call(this,c,e),++c.source.weight,++c.target.weight;for(e=0;s>e;++e)c=y[e],isNaN(c.x)&&(c.x=t("x",m)),isNaN(c.y)&&(c.y=t("y",v)),isNaN(c.px)&&(c.px=c.x),isNaN(c.py)&&(c.py=c.y);if(o=[],"function"==typeof p)for(e=0;s>e;++e)o[e]=+p.call(this,y[e],e);else for(e=0;s>e;++e)o[e]=p;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){e||(e=d3.behavior.drag().origin(a).on("dragstart",$e).on("drag",n).on("dragend",Je)),this.on("mouseover.force",Ge).on("mouseout.force",Ke).call(e)},d3.rebind(l,s,"on")},d3.layout.partition=function(){function t(n,e,r,i){var u=n.children;if(n.x=e,n.y=n.depth*i,n.dx=r,n.dy=i,u&&(a=u.length)){var a,o,c,l=-1;for(r=n.value?r/n.value:0;a>++l;)t(o=u[l],e,c=o.value*r,i),e+=c}}function n(t){var e=t.children,r=0;if(e&&(i=e.length))for(var i,u=-1;i>++u;)r=Math.max(r,n(e[u]));return 1+r}function e(e,u){var a=r.call(this,e,u);return t(a[0],0,i[0],i[1]/n(a[0])),a}var r=d3.layout.hierarchy(),i=[1,1];return e.size=function(t){return arguments.length?(i=t,e):i},hr(e,r)},d3.layout.pie=function(){function t(u){var a=u.map(function(e,r){return+n.call(t,e,r)}),o=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof i?i.apply(this,arguments):i)-r)/d3.sum(a),l=d3.range(u.length);null!=e&&l.sort(e===Ka?function(t,n){return a[n]-a[t]}:function(t,n){return e(u[t],u[n])});var s=[];return l.forEach(function(t){var n;s[t]={data:u[t],value:n=a[t],startAngle:o,endAngle:o+=n*c}}),s}var n=Number,e=Ka,r=0,i=2*Ru;return t.value=function(e){return arguments.length?(n=e,t):n},t.sort=function(n){return arguments.length?(e=n,t):e},t.startAngle=function(n){return arguments.length?(r=n,t):r},t.endAngle=function(n){return arguments.length?(i=n,t):i},t};var Ka={};d3.layout.stack=function(){function t(a,c){var l=a.map(function(e,r){return n.call(t,e,r)}),s=l.map(function(n){return n.map(function(n,e){return[u.call(t,n,e),o.call(t,n,e)]})}),f=e.call(t,s,c);l=d3.permute(l,f),s=d3.permute(s,f);var h,d,g,p=r.call(t,s,c),m=l.length,v=l[0].length;for(d=0;v>d;++d)for(i.call(t,l[0][d],g=p[d],s[0][d][1]),h=1;m>h;++h)i.call(t,l[h][d],g+=s[h-1][d][1],s[h][d][1]);return a}var n=a,e=ir,r=ur,i=rr,u=nr,o=er;return t.values=function(e){return arguments.length?(n=e,t):n},t.order=function(n){return arguments.length?(e="function"==typeof n?n:Wa.get(n)||ir,t):e},t.offset=function(n){return arguments.length?(r="function"==typeof n?n:Qa.get(n)||ur,t):r},t.x=function(n){return arguments.length?(u=n,t):u},t.y=function(n){return arguments.length?(o=n,t):o},t.out=function(n){return arguments.length?(i=n,t):i},t};var Wa=d3.map({"inside-out":function(t){var n,e,r=t.length,i=t.map(ar),u=t.map(or),a=d3.range(r).sort(function(t,n){return i[t]-i[n]}),o=0,c=0,l=[],s=[];for(n=0;r>n;++n)e=a[n],c>o?(o+=u[e],l.push(e)):(c+=u[e],s.push(e));return s.reverse().concat(l)},reverse:function(t){return d3.range(t.length).reverse()},"default":ir}),Qa=d3.map({silhouette:function(t){var n,e,r,i=t.length,u=t[0].length,a=[],o=0,c=[];for(e=0;u>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];r>o&&(o=r),a.push(r)}for(e=0;u>e;++e)c[e]=(o-a[e])/2;return c},wiggle:function(t){var n,e,r,i,u,a,o,c,l,s=t.length,f=t[0],h=f.length,d=[];for(d[0]=c=l=0,e=1;h>e;++e){for(n=0,i=0;s>n;++n)i+=t[n][e][1];for(n=0,u=0,o=f[e][0]-f[e-1][0];s>n;++n){for(r=0,a=(t[n][e][1]-t[n][e-1][1])/(2*o);n>r;++r)a+=(t[r][e][1]-t[r][e-1][1])/o;u+=a*t[n][e][1]}d[e]=c-=i?u/i*o:0,l>c&&(l=c)}for(e=0;h>e;++e)d[e]-=l;return d},expand:function(t){var n,e,r,i=t.length,u=t[0].length,a=1/i,o=[];for(e=0;u>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];if(r)for(n=0;i>n;n++)t[n][e][1]/=r;else for(n=0;i>n;n++)t[n][e][1]=a}for(e=0;u>e;++e)o[e]=0;return o},zero:ur});d3.layout.histogram=function(){function t(t,u){for(var a,o,c=[],l=t.map(e,this),s=r.call(this,l,u),f=i.call(this,s,l,u),u=-1,h=l.length,d=f.length-1,g=n?1:1/h;d>++u;)a=c[u]=[],a.dx=f[u+1]-(a.x=f[u]),a.y=0;if(d>0)for(u=-1;h>++u;)o=l[u],o>=s[0]&&s[1]>=o&&(a=c[d3.bisect(f,o,1,d)-1],a.y+=g,a.push(t[u]));return c}var n=!0,e=Number,r=fr,i=lr;return t.value=function(n){return arguments.length?(e=n,t):e},t.range=function(n){return arguments.length?(r=c(n),t):r},t.bins=function(n){return arguments.length?(i="number"==typeof n?function(t){return sr(t,n)}:c(n),t):i},t.frequency=function(e){return arguments.length?(n=!!e,t):n},t},d3.layout.hierarchy=function(){function t(n,a,o){var c=i.call(e,n,a);if(n.depth=a,o.push(n),c&&(l=c.length)){for(var l,s,f=-1,h=n.children=[],d=0,g=a+1;l>++f;)s=t(c[f],g,o),s.parent=n,h.push(s),d+=s.value;r&&h.sort(r),u&&(n.value=d)}else u&&(n.value=+u.call(e,n,a)||0);return n}function n(t,r){var i=t.children,a=0;if(i&&(o=i.length))for(var o,c=-1,l=r+1;o>++c;)a+=n(i[c],l);else u&&(a=+u.call(e,t,r)||0);return u&&(t.value=a),a}function e(n){var e=[];return t(n,0,e),e}var r=pr,i=dr,u=gr;return e.sort=function(t){return arguments.length?(r=t,e):r},e.children=function(t){return arguments.length?(i=t,e):i},e.value=function(t){return arguments.length?(u=t,e):u},e.revalue=function(t){return n(t,0),t},e},d3.layout.pack=function(){function t(t,i){var u=n.call(this,t,i),a=u[0];a.x=0,a.y=0,Rr(a,function(t){t.r=Math.sqrt(t.value)}),Rr(a,xr);var o=r[0],c=r[1],l=Math.max(2*a.r/o,2*a.r/c);if(e>0){var s=e*l/2;Rr(a,function(t){t.r+=s}),Rr(a,xr),Rr(a,function(t){t.r-=s}),l=Math.max(2*a.r/o,2*a.r/c)}return Sr(a,o/2,c/2,1/l),u}var n=d3.layout.hierarchy().sort(vr),e=0,r=[1,1];return t.size=function(n){return arguments.length?(r=n,t):r},t.padding=function(n){return arguments.length?(e=+n,t):e},hr(t,n)},d3.layout.cluster=function(){function t(t,i){var u,a=n.call(this,t,i),o=a[0],c=0;Rr(o,function(t){var n=t.children;n&&n.length?(t.x=Ar(n),t.y=Er(n)):(t.x=u?c+=e(t,u):0,t.y=0,u=t)});var l=Nr(o),s=Tr(o),f=l.x-e(l,s)/2,h=s.x+e(s,l)/2;return Rr(o,function(t){t.x=(t.x-f)/(h-f)*r[0],t.y=(1-(o.y?t.y/o.y:1))*r[1]}),a}var n=d3.layout.hierarchy().sort(null).value(null),e=qr,r=[1,1];return t.separation=function(n){return arguments.length?(e=n,t):e},t.size=function(n){return arguments.length?(r=n,t):r},hr(t,n)},d3.layout.tree=function(){function t(t,i){function u(t,n){var r=t.children,i=t._tree;if(r&&(a=r.length)){for(var a,c,l,s=r[0],f=s,h=-1;a>++h;)l=r[h],u(l,c),f=o(l,c,f),c=l;Pr(t);var d=.5*(s._tree.prelim+l._tree.prelim);n?(i.prelim=n._tree.prelim+e(t,n),i.mod=i.prelim-d):i.prelim=d}else n&&(i.prelim=n._tree.prelim+e(t,n))}function a(t,n){t.x=t._tree.prelim+n;var e=t.children;if(e&&(r=e.length)){var r,i=-1;for(n+=t._tree.mod;r>++i;)a(e[i],n)}}function o(t,n,r){if(n){for(var i,u=t,a=t,o=n,c=t.parent.children[0],l=u._tree.mod,s=a._tree.mod,f=o._tree.mod,h=c._tree.mod;o=zr(o),u=Cr(u),o&&u;)c=Cr(c),a=zr(a),a._tree.ancestor=t,i=o._tree.prelim+f-u._tree.prelim-l+e(o,u),i>0&&(jr(Or(o,t,r),t,i),l+=i,s+=i),f+=o._tree.mod,l+=u._tree.mod,h+=c._tree.mod,s+=a._tree.mod;o&&!zr(a)&&(a._tree.thread=o,a._tree.mod+=f-s),u&&!Cr(c)&&(c._tree.thread=u,c._tree.mod+=l-h,r=t)}return r}var c=n.call(this,t,i),l=c[0];Rr(l,function(t,n){t._tree={ancestor:t,prelim:0,mod:0,change:0,shift:0,number:n?n._tree.number+1:0}}),u(l),a(l,-l._tree.prelim);var s=Dr(l,Fr),f=Dr(l,Lr),h=Dr(l,Hr),d=s.x-e(s,f)/2,g=f.x+e(f,s)/2,p=h.depth||1;return Rr(l,function(t){t.x=(t.x-d)/(g-d)*r[0],t.y=t.depth/p*r[1],delete t._tree}),c}var n=d3.layout.hierarchy().sort(null).value(null),e=qr,r=[1,1];return t.separation=function(n){return arguments.length?(e=n,t):e},t.size=function(n){return arguments.length?(r=n,t):r},hr(t,n)},d3.layout.treemap=function(){function t(t,n){for(var e,r,i=-1,u=t.length;u>++i;)r=(e=t[i]).value*(0>n?0:n),e.area=isNaN(r)||0>=r?0:r}function n(e){var u=e.children;if(u&&u.length){var a,o,c,l=f(e),s=[],h=u.slice(),g=1/0,p="slice"===d?l.dx:"dice"===d?l.dy:"slice-dice"===d?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(t(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(a=h[c-1]),s.area+=a.area,"squarify"!==d||g>=(o=r(s,p))?(h.pop(),g=o):(s.area-=s.pop().area,i(s,p,l,!1),p=Math.min(l.dx,l.dy),s.length=s.area=0,g=1/0);s.length&&(i(s,p,l,!0),s.length=s.area=0),u.forEach(n)}}function e(n){var r=n.children;if(r&&r.length){var u,a=f(n),o=r.slice(),c=[];for(t(o,a.dx*a.dy/n.value),c.area=0;u=o.pop();)c.push(u),c.area+=u.area,null!=u.z&&(i(c,u.z?a.dx:a.dy,a,!o.length),c.length=c.area=0);r.forEach(e)}}function r(t,n){for(var e,r=t.area,i=0,u=1/0,a=-1,o=t.length;o>++a;)(e=t[a].area)&&(u>e&&(u=e),e>i&&(i=e));return r*=r,n*=n,r?Math.max(n*i*g/r,r/(n*u*g)):1/0}function i(t,n,e,r){var i,u=-1,a=t.length,o=e.x,l=e.y,s=n?c(t.area/n):0;if(n==e.dx){for((r||s>e.dy)&&(s=e.dy);a>++u;)i=t[u],i.x=o,i.y=l,i.dy=s,o+=i.dx=Math.min(e.x+e.dx-o,s?c(i.area/s):0);i.z=!0,i.dx+=e.x+e.dx-o,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);a>++u;)i=t[u],i.x=o,i.y=l,i.dx=s,l+=i.dy=Math.min(e.y+e.dy-l,s?c(i.area/s):0);i.z=!1,i.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function u(r){var i=a||o(r),u=i[0];return u.x=0,u.y=0,u.dx=l[0],u.dy=l[1],a&&o.revalue(u),t([u],u.dx*u.dy/u.value),(a?e:n)(u),h&&(a=i),i}var a,o=d3.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Yr,h=!1,d="squarify",g=.5*(1+Math.sqrt(5));return u.size=function(t){return arguments.length?(l=t,u):l},u.padding=function(t){function n(n){var e=t.call(u,n,n.depth);return null==e?Yr(n):Ur(n,"number"==typeof e?[e,e,e,e]:e)}function e(n){return Ur(n,t)}if(!arguments.length)return s;var r;return f=null==(s=t)?Yr:"function"==(r=typeof t)?n:"number"===r?(t=[t,t,t,t],e):e,u},u.round=function(t){return arguments.length?(c=t?Math.round:Number,u):c!=Number},u.sticky=function(t){return arguments.length?(h=t,a=null,u):h},u.ratio=function(t){return arguments.length?(g=t,u):g},u.mode=function(t){return arguments.length?(d=t+"",u):d},hr(u,o)},d3.csv=Ir(",","text/csv"),d3.tsv=Ir("        ","text/tab-separated-values"),d3.geo={},d3.geo.stream=function(t,n){to.hasOwnProperty(t.type)?to[t.type](t,n):Vr(t,n)};var to={Feature:function(t,n){Vr(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;i>++r;)Vr(e[r].geometry,n)}},no={Sphere:function(t,n){n.sphere()},Point:function(t,n){var e=t.coordinates;n.point(e[0],e[1])},MultiPoint:function(t,n){for(var e,r=t.coordinates,i=-1,u=r.length;u>++i;)e=r[i],n.point(e[0],e[1])},LineString:function(t,n){Xr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;i>++r;)Xr(e[r],n,0)},Polygon:function(t,n){Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;i>++r;)Zr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;i>++r;)Vr(e[r],n)}};d3.geo.albersUsa=function(){function t(t){return n(t)(t)}function n(t){var n=t[0],a=t[1];return a>50?r:-140>n?i:21>a?u:e}var e=d3.geo.albers(),r=d3.geo.albers().rotate([160,0]).center([0,60]).parallels([55,65]),i=d3.geo.albers().rotate([160,0]).center([0,20]).parallels([8,18]),u=d3.geo.albers().rotate([60,0]).center([0,10]).parallels([8,18]);return t.scale=function(n){return arguments.length?(e.scale(n),r.scale(.6*n),i.scale(n),u.scale(1.5*n),t.translate(e.translate())):e.scale()},t.translate=function(n){if(!arguments.length)return e.translate();var a=e.scale(),o=n[0],c=n[1];return e.translate(n),r.translate([o-.4*a,c+.17*a]),i.translate([o-.19*a,c+.2*a]),u.translate([o+.58*a,c+.43*a]),t},t.scale(e.scale())},(d3.geo.albers=function(){var t=29.5*ju,n=45.5*ju,e=Pi(ei),r=e(t,n);return r.parallels=function(r){return arguments.length?e(t=r[0]*ju,n=r[1]*ju):[t*Ou,n*Ou]},r.rotate([98,0]).center([0,38]).scale(1e3)}).raw=ei;var eo=Vi(function(t){return Math.sqrt(2/(1+t))},function(t){return 2*Math.asin(t/2)});(d3.geo.azimuthalEqualArea=function(){return Ri(eo)}).raw=eo;var ro=Vi(function(t){var n=Math.acos(t);return n&&n/Math.sin(n)},a);(d3.geo.azimuthalEquidistant=function(){return Ri(ro)}).raw=ro,d3.geo.bounds=ri(a),d3.geo.centroid=function(t){io=uo=ao=oo=co=0,d3.geo.stream(t,lo);var n;return uo&&Math.abs(n=Math.sqrt(ao*ao+oo*oo+co*co))>Pu?[Math.atan2(oo,ao)*Ou,Math.asin(Math.max(-1,Math.min(1,co/n)))*Ou]:void 0};var io,uo,ao,oo,co,lo={sphere:function(){2>io&&(io=2,uo=ao=oo=co=0)},point:ii,lineStart:ai,lineEnd:oi,polygonStart:function(){2>io&&(io=2,uo=ao=oo=co=0),lo.lineStart=ui},polygonEnd:function(){lo.lineStart=ai}};d3.geo.circle=function(){function t(){var t="function"==typeof r?r.apply(this,arguments):r,n=Oi(-t[0]*ju,-t[1]*ju,0).invert,i=[];return e(null,null,1,{point:function(t,e){i.push(t=n(t,e)),t[0]*=Ou,t[1]*=Ou}}),{type:"Polygon",coordinates:[i]}}var n,e,r=[0,0],i=6;return t.origin=function(n){return arguments.length?(r=n,t):r},t.angle=function(r){return arguments.length?(e=ci((n=+r)*ju,i*ju),t):n},t.precision=function(r){return arguments.length?(e=ci(n*ju,(i=+r)*ju),t):i},t.angle(90)};var so=si(o,vi,Mi);(d3.geo.equirectangular=function(){return Ri(_i).scale(250/Ru)}).raw=_i.invert=_i;var fo=Vi(function(t){return 1/t},Math.atan);(d3.geo.gnomonic=function(){return Ri(fo)}).raw=fo,d3.geo.graticule=function(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return d3.range(Math.ceil(r/c)*c,e,c).map(a).concat(d3.range(Math.ceil(u/l)*l,i,l).map(o))}var e,r,i,u,a,o,c=22.5,l=c,s=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[a(r).concat(o(i).slice(1),a(e).reverse().slice(1),o(u).reverse().slice(1))]}},t.extent=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],u=+n[0][1],i=+n[1][1],r>e&&(n=r,r=e,e=n),u>i&&(n=u,u=i,i=n),t.precision(s)):[[r,u],[e,i]]},t.step=function(n){return arguments.length?(c=+n[0],l=+n[1],t):[c,l]},t.precision=function(n){return arguments.length?(s=+n,a=wi(u,i,s),o=Si(r,e,s),t):s},t.extent([[-180+Pu,-90+Pu],[180-Pu,90-Pu]])},d3.geo.interpolate=function(t,n){return ki(t[0]*ju,t[1]*ju,n[0]*ju,n[1]*ju)},d3.geo.greatArc=function(){function e(){for(var t=r||a.apply(this,arguments),n=i||o.apply(this,arguments),e=u||d3.geo.interpolate(t,n),i=0,l=c/e.distance,s=[t];1>(i+=l);)s.push(e(i));return s.push(n),{type:"LineString",coordinates:s}}var r,i,u,a=n,o=t,c=6*ju;return e.distance=function(){return(u||d3.geo.interpolate(r||a.apply(this,arguments),i||o.apply(this,arguments))).distance},e.source=function(t){return arguments.length?(a=t,r="function"==typeof t?null:t,u=r&&i?d3.geo.interpolate(r,i):null,e):a},e.target=function(t){return arguments.length?(o=t,i="function"==typeof t?null:t,u=r&&i?d3.geo.interpolate(r,i):null,e):o},e.precision=function(t){return arguments.length?(c=t*ju,e):c/ju},e},Ei.invert=function(t,n){return[2*Ru*t,2*Math.atan(Math.exp(2*Ru*n))-Ru/2]},(d3.geo.mercator=function(){return Ri(Ei).scale(500)}).raw=Ei;var ho=Vi(function(){return 1},Math.asin);(d3.geo.orthographic=function(){return Ri(ho)}).raw=ho,d3.geo.path=function(){function t(t){return t&&d3.geo.stream(t,r(i.pointRadius("function"==typeof u?+u.apply(this,arguments):u))),i.result()}var n,e,r,i,u=4.5;return t.area=function(t){return go=0,d3.geo.stream(t,r(mo)),go},t.centroid=function(t){return io=ao=oo=co=0,d3.geo.stream(t,r(vo)),co?[ao/co,oo/co]:void 0},t.bounds=function(t){return ri(r)(t)},t.projection=function(e){return arguments.length?(r=(n=e)?e.stream||Ni(e):a,t):n},t.context=function(n){return arguments.length?(i=null==(e=n)?new Ti:new qi(n),t):e},t.pointRadius=function(n){return arguments.length?(u="function"==typeof n?n:+n,t):u},t.projection(d3.geo.albersUsa()).context(null)};var go,po,mo={point:Pn,lineStart:Pn,lineEnd:Pn,polygonStart:function(){po=0,mo.lineStart=Ci},polygonEnd:function(){mo.lineStart=mo.lineEnd=mo.point=Pn,go+=Math.abs(po/2)}},vo={point:zi,lineStart:Di,lineEnd:Li,polygonStart:function(){vo.lineStart=Fi},polygonEnd:function(){vo.point=zi,vo.lineStart=Di,vo.lineEnd=Li}};d3.geo.area=function(t){return yo=0,d3.geo.stream(t,bo),yo};var yo,Mo,bo={sphere:function(){yo+=4*Ru},point:Pn,lineStart:Pn,lineEnd:Pn,polygonStart:function(){Mo=0,bo.lineStart=Hi},polygonEnd:function(){yo+=0>Mo?4*Ru+Mo:Mo,bo.lineStart=bo.lineEnd=bo.point=Pn}};d3.geo.projection=Ri,d3.geo.projectionMutator=Pi;var xo=Vi(function(t){return 1/(1+t)},function(t){return 2*Math.atan(t)});(d3.geo.stereographic=function(){return Ri(xo)}).raw=xo,d3.geom={},d3.geom.hull=function(t){if(3>t.length)return[];var n,e,r,i,u,a,o,c,l,s,f=t.length,h=f-1,d=[],g=[],p=0;for(n=1;f>n;++n)t[n][1]<t[p][1]?p=n:t[n][1]==t[p][1]&&(p=t[n][0]<t[p][0]?n:p);for(n=0;f>n;++n)n!==p&&(i=t[n][1]-t[p][1],r=t[n][0]-t[p][0],d.push({angle:Math.atan2(i,r),index:n}));for(d.sort(function(t,n){return t.angle-n.angle}),l=d[0].angle,c=d[0].index,o=0,n=1;h>n;++n)e=d[n].index,l==d[n].angle?(r=t[c][0]-t[p][0],i=t[c][1]-t[p][1],u=t[e][0]-t[p][0],a=t[e][1]-t[p][1],r*r+i*i>=u*u+a*a?d[n].index=-1:(d[o].index=-1,l=d[n].angle,o=n,c=e)):(l=d[n].angle,o=n,c=e);for(g.push(p),n=0,e=0;2>n;++e)-1!==d[e].index&&(g.push(d[e].index),n++);for(s=g.length;h>e;++e)if(-1!==d[e].index){for(;!Xi(g[s-2],g[s-1],d[e].index,t);)--s;g[s++]=d[e].index}var m=[];for(n=0;s>n;++n)m.push(t[g[n]]);return m},d3.geom.polygon=function(t){return t.area=function(){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];e>++n;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return.5*r},t.centroid=function(n){var e,r,i=-1,u=t.length,a=0,o=0,c=t[u-1];for(arguments.length||(n=-1/(6*t.area()));u>++i;)e=c,c=t[i],r=e[0]*c[1]-c[0]*e[1],a+=(e[0]+c[0])*r,o+=(e[1]+c[1])*r;return[a*n,o*n]},t.clip=function(n){for(var e,r,i,u,a,o,c=-1,l=t.length,s=t[l-1];l>++c;){for(e=n.slice(),n.length=0,u=t[c],a=e[(i=e.length)-1],r=-1;i>++r;)o=e[r],Zi(o,s,u)?(Zi(a,s,u)||n.push(Bi(a,o,s,u)),n.push(o)):Zi(a,s,u)&&n.push(Bi(a,o,s,u)),a=o;s=u}return n},t},d3.geom.voronoi=function(t){var n=t.map(function(){return[]}),e=1e6;return $i(t,function(t){var r,i,u,a,o,c;1===t.a&&t.b>=0?(r=t.ep.r,i=t.ep.l):(r=t.ep.l,i=t.ep.r),1===t.a?(o=r?r.y:-e,u=t.c-t.b*o,c=i?i.y:e,a=t.c-t.b*c):(u=r?r.x:-e,o=t.c-t.a*u,a=i?i.x:e,c=t.c-t.a*a);var l=[u,o],s=[a,c];n[t.region.l.index].push(l,s),n[t.region.r.index].push(l,s)}),n=n.map(function(n,e){var r=t[e][0],i=t[e][1],u=n.map(function(t){return Math.atan2(t[0]-r,t[1]-i)});return d3.range(n.length).sort(function(t,n){return u[t]-u[n]}).filter(function(t,n,e){return!n||u[t]-u[e[n-1]]>Pu}).map(function(t){return n[t]})}),n.forEach(function(n,r){var i=n.length;if(!i)return n.push([-e,-e],[-e,e],[e,e],[e,-e]);if(!(i>2)){var u=t[r],a=n[0],o=n[1],c=u[0],l=u[1],s=a[0],f=a[1],h=o[0],d=o[1],g=Math.abs(h-s),p=d-f;if(Pu>Math.abs(p)){var m=f>l?-e:e;n.push([-e,m],[e,m])}else if(Pu>g){var v=s>c?-e:e;n.push([v,-e],[v,e])}else{var m=(s-c)*(d-f)>(h-s)*(f-l)?e:-e,y=Math.abs(p)-g;Pu>Math.abs(y)?n.push([0>p?m:-m,m]):(y>0&&(m*=-1),n.push([-e,m],[e,m]))}}}),n};var _o={l:"r",r:"l"};d3.geom.delaunay=function(t){var n=t.map(function(){return[]}),e=[];return $i(t,function(e){n[e.region.l.index].push(t[e.region.r.index])}),n.forEach(function(n,r){var i=t[r],u=i[0],a=i[1];n.forEach(function(t){t.angle=Math.atan2(t[0]-u,t[1]-a)}),n.sort(function(t,n){return t.angle-n.angle});for(var o=0,c=n.length-1;c>o;o++)e.push([i,n[o],n[o+1]])}),e},d3.geom.quadtree=function(t,n,e,r,i){function u(t,n,e,r,i,u){if(!isNaN(n.x)&&!isNaN(n.y))if(t.leaf){var o=t.point;o?.01>Math.abs(o.x-n.x)+Math.abs(o.y-n.y)?a(t,n,e,r,i,u):(t.point=null,a(t,o,e,r,i,u),a(t,n,e,r,i,u)):t.point=n}else a(t,n,e,r,i,u)}function a(t,n,e,r,i,a){var o=.5*(e+i),c=.5*(r+a),l=n.x>=o,s=n.y>=c,f=(s<<1)+l;t.leaf=!1,t=t.nodes[f]||(t.nodes[f]=Ji()),l?e=o:i=o,s?r=c:a=c,u(t,n,e,r,i,a)}var o,c=-1,l=t.length;if(5>arguments.length)if(3===arguments.length)i=e,r=n,e=n=0;else for(n=e=1/0,r=i=-1/0;l>++c;)o=t[c],n>o.x&&(n=o.x),e>o.y&&(e=o.y),o.x>r&&(r=o.x),o.y>i&&(i=o.y);var s=r-n,f=i-e;s>f?i=e+s:r=n+f;var h=Ji();return h.add=function(t){u(h,t,n,e,r,i)},h.visit=function(t){Gi(t,h,n,e,r,i)},t.forEach(h.add),h},d3.time={};var wo=Date,So=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];Ki.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){ko.setUTCDate.apply(this._,arguments)},setDay:function(){ko.setUTCDay.apply(this._,arguments)},setFullYear:function(){ko.setUTCFullYear.apply(this._,arguments)},setHours:function(){ko.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){ko.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){ko.setUTCMinutes.apply(this._,arguments)},setMonth:function(){ko.setUTCMonth.apply(this._,arguments)},setSeconds:function(){ko.setUTCSeconds.apply(this._,arguments)},setTime:function(){ko.setTime.apply(this._,arguments)}};var ko=Date.prototype,Eo="%a %b %e %X %Y",Ao="%m/%d/%Y",No="%H:%M:%S",To=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],qo=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],Co=["January","February","March","April","May","June","July","August","September","October","November","December"],zo=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];d3.time.format=function(t){function n(n){for(var r,i,u,a=[],o=-1,c=0;e>++o;)37===t.charCodeAt(o)&&(a.push(t.substring(c,o)),null!=(i=jo[r=t.charAt(++o)])&&(r=t.charAt(++o)),(u=Oo[r])&&(r=u(n,null==i?"e"===r?" ":"0":i)),a.push(r),c=o+1);return a.push(t.substring(c,o)),a.join("")}var e=t.length;return n.parse=function(n){var e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0},r=Wi(e,t,n,0);if(r!=n.length)return null;"p"in e&&(e.H=e.H%12+12*e.p);var i=new wo;return i.setFullYear(e.y,e.m,e.d),i.setHours(e.H,e.M,e.S,e.L),i},n.toString=function(){return t},n};var Do=Qi(To),Lo=Qi(qo),Fo=Qi(Co),Ho=tu(Co),Ro=Qi(zo),Po=tu(zo),jo={"-":"",_:" ",0:"0"},Oo={a:function(t){return qo[t.getDay()]},A:function(t){return To[t.getDay()]},b:function(t){return zo[t.getMonth()]},B:function(t){return Co[t.getMonth()]},c:d3.time.format(Eo),d:function(t,n){return nu(t.getDate(),n,2)},e:function(t,n){return nu(t.getDate(),n,2)},H:function(t,n){return nu(t.getHours(),n,2)},I:function(t,n){return nu(t.getHours()%12||12,n,2)},j:function(t,n){return nu(1+d3.time.dayOfYear(t),n,3)},L:function(t,n){return nu(t.getMilliseconds(),n,3)},m:function(t,n){return nu(t.getMonth()+1,n,2)},M:function(t,n){return nu(t.getMinutes(),n,2)},p:function(t){return t.getHours()>=12?"PM":"AM"},S:function(t,n){return nu(t.getSeconds(),n,2)},U:function(t,n){return nu(d3.time.sundayOfYear(t),n,2)},w:function(t){return t.getDay()},W:function(t,n){return nu(d3.time.mondayOfYear(t),n,2)},x:d3.time.format(Ao),X:d3.time.format(No),y:function(t,n){return nu(t.getFullYear()%100,n,2)},Y:function(t,n){return nu(t.getFullYear()%1e4,n,4)},Z:Mu,"%":function(){return"%"}},Yo={a:eu,A:ru,b:iu,B:uu,c:au,d:du,e:du,H:gu,I:gu,L:vu,m:hu,M:pu,p:yu,S:mu,x:ou,X:cu,y:su,Y:lu},Uo=/^\s*\d+/,Io=d3.map({am:0,pm:1});d3.time.format.utc=function(t){function n(t){try{wo=Ki;var n=new wo;return n._=t,e(n)}finally{wo=Date}}var e=d3.time.format(t);return n.parse=function(t){try{wo=Ki;var n=e.parse(t);return n&&n._}finally{wo=Date}},n.toString=e.toString,n};var Vo=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString?bu:Vo,bu.parse=function(t){var n=new Date(t);return isNaN(n)?null:n},bu.toString=Vo.toString,d3.time.second=xu(function(t){return new wo(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(t.getTime()+1e3*Math.floor(n))},function(t){return t.getSeconds()}),d3.time.seconds=d3.time.second.range,d3.time.seconds.utc=d3.time.second.utc.range,d3.time.minute=xu(function(t){return new wo(6e4*Math.floor(t/6e4))},function(t,n){t.setTime(t.getTime()+6e4*Math.floor(n))},function(t){return t.getMinutes()}),d3.time.minutes=d3.time.minute.range,d3.time.minutes.utc=d3.time.minute.utc.range,d3.time.hour=xu(function(t){var n=t.getTimezoneOffset()/60;return new wo(36e5*(Math.floor(t/36e5-n)+n))},function(t,n){t.setTime(t.getTime()+36e5*Math.floor(n))},function(t){return t.getHours()}),d3.time.hours=d3.time.hour.range,d3.time.hours.utc=d3.time.hour.utc.range,d3.time.day=xu(function(t){var n=new wo(1970,0);return n.setFullYear(t.getFullYear(),t.getMonth(),t.getDate()),n},function(t,n){t.setDate(t.getDate()+n)},function(t){return t.getDate()-1}),d3.time.days=d3.time.day.range,d3.time.days.utc=d3.time.day.utc.range,d3.time.dayOfYear=function(t){var n=d3.time.year(t);return Math.floor((t-n-6e4*(t.getTimezoneOffset()-n.getTimezoneOffset()))/864e5)},So.forEach(function(t,n){t=t.toLowerCase(),n=7-n;var e=d3.time[t]=xu(function(t){return(t=d3.time.day(t)).setDate(t.getDate()-(t.getDay()+n)%7),t},function(t,n){t.setDate(t.getDate()+7*Math.floor(n))},function(t){var e=d3.time.year(t).getDay();return Math.floor((d3.time.dayOfYear(t)+(e+n)%7)/7)-(e!==n)});d3.time[t+"s"]=e.range,d3.time[t+"s"].utc=e.utc.range,d3.time[t+"OfYear"]=function(t){var e=d3.time.year(t).getDay();return Math.floor((d3.time.dayOfYear(t)+(e+n)%7)/7)}}),d3.time.week=d3.time.sunday,d3.time.weeks=d3.time.sunday.range,d3.time.weeks.utc=d3.time.sunday.utc.range,d3.time.weekOfYear=d3.time.sundayOfYear,d3.time.month=xu(function(t){return t=d3.time.day(t),t.setDate(1),t},function(t,n){t.setMonth(t.getMonth()+n)},function(t){return t.getMonth()}),d3.time.months=d3.time.month.range,d3.time.months.utc=d3.time.month.utc.range,d3.time.year=xu(function(t){return t=d3.time.day(t),t.setMonth(0,1),t},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t){return t.getFullYear()}),d3.time.years=d3.time.year.range,d3.time.years.utc=d3.time.year.utc.range;var Xo=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Zo=[[d3.time.second,1],[d3.time.second,5],[d3.time.second,15],[d3.time.second,30],[d3.time.minute,1],[d3.time.minute,5],[d3.time.minute,15],[d3.time.minute,30],[d3.time.hour,1],[d3.time.hour,3],[d3.time.hour,6],[d3.time.hour,12],[d3.time.day,1],[d3.time.day,2],[d3.time.week,1],[d3.time.month,1],[d3.time.month,3],[d3.time.year,1]],Bo=[[d3.time.format("%Y"),o],[d3.time.format("%B"),function(t){return t.getMonth()}],[d3.time.format("%b %d"),function(t){return 1!=t.getDate()}],[d3.time.format("%a %d"),function(t){return t.getDay()&&1!=t.getDate()}],[d3.time.format("%I %p"),function(t){return t.getHours()}],[d3.time.format("%I:%M"),function(t){return t.getMinutes()}],[d3.time.format(":%S"),function(t){return t.getSeconds()}],[d3.time.format(".%L"),function(t){return t.getMilliseconds()}]],$o=d3.scale.linear(),Jo=Eu(Bo);Zo.year=function(t,n){return $o.domain(t.map(Nu)).ticks(n).map(Au)},d3.time.scale=function(){return wu(d3.scale.linear(),Zo,Jo)};var Go=Zo.map(function(t){return[t[0].utc,t[1]]}),Ko=[[d3.time.format.utc("%Y"),o],[d3.time.format.utc("%B"),function(t){return t.getUTCMonth()}],[d3.time.format.utc("%b %d"),function(t){return 1!=t.getUTCDate()}],[d3.time.format.utc("%a %d"),function(t){return t.getUTCDay()&&1!=t.getUTCDate()}],[d3.time.format.utc("%I %p"),function(t){return t.getUTCHours()}],[d3.time.format.utc("%I:%M"),function(t){return t.getUTCMinutes()}],[d3.time.format.utc(":%S"),function(t){return t.getUTCSeconds()}],[d3.time.format.utc(".%L"),function(t){return t.getUTCMilliseconds()}]],Wo=Eu(Ko);Go.year=function(t,n){return $o.domain(t.map(qu)).ticks(n).map(Tu)},d3.time.scale.utc=function(){return wu(d3.scale.linear(),Go,Wo)}})();
\ No newline at end of file
diff --git a/dgbuilder/public/favicon.ico b/dgbuilder/public/favicon.ico
new file mode 100644 (file)
index 0000000..10210a7
Binary files /dev/null and b/dgbuilder/public/favicon.ico differ
diff --git a/dgbuilder/public/font-awesome/css/font-awesome.min.css b/dgbuilder/public/font-awesome/css/font-awesome.min.css
new file mode 100644 (file)
index 0000000..ec53d4d
--- /dev/null
@@ -0,0 +1,4 @@
+/*!
+ *  Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}
\ No newline at end of file
diff --git a/dgbuilder/public/font-awesome/fonts/FontAwesome.otf b/dgbuilder/public/font-awesome/fonts/FontAwesome.otf
new file mode 100644 (file)
index 0000000..81c9ad9
Binary files /dev/null and b/dgbuilder/public/font-awesome/fonts/FontAwesome.otf differ
diff --git a/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.eot b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.eot
new file mode 100755 (executable)
index 0000000..84677bc
Binary files /dev/null and b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.eot differ
diff --git a/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.svg b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.svg
new file mode 100755 (executable)
index 0000000..d907b25
--- /dev/null
@@ -0,0 +1,520 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" "  horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1536 160q0 -119 -84.5 -203.5t-203.5 -84.5h-192v608h203l30 224h-233v143q0 54 28 83t96 29l132 1v207q-96 9 -180 9q-136 0 -218 -80.5t-82 -225.5v-166h-224v-224h224v-608h-544q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5v-960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257 -63q-47 -29 -75.5 -73t-28.5 -95 q0 -43 18.5 -77.5t48.5 -56.5t69 -37t77.5 -21t76.5 -6q60 0 120.5 15.5t113.5 46t86 82.5t33 117q0 49 -20 89.5t-49 66.5t-58 47.5t-49 44t-20 44.5t15.5 42.5t37.5 39.5t44 42t37.5 59.5t15.5 82.5q0 60 -22.5 99.5t-72.5 90.5h83zM1152 672h128v64h-128v128h-64v-128 h-128v-64h128v-160h64v160zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 43.5q53 57 53 159q0 58 -17 125t-48.5 129.5 t-84.5 103.5t-117 41q-42 0 -82.5 -19.5t-65.5 -52.5q-47 -59 -47 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26zM591 -37q58 0 111.5 13t99 39t73 73t27.5 109q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -48 2 q-53 0 -105 -7t-107.5 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -70 35 -123.5t91.5 -83t119 -44t127.5 -14.5zM1401 839h213v-108h-213v-219h-105v219h-212v108h212v217h105v-217z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 -88h-132q75 -63 113 -133t38 -160q0 -72 -24.5 -129.5 t-59.5 -93t-69.5 -65t-59 -61.5t-24.5 -66q0 -36 32 -70.5t77 -68t90.5 -73.5t77.5 -104t32 -142q0 -91 -49 -173q-71 -122 -209.5 -179.5t-298.5 -57.5q-132 0 -246.5 41.5t-172.5 137.5q-36 59 -36 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 41 -47.5 73.5 t-15.5 73.5q0 40 21 85q-46 -4 -68 -4q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q76 66 182 98t218 32z" />
+<glyph unicode="&#xf1a1;" horiz-adv-x="1984" d="M831 572q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41t96.5 -41t40.5 -98zM1292 711q56 0 96.5 -41t40.5 -98q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41zM1984 722q0 -62 -31 -114t-83 -82q5 -33 5 -61 q0 -121 -68.5 -230.5t-197.5 -193.5q-125 -82 -285.5 -125.5t-335.5 -43.5q-176 0 -336.5 43.5t-284.5 125.5q-129 84 -197.5 193t-68.5 231q0 29 5 66q-48 31 -77 81.5t-29 109.5q0 94 66 160t160 66q83 0 148 -55q248 158 592 164l134 423q4 14 17.5 21.5t28.5 4.5 l347 -82q22 50 68.5 81t102.5 31q77 0 131.5 -54.5t54.5 -131.5t-54.5 -132t-131.5 -55q-76 0 -130.5 54t-55.5 131l-315 74l-116 -366q327 -14 560 -166q64 58 151 58q94 0 160 -66t66 -160zM1664 1459q-45 0 -77 -32t-32 -77t32 -77t77 -32t77 32t32 77t-32 77t-77 32z M77 722q0 -67 51 -111q49 131 180 235q-36 25 -82 25q-62 0 -105.5 -43.5t-43.5 -105.5zM1567 105q112 73 171.5 166t59.5 194t-59.5 193.5t-171.5 165.5q-116 75 -265.5 115.5t-313.5 40.5t-313.5 -40.5t-265.5 -115.5q-112 -73 -171.5 -165.5t-59.5 -193.5t59.5 -194 t171.5 -166q116 -75 265.5 -115.5t313.5 -40.5t313.5 40.5t265.5 115.5zM1850 605q57 46 57 117q0 62 -43.5 105.5t-105.5 43.5q-49 0 -86 -28q131 -105 178 -238zM1258 237q11 11 27 11t27 -11t11 -27.5t-11 -27.5q-99 -99 -319 -99h-2q-220 0 -319 99q-11 11 -11 27.5 t11 27.5t27 11t27 -11q77 -77 265 -77h2q188 0 265 77z" />
+<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51 -36 87.5t-87 36.5q-60 0 -98 -48 q-151 107 -375 115l83 265l206 -49q1 -50 36.5 -85t84.5 -35q50 0 86 35.5t36 85.5t-36 86t-86 36q-36 0 -66 -20.5t-45 -53.5l-227 54q-9 2 -17.5 -2.5t-11.5 -14.5l-95 -302q-224 -4 -381 -113q-36 43 -93 43q-51 0 -87 -36.5t-36 -87.5q0 -37 19.5 -67.5t52.5 -45.5 q-7 -25 -7 -54q0 -98 74 -181.5t201.5 -132t278.5 -48.5q150 0 277.5 48.5t201.5 132t74 181.5q0 27 -6 54zM971 702q37 0 63 -26t26 -63t-26 -64t-63 -27t-63 27t-26 64t26 63t63 26z" />
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1bd;" d="M1397 1408q58 0 98.5 -40.5t40.5 -98.5v-1258q0 -58 -40.5 -98.5t-98.5 -40.5h-1258q-58 0 -98.5 40.5t-40.5 98.5v1258q0 58 40.5 98.5t98.5 40.5h1258zM1465 11v1258q0 28 -20 48t-48 20h-1258q-28 0 -48 -20t-20 -48v-1258q0 -28 20 -48t48 -20h1258q28 0 48 20t20 48 zM694 749l188 -387l533 145v-496q0 -7 -5.5 -12.5t-12.5 -5.5h-1258q-7 0 -12.5 5.5t-5.5 12.5v141l711 195l-212 439q4 1 12 2.5t12 1.5q170 32 303.5 21.5t221 -46t143.5 -94.5q27 -28 -25 -42q-64 -16 -256 -62l-97 198q-111 7 -240 -16zM1397 1287q7 0 12.5 -5.5 t5.5 -12.5v-428q-85 30 -188 52q-294 64 -645 12l-18 -3l-65 134h-233l85 -190q-132 -51 -230 -137v560q0 7 5.5 12.5t12.5 5.5h1258zM286 387q-14 -3 -26 4.5t-14 21.5q-24 203 166 305l129 -270z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q-218 -161 -612 -161h-60q-32 0 -59.5 -22t-34.5 -53 l-73 -315q-8 -36 -40 -61.5t-69 -25.5h-214q-31 0 -52.5 19.5t-21.5 51.5q0 8 2 20l300 1301q8 36 40.5 61.5t69.5 25.5h444q68 0 125 -4t120.5 -15t113.5 -30t96.5 -50.5t77.5 -74t49.5 -103.5t18.5 -136z" />
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0 87.5 7.5t80.5 24.5t63.5 52.5t23.5 84.5 q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM719 798q-38 0 -74 -6q-2 0 -8.5 -1t-9 -1.5l-7.5 -1.5t-7.5 -2t-6.5 -3t-6.5 -4t-5 -5t-4.5 -7t-4 -9q-9 -29 -9 -39t9 -10q5 0 21.5 5t19.5 6q30 8 58 8q74 0 74 -36q0 -11 -10 -14q-8 -2 -18 -3t-21.5 -1.5t-17.5 -1.5 q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5q0 -38 26 -59.5t64 -21.5q24 0 45.5 6.5t33 13t38.5 23.5q-3 -7 -3 -15t5.5 -13.5t12.5 -5.5h56q1 1 7 3.5t7.5 3.5t5 3.5t5 5.5t2.5 8l45 194q4 13 4 30q0 81 -145 81zM1247 793h-74q-22 0 -39 -23q-5 -7 -29.5 -51 t-46.5 -81.5t-26 -38.5l-5 4q0 77 -27 166q-1 5 -3.5 8.5t-6 6.5t-6.5 5t-8.5 3t-8.5 1.5t-9.5 1t-9 0.5h-10h-8.5q-38 0 -38 -21l1 -5q5 -53 25 -151t25 -143q2 -16 2 -24q0 -19 -30.5 -61.5t-30.5 -58.5q0 -13 40 -13q61 0 76 25l245 415q10 20 10 26q0 9 -8 9zM1489 892 h-129q-18 0 -29 -23q-6 -13 -46.5 -191.5t-40.5 -190.5q0 -20 43 -20h7.5h9h9t9.5 1t8.5 2t8.5 3t6.5 4.5t5.5 6t3 8.5l21 91q2 10 10.5 17t19.5 7q47 0 87.5 7t80.5 24.5t63.5 52.5t23.5 84q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM1835 798q-26 0 -74 -6 q-38 -6 -48 -16q-7 -8 -11 -19q-8 -24 -8 -39q0 -10 8 -10q1 0 41 12q30 8 58 8q74 0 74 -36q0 -12 -10 -14q-4 -1 -57 -7q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5t26 -58.5t64 -21.5q24 0 45 6t34 13t38 24q-3 -15 -3 -16q0 -5 2 -8.5t6.5 -5.5t8 -3.5 t10.5 -2t9.5 -0.5h9.5h8q42 0 48 25l45 194q3 15 3 31q0 81 -145 81zM2157 889h-55q-25 0 -33 -40q-10 -44 -36.5 -167t-42.5 -190v-5q0 -16 16 -18h1h57q10 0 18.5 6.5t10.5 16.5l83 374h-1l1 5q0 7 -5.5 12.5t-13.5 5.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048 q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+<glyph unicode="&#xf20d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf20e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.ttf b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.ttf
new file mode 100755 (executable)
index 0000000..96a3639
Binary files /dev/null and b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.ttf differ
diff --git a/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.woff b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.woff
new file mode 100755 (executable)
index 0000000..628b6a5
Binary files /dev/null and b/dgbuilder/public/font-awesome/fonts/fontawesome-webfont.woff differ
diff --git a/dgbuilder/public/grip.png b/dgbuilder/public/grip.png
new file mode 100644 (file)
index 0000000..c01edb5
Binary files /dev/null and b/dgbuilder/public/grip.png differ
diff --git a/dgbuilder/public/icons/alert.png b/dgbuilder/public/icons/alert.png
new file mode 100644 (file)
index 0000000..a863111
Binary files /dev/null and b/dgbuilder/public/icons/alert.png differ
diff --git a/dgbuilder/public/icons/arduino.png b/dgbuilder/public/icons/arduino.png
new file mode 100644 (file)
index 0000000..43e7d4b
Binary files /dev/null and b/dgbuilder/public/icons/arduino.png differ
diff --git a/dgbuilder/public/icons/arrow-in.png b/dgbuilder/public/icons/arrow-in.png
new file mode 100644 (file)
index 0000000..e38f391
Binary files /dev/null and b/dgbuilder/public/icons/arrow-in.png differ
diff --git a/dgbuilder/public/icons/bridge-dash.png b/dgbuilder/public/icons/bridge-dash.png
new file mode 100644 (file)
index 0000000..beaf8e6
Binary files /dev/null and b/dgbuilder/public/icons/bridge-dash.png differ
diff --git a/dgbuilder/public/icons/bridge.png b/dgbuilder/public/icons/bridge.png
new file mode 100644 (file)
index 0000000..2011292
Binary files /dev/null and b/dgbuilder/public/icons/bridge.png differ
diff --git a/dgbuilder/public/icons/comment.png b/dgbuilder/public/icons/comment.png
new file mode 100644 (file)
index 0000000..d64d12a
Binary files /dev/null and b/dgbuilder/public/icons/comment.png differ
diff --git a/dgbuilder/public/icons/db.png b/dgbuilder/public/icons/db.png
new file mode 100644 (file)
index 0000000..5e74f74
Binary files /dev/null and b/dgbuilder/public/icons/db.png differ
diff --git a/dgbuilder/public/icons/debug.png b/dgbuilder/public/icons/debug.png
new file mode 100644 (file)
index 0000000..0569156
Binary files /dev/null and b/dgbuilder/public/icons/debug.png differ
diff --git a/dgbuilder/public/icons/envelope.png b/dgbuilder/public/icons/envelope.png
new file mode 100644 (file)
index 0000000..fb0d36b
Binary files /dev/null and b/dgbuilder/public/icons/envelope.png differ
diff --git a/dgbuilder/public/icons/feed.png b/dgbuilder/public/icons/feed.png
new file mode 100644 (file)
index 0000000..9f2671c
Binary files /dev/null and b/dgbuilder/public/icons/feed.png differ
diff --git a/dgbuilder/public/icons/file.png b/dgbuilder/public/icons/file.png
new file mode 100644 (file)
index 0000000..78ee09f
Binary files /dev/null and b/dgbuilder/public/icons/file.png differ
diff --git a/dgbuilder/public/icons/function.png b/dgbuilder/public/icons/function.png
new file mode 100644 (file)
index 0000000..9095050
Binary files /dev/null and b/dgbuilder/public/icons/function.png differ
diff --git a/dgbuilder/public/icons/hash.png b/dgbuilder/public/icons/hash.png
new file mode 100644 (file)
index 0000000..e68e45d
Binary files /dev/null and b/dgbuilder/public/icons/hash.png differ
diff --git a/dgbuilder/public/icons/inject.png b/dgbuilder/public/icons/inject.png
new file mode 100644 (file)
index 0000000..dbf4711
Binary files /dev/null and b/dgbuilder/public/icons/inject.png differ
diff --git a/dgbuilder/public/icons/leveldb.png b/dgbuilder/public/icons/leveldb.png
new file mode 100644 (file)
index 0000000..55760c7
Binary files /dev/null and b/dgbuilder/public/icons/leveldb.png differ
diff --git a/dgbuilder/public/icons/light.png b/dgbuilder/public/icons/light.png
new file mode 100644 (file)
index 0000000..ce21542
Binary files /dev/null and b/dgbuilder/public/icons/light.png differ
diff --git a/dgbuilder/public/icons/mongodb.png b/dgbuilder/public/icons/mongodb.png
new file mode 100644 (file)
index 0000000..3a1fc11
Binary files /dev/null and b/dgbuilder/public/icons/mongodb.png differ
diff --git a/dgbuilder/public/icons/node-changed.png b/dgbuilder/public/icons/node-changed.png
new file mode 100644 (file)
index 0000000..38a1794
Binary files /dev/null and b/dgbuilder/public/icons/node-changed.png differ
diff --git a/dgbuilder/public/icons/node-error.png b/dgbuilder/public/icons/node-error.png
new file mode 100644 (file)
index 0000000..c20c8e8
Binary files /dev/null and b/dgbuilder/public/icons/node-error.png differ
diff --git a/dgbuilder/public/icons/range.png b/dgbuilder/public/icons/range.png
new file mode 100644 (file)
index 0000000..2e7183c
Binary files /dev/null and b/dgbuilder/public/icons/range.png differ
diff --git a/dgbuilder/public/icons/redis.png b/dgbuilder/public/icons/redis.png
new file mode 100644 (file)
index 0000000..92e82fd
Binary files /dev/null and b/dgbuilder/public/icons/redis.png differ
diff --git a/dgbuilder/public/icons/rpi.png b/dgbuilder/public/icons/rpi.png
new file mode 100644 (file)
index 0000000..162b99d
Binary files /dev/null and b/dgbuilder/public/icons/rpi.png differ
diff --git a/dgbuilder/public/icons/serial.png b/dgbuilder/public/icons/serial.png
new file mode 100644 (file)
index 0000000..f4bcedc
Binary files /dev/null and b/dgbuilder/public/icons/serial.png differ
diff --git a/dgbuilder/public/icons/swap.png b/dgbuilder/public/icons/swap.png
new file mode 100644 (file)
index 0000000..e9e70ef
Binary files /dev/null and b/dgbuilder/public/icons/swap.png differ
diff --git a/dgbuilder/public/icons/switch.png b/dgbuilder/public/icons/switch.png
new file mode 100644 (file)
index 0000000..4d172de
Binary files /dev/null and b/dgbuilder/public/icons/switch.png differ
diff --git a/dgbuilder/public/icons/template.png b/dgbuilder/public/icons/template.png
new file mode 100644 (file)
index 0000000..1db6f27
Binary files /dev/null and b/dgbuilder/public/icons/template.png differ
diff --git a/dgbuilder/public/icons/timer.png b/dgbuilder/public/icons/timer.png
new file mode 100644 (file)
index 0000000..4f02f46
Binary files /dev/null and b/dgbuilder/public/icons/timer.png differ
diff --git a/dgbuilder/public/icons/trigger.png b/dgbuilder/public/icons/trigger.png
new file mode 100644 (file)
index 0000000..37b60f1
Binary files /dev/null and b/dgbuilder/public/icons/trigger.png differ
diff --git a/dgbuilder/public/icons/twitter.png b/dgbuilder/public/icons/twitter.png
new file mode 100644 (file)
index 0000000..d060594
Binary files /dev/null and b/dgbuilder/public/icons/twitter.png differ
diff --git a/dgbuilder/public/icons/watch.png b/dgbuilder/public/icons/watch.png
new file mode 100644 (file)
index 0000000..a6c1b94
Binary files /dev/null and b/dgbuilder/public/icons/watch.png differ
diff --git a/dgbuilder/public/icons/white-globe.png b/dgbuilder/public/icons/white-globe.png
new file mode 100644 (file)
index 0000000..8a19079
Binary files /dev/null and b/dgbuilder/public/icons/white-globe.png differ
diff --git a/dgbuilder/public/images/dgstart.png b/dgbuilder/public/images/dgstart.png
new file mode 100644 (file)
index 0000000..58521af
Binary files /dev/null and b/dgbuilder/public/images/dgstart.png differ
diff --git a/dgbuilder/public/images/page-loading.gif b/dgbuilder/public/images/page-loading.gif
new file mode 100644 (file)
index 0000000..c25b436
Binary files /dev/null and b/dgbuilder/public/images/page-loading.gif differ
diff --git a/dgbuilder/public/index.html b/dgbuilder/public/index.html
new file mode 100644 (file)
index 0000000..07090db
--- /dev/null
@@ -0,0 +1,332 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
+<meta name="apple-mobile-web-app-capable" content="yes">
+<meta name="mobile-web-app-capable" content="yes">
+
+<!--
+  Copyright 2013, 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<head>
+<!--<title>Node-RED</title>-->
+<title>Directed Graph Builder</title>
+<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
+<link href="jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
+<link rel="stylesheet" type="text/css" href="orion/built-editor.css"/>
+<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.min.css"/>
+<link rel="stylesheet" href="style.css">
+</head>
+<body spellcheck="false">
+<div id="header">
+    <!--<span class="logo"><img src="node-red.png"> <span>Node-RED</span></span>-->
+    <!--<span class="logo"><img src="node-red.png"> <span>Directed Graph Builder</span></span>-->
+    <span class="logo"><img src="node-red.png"> <span>Directed Graph Builder</span><span id='processingStatusId' ></span></span>
+    <div class="pull-right">
+       <span id='releaseId' ></span>
+        <a id="btn-deploy" class="button action-deploy disabled" href="#"><i id="btn-icn-deploy" class="fa fa-download"></i>Save</a>
+        <a id="btn-sidemenu" class="button dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a>
+    </div>
+</div>
+<div id="main-container" class="sidebar-closed">
+    <div id="palette">
+        <img src="spin.svg" class="palette-spinner"/>
+        <div id="palette-container" class="palette-scroll">
+        </div>
+        <div id="palette-search">
+            <i class="fa fa-search"></i><input id="palette-search-input" type="text" placeholder="filter"><a href="#" id="palette-search-clear"><i class="fa fa-times"></i></a></input>
+        </div>
+    </div><!-- /palette -->
+
+    <div id="workspace">
+        <ul id="workspace-tabs"></ul>
+        <div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
+        <div id="chart"></div>
+        <div id="workspace-toolbar">
+            <div class="btn-group">
+                <a class="btn btn-small" href="#"><i class="fa fa-search-minus"></i></a>
+                <a class="btn btn-small" href="#"><i class="fa fa-dot-circle-o"></i></a>
+                <a class="btn btn-small" href="#"><i class="fa fa-search-plus"></i></a>
+            </div>
+        </div>
+    </div>
+
+    <div id="chart-zoom-controls">
+        <div class="btn-group">
+            <a class="btn btn-mini" id="btn-zoom-out" href="#"><i class="fa fa-search-minus"></i></a>
+            <a class="btn btn-mini" id="btn-zoom-zero" href="#"><i class="fa fa-dot-circle-o"></i></a>
+            <a class="btn btn-mini" id="btn-zoom-in" href="#"><i class="fa fa-search-plus"></i></a>
+        </div>
+    </div>
+
+    <div id="sidebar">
+        <ul id="sidebar-tabs"></ul>
+        <div id="sidebar-content"></div>
+    </div>
+
+    <div id="sidebar-separator"></div>
+
+</div>
+
+<div id="notifications"></div>
+<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
+
+<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
+<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
+
+<div id="node-dialog-confirm-deploy" class="hide">
+    <form class="form-horizontal">
+        <div id="node-dialog-confirm-deploy-config" style="text-align: center; padding-top: 30px;">
+         Some of the nodes are not properly configured. Are you sure you want to deploy?
+        </div>
+        <div id="node-dialog-confirm-deploy-unknown" style="text-align: center; padding-top: 10px;">
+         The workspace contains some unknown node types:
+         <ul style="width: 300px; margin: auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
+         Are you sure you want to deploy?
+        </div>
+    </form>
+</div>
+
+<div id="node-help" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="node-help-label" aria-hidden="true">
+  <div class="modal-header">
+    <h5 id="node-help-label">Keyboard Shortcuts <!-- <span style="float: right;"><a href="http://node-red.github.io/docs" target="_blank">Open help in new window &raquo;</a></span> -->
+</h5>
+  </div>
+  <div class="modal-body">
+    <table>
+        <tr>
+          <td><span class="help-key">?</span></td><td>Help</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">a</span></td><td>Select all nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">Space</span></td><td>Toggle sidebar</td>
+          <td><span class="help-key">Shift</span> <span class="help-key">Click</span></td><td>Select all connected nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">z</span></td><td>Undo</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">Click</span></td><td>Add/remove node from selection</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">m</span></td><td>Toggle Node Palette</td>
+          <td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">x</span></td><td>Cut selected nodes</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">b</span></td><td>Find Node</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">c</span></td><td>Copy selected nodes</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">v</span></td><td>Paste nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">i</span></td><td>Import nodes</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">e</span></td><td>Export selected nodes</td>
+        </tr>
+        <tr>
+          <td colspan="2"></td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">+</span></td><td>Zoom in</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">-</span></td><td>Zoom out</td>
+        </tr>
+    </table>
+  </div>
+  <div class="modal-footer">
+    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
+  </div>
+</div>
+
+<div id="node-dialog-library-save-confirm" class="hide">
+    <form class="form-horizontal">
+        <div style="text-align: center; padding-top: 30px;">
+         A <span id="node-dialog-library-save-type"></span> called <span id="node-dialog-library-save-name"></span> already exists. Overwrite?
+        </div>
+    </form>
+</div>
+
+<div id="node-dialog-library-save" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <label for="node-dialog-library-save-folder"><i class="fa fa-folder-open"></i> Folder</label>
+            <input type="text" id="node-dialog-library-save-folder" placeholder="Folder">
+        </div>
+        <div class="form-row">
+            <label for="node-dialog-library-save-filename"><i class="fa fa-file"></i> Filename</label>
+            <input type="text" id="node-dialog-library-save-filename" placeholder="Filename">
+        </div>
+    </form>
+</div>
+
+<div id="node-dialog-library-lookup" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
+                <li class="active"><a href="#">Library</a></li>
+            </ul>
+        </div>
+        <div class="form-row">
+            <div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
+                <div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
+            </div>
+            <div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
+                <div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
+            </div>
+        </div>
+    </form>
+</div>
+<div id="node-dialog-rename-workspace" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <label for="node-input-workspace-name" ><i class="fa fa-tag"></i> Name:</label>
+            <input type="text" id="node-input-workspace-name">
+        </div>
+    </form>
+</div>
+<div id="node-dialog-delete-workspace" class="hide">
+    <form class="form-horizontal">
+        <div style="text-align: center; padding-top: 30px;">
+         Are you sure you want to delete '<span id="node-dialog-delete-workspace-name"></span>'?
+        </div>
+    </form>
+</div>
+<div id="xmldialog" class="hide"></div>
+<div id="filter-tabs-dialog" class="hide"></div>
+<div id="loop-detection-dialog" class="hide"></div>
+<div id="dgnumber-find-dialog" class="hide"></div>
+<div id="search-text-dialog" class="hide"></div>
+<div id="dgstart-generate-xml-dialog" class="hide"></div>
+<div id="update-password-dialog" class="hide"></div>
+<div id="update-configuration-dialog" class="hide"></div>
+<div id="dgflow-browser-dialog" class="hide"></div>
+<div id="codecloud-browser-dialog" class="hide"></div>
+<div id="gitlocal-browser-dialog" class="hide"></div>
+<div id="gitcommands-dialog" class="hide"></div>
+<div id="upload-xml-status-dialog" class="hide"></div>
+<div id="flow-design-err-dialog" class="hide"></div>
+<div id="sli-values-dialog" class="hide"></div>
+<div id="comments-dialog" class="hide"></div>
+<div id="show-errors-dialog" class="hide"></div>
+<div id="yang-upload-dialog" class="hide"></div>
+<div id="yang-modules-browser-dialog" class="hide"></div>
+<div id="list-yang-browser-dialog" class="hide"></div>
+<div id="request-input-dialog" class="hide"></div>
+<script type="text/x-red" data-template-name="export-clipboard-dialog">
+    <div class="form-row">
+        <label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> Nodes:</label>
+        <textarea readonly style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-export" rows="5"></textarea>
+    </div>
+    <div class="form-tips">
+        Select the text above and copy to the clipboard with Ctrl-A Ctrl-C.
+    </div>
+</script>
+<script type="text/x-red" data-template-name="export-library-dialog">
+    <div class="form-row">
+        <label for="node-input-filename" ><i class="fa fa-file"></i> Filename:</label>
+        <input type="text" id="node-input-filename" placeholder="Filename">
+    </div>
+</script>
+<script type="text/x-red" data-template-name="import-dialog">
+    <div class="form-row">
+        <label for="node-input-import"><i class="fa fa-clipboard"></i> Nodes:</label>
+        <textarea style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-import" rows="5" placeholder="Paste nodes here"></textarea>
+    </div>
+</script>
+
+<script src="jquery/js/jquery-1.11.1.min.js"></script>
+<script src="bootstrap/js/bootstrap.min.js"></script>
+<script src="jquery/js/jquery-ui-1.10.3.custom.min.js"></script>
+<script src="jquery/js/jquery.ui.touch-punch.min.js"></script>
+<script src="orion/built-editor.min.js"></script>
+<script src="d3.v3.min.js"></script>
+
+<script src="red/main.js"></script>
+<script src="red/comms.js"></script>
+<script src="red/ui/state.js"></script>
+<script src="red/nodes.js"></script>
+<script src="red/history.js"></script>
+<script src="red/validators.js"></script>
+<script src="red/ui/menu.js"></script>
+<script src="red/ui/keyboard.js"></script>
+<script src="red/ui/tabs.js"></script>
+<script src="red/ui/view.js"></script>
+<script src="red/ui/sidebar.js"></script>
+<script src="red/ui/palette.js"></script>
+<script src="red/ui/tab-info.js"></script>
+<script src="red/ui/tab-config.js"></script>
+<script src="red/ui/editor.js"></script>
+<script src="red/ui/library.js"></script>
+<script src="red/ui/notifications.js"></script>
+<script src="red/ui/touch/radialMenu.js"></script>
+
+
+<script lang="javascript">
+ $(function() {
+        RED.keyboard.add(/* M */ 77,{ctrl:true},function(){RED.menu.setSelected("btn-node-panel",!RED.menu.isSelected("btn-node-panel"));d3.event.preventDefault();});
+       RED.menu.setSelected("btn-node-panel",true);
+    });
+
+var sliValuesObj = {};
+var rpcValues = {};
+var reqInputValues = {};
+$(function(){
+ $.get("/initialLoadSelectedModules")
+        .done(function( data ) {
+               //console.dir(data);
+                if(data != undefined && data != null){
+                     for(var i=0;i<data.sliValuesObj.length;i++){
+                               var moduleName = data.sliValuesObj[i].moduleName;       
+                               //console.dir(data.sliValuesObj[i][ moduleName + '_PROPS']);
+                               //console.dir(data.sliValuesObj[i][moduleName + '_RPCS']);
+                               sliValuesObj[moduleName] = data.sliValuesObj[i][moduleName + '_PROPS'];
+                               rpcValues[moduleName] = data.sliValuesObj[i][ moduleName +'_RPCS'];
+                               for(var k=0;rpcValues[moduleName] != undefined && k<rpcValues[moduleName].length;k++){
+                                       var rpcName = rpcValues[moduleName][k];
+                                       reqInputValues[moduleName + "_" + rpcName] = data.sliValuesObj[i][rpcName +"-input"];
+                               }
+                       }
+                }
+
+        })
+        .fail(function(err) {
+               console.dir(err);
+        })
+        .always(function() {
+        });
+});
+
+</script>
+<script>
+ $(document).ready(function() {
+
+var urlPath="/getRelease";
+       $.get(urlPath)
+        .done(function( data ) {
+               //console.dir(data);
+                if(data != undefined && data != null){
+                       var release = data.release;
+                       //document.title +=" " + release;
+                       $("#releaseId").text("Workspace:" + release);
+                       $("#releaseId").css({color:'lightgrey'});
+                       
+                }
+        })
+       .fail(function(err) {
+        })
+        .always(function() {
+        });
+});
+</script>
+</body>
+</html>
diff --git a/dgbuilder/public/index.html.orig b/dgbuilder/public/index.html.orig
new file mode 100644 (file)
index 0000000..8141b8a
--- /dev/null
@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
+<meta name="apple-mobile-web-app-capable" content="yes">
+<meta name="mobile-web-app-capable" content="yes">
+
+<!--
+  Copyright 2013, 2014 IBM Corp.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<head>
+<title>Node-RED</title>
+<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
+<link href="jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
+<link rel="stylesheet" type="text/css" href="orion/built-editor.css"/>
+<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.min.css"/>
+<link rel="stylesheet" href="style.css">
+</head>
+<body spellcheck="false">
+<div id="header">
+    <span class="logo"><img src="node-red.png"> <span>Node-RED</span></span>
+    <div class="pull-right">
+        <a id="btn-deploy" class="button action-deploy disabled" href="#"><i id="btn-icn-deploy" class="fa fa-download"></i> Deploy</a>
+        <a id="btn-sidemenu" class="button dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a>
+    </div>
+</div>
+<div id="main-container" class="sidebar-closed">
+    <div id="palette">
+        <img src="spin.svg" class="palette-spinner"/>
+        <div id="palette-container" class="palette-scroll">
+        </div>
+        <div id="palette-search">
+            <i class="fa fa-search"></i><input id="palette-search-input" type="text" placeholder="filter"><a href="#" id="palette-search-clear"><i class="fa fa-times"></i></a></input>
+        </div>
+    </div><!-- /palette -->
+
+    <div id="workspace">
+        <ul id="workspace-tabs"></ul>
+        <div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
+        <div id="chart"></div>
+        <div id="workspace-toolbar">
+            <div class="btn-group">
+                <a class="btn btn-small" href="#"><i class="fa fa-search-minus"></i></a>
+                <a class="btn btn-small" href="#"><i class="fa fa-dot-circle-o"></i></a>
+                <a class="btn btn-small" href="#"><i class="fa fa-search-plus"></i></a>
+            </div>
+        </div>
+    </div>
+
+    <div id="chart-zoom-controls">
+        <div class="btn-group">
+            <a class="btn btn-mini" id="btn-zoom-out" href="#"><i class="fa fa-search-minus"></i></a>
+            <a class="btn btn-mini" id="btn-zoom-zero" href="#"><i class="fa fa-dot-circle-o"></i></a>
+            <a class="btn btn-mini" id="btn-zoom-in" href="#"><i class="fa fa-search-plus"></i></a>
+        </div>
+    </div>
+
+    <div id="sidebar">
+        <ul id="sidebar-tabs"></ul>
+        <div id="sidebar-content"></div>
+    </div>
+
+    <div id="sidebar-separator"></div>
+
+</div>
+
+<div id="notifications"></div>
+<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
+
+<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
+<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
+
+<div id="node-dialog-confirm-deploy" class="hide">
+    <form class="form-horizontal">
+        <div id="node-dialog-confirm-deploy-config" style="text-align: center; padding-top: 30px;">
+         Some of the nodes are not properly configured. Are you sure you want to deploy?
+        </div>
+        <div id="node-dialog-confirm-deploy-unknown" style="text-align: center; padding-top: 10px;">
+         The workspace contains some unknown node types:
+         <ul style="width: 300px; margin: auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
+         Are you sure you want to deploy?
+        </div>
+    </form>
+</div>
+
+<div id="node-help" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="node-help-label" aria-hidden="true">
+  <div class="modal-header">
+    <h5 id="node-help-label">Keyboard Shortcuts <span style="float: right;"><a href="http://node-red.github.io/docs" target="_blank">Open help in new window &raquo;</a></span></h5>
+  </div>
+  <div class="modal-body">
+    <table>
+        <tr>
+          <td><span class="help-key">?</span></td><td>Help</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">a</span></td><td>Select all nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">Space</span></td><td>Toggle sidebar</td>
+          <td><span class="help-key">Shift</span> <span class="help-key">Click</span></td><td>Select all connected nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">z</span></td><td>Undo</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">Click</span></td><td>Add/remove node from selection</td>
+        </tr>
+        <tr>
+          <td></td><td></td>
+          <td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">x</span></td><td>Cut selected nodes</td>
+          <td></td><td></td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">c</span></td><td>Copy selected nodes</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">v</span></td><td>Paste nodes</td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">i</span></td><td>Import nodes</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">e</span></td><td>Export selected nodes</td>
+        </tr>
+        <tr>
+          <td colspan="2"></td>
+        </tr>
+        <tr>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">+</span></td><td>Zoom in</td>
+          <td><span class="help-key">Ctrl</span> <span class="help-key">-</span></td><td>Zoom out</td>
+        </tr>
+    </table>
+  </div>
+  <div class="modal-footer">
+    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
+  </div>
+</div>
+
+<div id="node-dialog-library-save-confirm" class="hide">
+    <form class="form-horizontal">
+        <div style="text-align: center; padding-top: 30px;">
+         A <span id="node-dialog-library-save-type"></span> called <span id="node-dialog-library-save-name"></span> already exists. Overwrite?
+        </div>
+    </form>
+</div>
+
+<div id="node-dialog-library-save" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <label for="node-dialog-library-save-folder"><i class="fa fa-folder-open"></i> Folder</label>
+            <input type="text" id="node-dialog-library-save-folder" placeholder="Folder">
+        </div>
+        <div class="form-row">
+            <label for="node-dialog-library-save-filename"><i class="fa fa-file"></i> Filename</label>
+            <input type="text" id="node-dialog-library-save-filename" placeholder="Filename">
+        </div>
+    </form>
+</div>
+
+<div id="node-dialog-library-lookup" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
+                <li class="active"><a href="#">Library</a></li>
+            </ul>
+        </div>
+        <div class="form-row">
+            <div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
+                <div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
+            </div>
+            <div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
+                <div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
+            </div>
+        </div>
+    </form>
+</div>
+<div id="node-dialog-rename-workspace" class="hide">
+    <form class="form-horizontal">
+        <div class="form-row">
+            <label for="node-input-workspace-name" ><i class="fa fa-tag"></i> Name:</label>
+            <input type="text" id="node-input-workspace-name">
+        </div>
+    </form>
+</div>
+<div id="node-dialog-delete-workspace" class="hide">
+    <form class="form-horizontal">
+        <div style="text-align: center; padding-top: 30px;">
+         Are you sure you want to delete '<span id="node-dialog-delete-workspace-name"></span>'?
+        </div>
+    </form>
+</div>
+
+<script type="text/x-red" data-template-name="export-clipboard-dialog">
+    <div class="form-row">
+        <label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> Nodes:</label>
+        <textarea readonly style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-export" rows="5"></textarea>
+    </div>
+    <div class="form-tips">
+        Select the text above and copy to the clipboard with Ctrl-A Ctrl-C.
+    </div>
+</script>
+<script type="text/x-red" data-template-name="export-library-dialog">
+    <div class="form-row">
+        <label for="node-input-filename" ><i class="fa fa-file"></i> Filename:</label>
+        <input type="text" id="node-input-filename" placeholder="Filename">
+    </div>
+</script>
+<script type="text/x-red" data-template-name="import-dialog">
+    <div class="form-row">
+        <label for="node-input-import"><i class="fa fa-clipboard"></i> Nodes:</label>
+        <textarea style="font-family: monospace; font-size: 12px; background:rgb(226, 229, 255); padding-left: 0.5em;" class="input-block-level" id="node-input-import" rows="5" placeholder="Paste nodes here"></textarea>
+    </div>
+</script>
+
+<script src="jquery/js/jquery-1.11.1.min.js"></script>
+<script src="bootstrap/js/bootstrap.min.js"></script>
+<script src="jquery/js/jquery-ui-1.10.3.custom.min.js"></script>
+<script src="jquery/js/jquery.ui.touch-punch.min.js"></script>
+<script src="orion/built-editor.min.js"></script>
+<script src="d3.v3.min.js"></script>
+<script src="red/main.js"></script>
+<script src="red/comms.js"></script>
+<script src="red/ui/state.js"></script>
+<script src="red/nodes.js"></script>
+<script src="red/history.js"></script>
+<script src="red/validators.js"></script>
+<script src="red/ui/menu.js"></script>
+<script src="red/ui/keyboard.js"></script>
+<script src="red/ui/tabs.js"></script>
+<script src="red/ui/view.js"></script>
+<script src="red/ui/sidebar.js"></script>
+<script src="red/ui/palette.js"></script>
+<script src="red/ui/tab-info.js"></script>
+<script src="red/ui/tab-config.js"></script>
+<script src="red/ui/editor.js"></script>
+<script src="red/ui/library.js"></script>
+<script src="red/ui/notifications.js"></script>
+<script src="red/ui/touch/radialMenu.js"></script>
+</body>
+</html>
diff --git a/dgbuilder/public/jquery/css/smoothness/images/animated-overlay.gif b/dgbuilder/public/jquery/css/smoothness/images/animated-overlay.gif
new file mode 100644 (file)
index 0000000..d441f75
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/animated-overlay.gif differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644 (file)
index 0000000..736b15a
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644 (file)
index 0000000..450d29e
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644 (file)
index 0000000..d1f3621
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644 (file)
index 0000000..a7a6501
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644 (file)
index 0000000..eadb5fb
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644 (file)
index 0000000..24ae2b7
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644 (file)
index 0000000..c48f520
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644 (file)
index 0000000..f8e7c29
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-icons_222222_256x240.png b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_222222_256x240.png
new file mode 100644 (file)
index 0000000..c1cb117
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_222222_256x240.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png
new file mode 100644 (file)
index 0000000..84b601b
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-icons_454545_256x240.png b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_454545_256x240.png
new file mode 100644 (file)
index 0000000..b6db1ac
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_454545_256x240.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-icons_888888_256x240.png b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_888888_256x240.png
new file mode 100644 (file)
index 0000000..feea0e2
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_888888_256x240.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png
new file mode 100644 (file)
index 0000000..ed5b6b0
Binary files /dev/null and b/dgbuilder/public/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/dgbuilder/public/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css b/dgbuilder/public/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css
new file mode 100644 (file)
index 0000000..8d0e72c
--- /dev/null
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.3 - 2013-08-17
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted #000}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:700;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:0;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:0}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:400}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:400;margin:-1px}.ui-menu .ui-state-disabled{font-weight:400;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url(images/animated-overlay.gif);height:100%;filter:alpha(opacity=25);opacity:.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:0;background:0;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:0;border-bottom:0;border-right:0}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:0}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
\ No newline at end of file
diff --git a/dgbuilder/public/jquery/js/jquery-1.11.1.min.js b/dgbuilder/public/jquery/js/jquery-1.11.1.min.js
new file mode 100644 (file)
index 0000000..ab28a24
--- /dev/null
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
diff --git a/dgbuilder/public/jquery/js/jquery-ui-1.10.3.custom.min.js b/dgbuilder/public/jquery/js/jquery-ui-1.10.3.custom.min.js
new file mode 100644 (file)
index 0000000..491cda7
--- /dev/null
@@ -0,0 +1,7 @@
+/*! jQuery UI - v1.10.3 - 2013-08-17
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js
+* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
+
+(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.3",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(a!==e)return a;var i,s,n=t("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),o=n.children()[0];return t("body").append(n),i=o.offsetWidth,n.css("overflow","scroll"),s=o.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),a=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,a="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:a?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]);return{element:i,isWindow:s,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var a,p,m,g,v,b,_=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),x=(e.collision||"flip").split(" "),k={};return b=n(_),_[0].preventDefault&&(e.at="left top"),p=b.width,m=b.height,g=b.offset,v=t.extend({},g),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),k[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===x.length&&(x[1]=x[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=m:"center"===e.at[1]&&(v.top+=m/2),a=i(k.at,p,m),v.left+=a[0],v.top+=a[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),b=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,T=d+b+s(this,"marginBottom")+w.height,C=t.extend({},v),M=i(k.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?C.left-=u:"center"===e.my[0]&&(C.left-=u/2),"bottom"===e.my[1]?C.top-=d:"center"===e.my[1]&&(C.top-=d/2),C.left+=M[0],C.top+=M[1],t.support.offsetFractions||(C.left=h(C.left),C.top=h(C.top)),n={marginLeft:f,marginTop:b},t.each(["left","top"],function(i,s){t.ui.position[x[i]]&&t.ui.position[x[i]][s](C,{targetWidth:p,targetHeight:m,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:T,offset:[a[0]+M[0],a[1]+M[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=g.left-C.left,s=i+p-u,n=g.top-C.top,a=n+m-d,h={target:{element:_,left:g.left,top:g.top,width:p,height:m},element:{element:c,left:C.left,top:C.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>a?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>m&&m>r(n+a)&&(h.vertical="middle"),h.important=o(r(i),r(s))>o(r(n),r(a))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(C,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-o-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-o-a,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-o-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-o-a,t.top+p+f+m>c&&(0>s||r(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,t.top+p+f+m>u&&(i>0||u>r(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,a,o=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(o?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},o&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(a in s)e.style[a]=s[a];e.appendChild(r),i=o||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()})(jQuery);(function(e){e.widget("ui.draggable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var i=this.options;return this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(e(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){e("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||e.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1):!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,e(document).width()-this.helperProportions.width-this.margins.left,(e(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(t){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=t.pageX,l=t.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),t.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),t.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s]),"drag"===t&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i){var s=e(this).data("ui-draggable"),n=s.options,a=e.extend({},i,{item:s.element});s.sortables=[],e(n.connectToSortable).each(function(){var i=e.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",t,a))})},stop:function(t,i){var s=e(this).data("ui-draggable"),n=e.extend({},i,{item:s.element});e.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,n))})},drag:function(t,i){var s=e(this).data("ui-draggable"),n=this;e.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,e.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",t),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",t),s.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(){var t=e("body"),i=e(this).data("ui-draggable").options;t.css("cursor")&&(i._cursor=t.css("cursor")),t.css("cursor",i.cursor)},stop:function(){var t=e(this).data("ui-draggable").options;t._cursor&&e("body").css("cursor",t._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._opacity&&e(i.helper).css("opacity",s._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(){var t=e(this).data("ui-draggable");t.scrollParent[0]!==document&&"HTML"!==t.scrollParent[0].tagName&&(t.overflowOffset=t.scrollParent.offset())},drag:function(t){var i=e(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-t.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:t.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-t.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:t.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(t.pageY-e(document).scrollTop()<s.scrollSensitivity?n=e(document).scrollTop(e(document).scrollTop()-s.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<s.scrollSensitivity&&(n=e(document).scrollTop(e(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(t.pageX-e(document).scrollLeft()<s.scrollSensitivity?n=e(document).scrollLeft(e(document).scrollLeft()-s.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<s.scrollSensitivity&&(n=e(document).scrollLeft(e(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&e.ui.ddmanager&&!s.dropBehaviour&&e.ui.ddmanager.prepareOffsets(i,t)}}),e.ui.plugin.add("draggable","snap",{start:function(){var t=e(this).data("ui-draggable"),i=t.options;t.snapElements=[],e(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=e(this),s=i.offset();this!==t.element[0]&&t.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(t,i){var s,n,a,o,r,h,l,u,c,d,p=e(this).data("ui-draggable"),f=p.options,m=f.snapTolerance,g=i.offset.left,v=g+p.helperProportions.width,b=i.offset.top,y=b+p.helperProportions.height;for(c=p.snapElements.length-1;c>=0;c--)r=p.snapElements[c].left,h=r+p.snapElements[c].width,l=p.snapElements[c].top,u=l+p.snapElements[c].height,r-m>v||g>h+m||l-m>y||b>u+m||!e.contains(p.snapElements[c].item.ownerDocument,p.snapElements[c].item)?(p.snapElements[c].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(s=m>=Math.abs(l-y),n=m>=Math.abs(u-b),a=m>=Math.abs(r-v),o=m>=Math.abs(h-g),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||a||o,"outer"!==f.snapMode&&(s=m>=Math.abs(l-b),n=m>=Math.abs(u-y),a=m>=Math.abs(r-g),o=m>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[c].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=s||n||a||o||d)}}),e.ui.plugin.add("draggable","stack",{start:function(){var t,i=this.data("ui-draggable").options,s=e.makeArray(e(i.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});s.length&&(t=parseInt(e(s[0]).css("zIndex"),10)||0,e(s).each(function(i){e(this).css("zIndex",t+i)}),this.css("zIndex",t+s.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._zIndex&&e(i.helper).css("zIndex",s._zIndex)}})})(jQuery);(function(e){function t(e,t,i){return e>t&&t+i>e}e.widget("ui.droppable",{version:"1.10.3",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t=this.options,i=t.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(i)?i:function(e){return e.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},e.ui.ddmanager.droppables[t.scope]=e.ui.ddmanager.droppables[t.scope]||[],e.ui.ddmanager.droppables[t.scope].push(this),t.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var t=0,i=e.ui.ddmanager.droppables[this.options.scope];i.length>t;t++)i[t]===this&&i.splice(t,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){"accept"===t&&(this.accept=e.isFunction(i)?i:function(e){return e.is(i)}),e.Widget.prototype._setOption.apply(this,arguments)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var t=e.data(this,"ui-droppable");return t.options.greedy&&!t.options.disabled&&t.options.scope===s.options.scope&&t.accept.call(t.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(t,{offset:t.element.offset()}),t.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(e,i,s){if(!i.offset)return!1;var n,a,o=(e.positionAbs||e.position.absolute).left,r=o+e.helperProportions.width,h=(e.positionAbs||e.position.absolute).top,l=h+e.helperProportions.height,u=i.offset.left,c=u+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return o>=u&&c>=r&&h>=d&&p>=l;case"intersect":return o+e.helperProportions.width/2>u&&c>r-e.helperProportions.width/2&&h+e.helperProportions.height/2>d&&p>l-e.helperProportions.height/2;case"pointer":return n=(e.positionAbs||e.position.absolute).left+(e.clickOffset||e.offset.click).left,a=(e.positionAbs||e.position.absolute).top+(e.clickOffset||e.offset.click).top,t(a,d,i.proportions.height)&&t(n,u,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(o>=u&&c>=o||r>=u&&c>=r||u>o&&r>c);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions.height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions={width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight})}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e.data(this,"ui-droppable").options.scope===n}),a.length&&(s=e.data(a[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}}})(jQuery);(function(e){function t(e){return parseInt(e,10)||0}function i(e){return!isNaN(parseInt(e,10))}e.widget("ui.resizable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("<div class='ui-resizable-handle "+a+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=e(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=t(this.helper.css("left")),n=t(this.helper.css("top")),o.containment&&(s+=e(o.containment).scrollLeft()||0,n+=e(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(t){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,u=this.size.height,c=t.pageX-a.left||0,d=t.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[t,c,d]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==u&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(n)||this._trigger("resize",t,this.ui()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&e.ui.hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||e)&&(t=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,t>o.minWidth&&(o.minWidth=t),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(e){this.offset=this.helper.offset(),i(e.left)&&(this.position.left=e.left),i(e.top)&&(this.position.top=e.top),i(e.height)&&(this.size.height=e.height),i(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,s=this.size,n=this.axis;return i(e.height)?e.width=e.height*this.aspectRatio:i(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===n&&(e.left=t.left+(s.width-e.width),e.top=null),"nw"===n&&(e.top=t.top+(s.height-e.height),e.left=t.left+(s.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,s=this.axis,n=i(e.width)&&t.maxWidth&&t.maxWidth<e.width,a=i(e.height)&&t.maxHeight&&t.maxHeight<e.height,o=i(e.width)&&t.minWidth&&t.minWidth>e.width,r=i(e.height)&&t.minHeight&&t.minHeight>e.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,u=/sw|nw|w/.test(s),c=/nw|ne|n/.test(s);return o&&(e.width=t.minWidth),r&&(e.height=t.minHeight),n&&(e.width=t.maxWidth),a&&(e.height=t.maxHeight),o&&u&&(e.left=h-t.minWidth),n&&u&&(e.left=h-t.maxWidth),r&&c&&(e.top=l-t.minHeight),a&&c&&(e.top=l-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var e,t,i,s,n,a=this.helper||this.element;for(e=0;this._proportionallyResizeElements.length>e;e++){if(n=this._proportionallyResizeElements[e],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],t=0;i.length>t;t++)this.borderDif[t]=(parseInt(i[t],10)||0)+(parseInt(s[t],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&e.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=e(this).data("ui-resizable"),u=l.options,c=l.element,d=u.containment,p=d instanceof e?d.get(0):/parent/.test(d)?c.parent().get(0):d;p&&(l.containerElement=e(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(i=e(p),s=[],e(["Top","Right","Left","Bottom"]).each(function(e,n){s[e]=t(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=e.ui.hasScroll(p,"left")?p.scrollWidth:o,h=e.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(t){var i,s,n,a,o=e(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,c={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-c.left:o.offset.left-c.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-c.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=o.parentData.left),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).data("ui-resizable");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).data("ui-resizable");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size,n=t.originalSize,a=t.originalPosition,o=t.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,u=Math.round((s.width-n.width)/h)*h,c=Math.round((s.height-n.height)/l)*l,d=n.width+u,p=n.height+c,f=i.maxWidth&&d>i.maxWidth,m=i.maxHeight&&p>i.maxHeight,g=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,g&&(d+=h),v&&(p+=l),f&&(d-=h),m&&(p-=l),/^(se|s|e)$/.test(o)?(t.size.width=d,t.size.height=p):/^(ne)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.top=a.top-c):/^(sw)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.left=a.left-u):(t.size.width=d,t.size.height=p,t.position.top=a.top-c,t.position.left=a.left-u)}})})(jQuery);(function(e){e.widget("ui.selectable",e.ui.mouse,{version:"1.10.3",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,a.widgetName+"-item")===a?(s=t(this),!1):undefined}),t.data(e.target,a.widgetName+"-item")===a&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=t("<style>*{ cursor: "+o.cursor+" !important; }</style>").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!o.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<o.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+o.scrollSpeed:e.pageY-this.overflowOffset.top<o.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-o.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<o.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+o.scrollSpeed:e.pageX-this.overflowOffset.left<o.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-o.scrollSpeed)):(e.pageY-t(document).scrollTop()<o.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-o.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<o.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+o.scrollSpeed)),e.pageX-t(document).scrollLeft()<o.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-o.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<o.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+o.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!o.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=t.left,o=a+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>a&&o>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,a=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return n?this.floating?o&&"right"===o||"down"===a?2:1:a&&("down"===a?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return this.floating&&a?"right"===a&&s||"left"===a&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,a,o=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&r.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){o.push(this)});return t(o)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(u.push([t.isFunction(a.options.items)?a.options.items.call(a.element[0],e,{item:this.currentItem}):t(a.options.items,a.element),a]),this.containers.push(a));for(i=u.length-1;i>=0;i--)for(o=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",o),c.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?e.currentItem.children().each(function(){t("<td>&#160;</td>",e.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,a,o,r,h,l,c,u,d,p,f=null,m=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],m=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[m].containerCache.over||(this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1);else{for(o=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],a=this.items.length-1;a>=0;a--)t.contains(this.containers[m].element[0],this.items[a].item[0])&&this.items[a].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[a].top,this.items[a].height))&&(u=this.items[a].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[a][l]-c)&&(d=!0,u+=this.items[a][l]),o>Math.abs(u-c)&&(o=Math.abs(u-c),r=this.items[a],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[m])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[m].element,!0),this._trigger("change",s,this._uiHash()),this.containers[m]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[m],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,a=e.pageX,o=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(a=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(o=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(a=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})})(jQuery);(function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.3",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),a=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(t(e.target).attr("tabIndex",-1),t(a).attr("tabIndex",0),a.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,a=this.element.parent(),o=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),a=n.attr("id");s||(s=o+"-header-"+e,i.attr("id",s)),a||(a=o+"-panel-"+e,n.attr("id",a)),i.attr("aria-controls",a),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=a.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?t():n,newPanel:r};e.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var a,o,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(o=d),o=o||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(a=t.show().outerHeight(),e.animate(i,{duration:r,easing:o,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:o,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(a-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,o,p):t.animate(s,r,o,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})})(jQuery);(function(t){var e=0;t.widget("ui.autocomplete",{version:"1.10.3",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var a=t.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:e=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case a.UP:e=!0,this._keyEvent("previous",n);break;case a.DOWN:e=!0,this._keyEvent("next",n);break;case a.ENTER:case a.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertBefore(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var t=this,i=++e;return function(s){i===e&&t.__response(s),t.pending--,t.pending||t.element.removeClass("ui-autocomplete-loading")}},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})})(jQuery);(function(t){var e,i,s,n,a="ui-button ui-widget ui-state-default ui-corner-all",o="ui-state-hover ui-state-active ",r="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",h=function(){var e=t(this);setTimeout(function(){e.find(":ui-button").button("refresh")},1)},l=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.3",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,h),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var o=this,r=this.options,c="checkbox"===this.type||"radio"===this.type,u=c?"":"ui-state-active",d="ui-state-focus";null===r.label&&(r.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(a).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){r.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){r.disabled||t(this).removeClass(u)}).bind("click"+this.eventNamespace,function(t){r.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){o.buttonElement.addClass(d)}).bind("blur"+this.eventNamespace,function(){o.buttonElement.removeClass(d)}),c&&(this.element.bind("change"+this.eventNamespace,function(){n||o.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(t){r.disabled||(n=!1,i=t.pageX,s=t.pageY)}).bind("mouseup"+this.eventNamespace,function(t){r.disabled||(i!==t.pageX||s!==t.pageY)&&(n=!0)})),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return r.disabled||n?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(r.disabled||n)return!1;t(this).addClass("ui-state-active"),o.buttonElement.attr("aria-pressed","true");var e=o.element[0];l(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return r.disabled?!1:(t(this).addClass("ui-state-active"),e=this,o.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return r.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return r.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",r.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(a+" "+o+" "+r).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(e?this.element.prop("disabled",!0):this.element.prop("disabled",!1),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?l(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(r),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,a=[];s.primary||s.secondary?(this.options.text&&a.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(a.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):a.push("ui-button-text-only"),e.addClass(a.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.3",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})})(jQuery);(function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(a.inline?e.parent()[0]:a.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.3"}});var a,r="datepicker";t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,a;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),a=this._newInst(t(e),n),a.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,a):n&&this._inlineDatepicker(e,a)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,r,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,a,r=this._get(i,"appendText"),o=this._get(i,"isRTL");i.append&&i.append.remove(),r&&(i.append=t("<span class='"+this._appendClass+"'>"+r+"</span>"),e[o?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),a=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:a,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(a?t("<img/>").attr({src:a,alt:n,title:n}):n)),e[o?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,a=new Date(2009,11,20),r=this._get(t,"dateFormat");r.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},a.setMonth(e(this._get(t,r.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(e(this._get(t,r.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),t.input.attr("size",this._formatDate(t,a).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,r,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,a,o){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],r,p)),n(p.settings,a||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],r,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,r);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,r),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),a=t.data(e,r);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),a=t.data(e,r);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,r)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,a){var r,o,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(r=s||{},"string"==typeof s&&(r={},r[s]=a),c&&(this._curInst===c&&this._hideDatepicker(),o=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,r),null!==h&&r.dateFormat!==e&&r.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&r.dateFormat!==e&&r.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in r&&(r.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,o),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,a=t.datepicker._getInst(e.target),r=!0,o=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),r=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",a.dpDiv),n[0]&&t.datepicker._selectDay(e.target,a.selectedMonth,a.selectedYear,n[0]),i=t.datepicker._get(a,"onSelect"),i?(s=t.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(a,"stepBigMonths"):-t.datepicker._get(a,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(a,"stepBigMonths"):+t.datepicker._get(a,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),r=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),r=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,o?1:-1,"D"),r=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(a,"stepBigMonths"):-t.datepicker._get(a,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),r=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,o?-1:1,"D"),r=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(a,"stepBigMonths"):+t.datepicker._get(a,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),r=e.ctrlKey||e.metaKey;break;default:r=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):r=!1;r&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,a=t.datepicker._getInst(i.target);return t.datepicker._get(a,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(a,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,a,r,o,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),a=s?s.apply(e,[e,i]):{},a!==!1&&(n(i.settings,a),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),o={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),o=t.datepicker._checkOffset(i,o,r),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:o.left+"px",top:o.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),t.datepicker._shouldFocusInput(i)&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,a=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],r=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",r*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),a=e.dpDiv.outerHeight(),r=e.input?e.input.outerWidth():0,o=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-r:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+o?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+o):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,a,o=this._curInst;!o||e&&o!==t.data(e,r)||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){t.datepicker._tidyDialog(o)},t.effects&&(t.effects.effect[i]||t.effects[i])?o.dpDiv.hide(i,t.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(e,i,s,n){var a,r=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(r[0])||(a=this._getInst(r[0]),a.selectedDay=a.currentDay=t("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(e,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,a=this._get(e,"altField");a&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(a).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var a,r,o,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,m=(n?n.monthNames:null)||this._defaults.monthNames,g=-1,v=-1,_=-1,b=-1,y=!1,x=function(t){var e=i.length>a+1&&i.charAt(a+1)===t;return e&&a++,e},k=function(t){var e=x(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),a=s.substring(l).match(n);if(!a)throw"Missing number at position "+l;return l+=a[0].length,parseInt(a[0],10)},w=function(i,n,a){var r=-1,o=t.map(x(i)?a:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(o,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(r=i[0],l+=n.length,!1):e}),-1!==r)return r+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(a))throw"Unexpected literal at position "+l;l++};for(a=0;i.length>a;a++)if(y)"'"!==i.charAt(a)||x("'")?D():y=!1;else switch(i.charAt(a)){case"d":_=k("d");break;case"D":w("D",d,p);break;case"o":b=k("o");break;case"m":v=k("m");break;case"M":v=w("M",f,m);break;case"y":g=k("y");break;case"@":h=new Date(k("@")),g=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((k("!")-this._ticksTo1970)/1e4),g=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":x("'")?D():y=!0;break;default:D()}if(s.length>l&&(o=s.substr(l),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=g?0:-100)),b>-1)for(v=1,_=b;;){if(r=this._getDaysInMonth(g,v-1),r>=_)break;v++,_-=r}if(h=this._daylightSavingAdjust(new Date(g,v-1,_)),h.getFullYear()!==g||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,r=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,o=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,a);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),r,o);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),a=n,r=this._getFormatConfig(t);try{a=this.parseDate(i,s,r)||n}catch(o){s=e?"":s}t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),t.currentDay=s?a.getDate():0,t.currentMonth=s?a.getMonth():0,t.currentYear=s?a.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},a=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,a=n.getFullYear(),r=n.getMonth(),o=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":o+=parseInt(l[1],10);break;case"w":case"W":o+=7*parseInt(l[1],10);break;case"m":case"M":r+=parseInt(l[1],10),o=Math.min(o,t.datepicker._getDaysInMonth(a,r));break;case"y":case"Y":a+=parseInt(l[1],10),o=Math.min(o,t.datepicker._getDaysInMonth(a,r))}l=h.exec(i)}return new Date(a,r,o)},r=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return r=r&&"Invalid Date"==""+r?s:r,r&&(r.setHours(0),r.setMinutes(0),r.setSeconds(0),r.setMilliseconds(0)),this._daylightSavingAdjust(r)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,a=t.selectedYear,r=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=r.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=r.getMonth(),t.drawYear=t.selectedYear=t.currentYear=r.getFullYear(),n===t.selectedMonth&&a===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,a,r,o,h,l,c,u,d,p,f,m,g,v,_,b,y,x,k,w,D,T,C,M,S,N,I,P,A,z,H,E,F,O,W,j,R=new Date,L=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),J=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),Q=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),U=this._get(t,"stepMonths"),q=1!==Q[0]||1!==Q[1],X=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),$=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),$)for(e=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-Q[0]*Q[1]+1,$.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-U,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":J?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+U,1)),this._getFormatConfig(t)):n,a=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":J?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",r=this._get(t,"currentText"),o=this._get(t,"gotoCurrent")&&t.currentDay?X:L,r=K?this.formatDate(r,o,this._getFormatConfig(t)):r,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,o)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+r+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),m=this._get(t,"monthNamesShort"),g=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;Q[0]>k;k++){for(w="",this.maxRows=4,D=0;Q[1]>D;D++){if(T=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),C=" ui-corner-all",M="",q){if(M+="<div class='ui-datepicker-group",Q[1]>1)switch(D){case 0:M+=" ui-datepicker-group-first",C=" ui-corner-"+(Y?"right":"left");break;case Q[1]-1:M+=" ui-datepicker-group-last",C=" ui-corner-"+(Y?"left":"right");break;default:M+=" ui-datepicker-group-middle",C=""}M+="'>"}for(M+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+C+"'>"+(/all|left/.test(C)&&0===k?Y?a:s:"")+(/all|right/.test(C)&&0===k?Y?s:a:"")+this._generateMonthYearHeader(t,Z,te,G,$,k>0||D>0,f,m)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",S=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",x=0;7>x;x++)N=(x+c)%7,S+="<th"+((x+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[N]+"'>"+p[N]+"</span></th>";for(M+=S+"</tr></thead><tbody>",I=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,I)),P=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((P+I)/7),z=q?this.maxRows>A?this.maxRows:A:A,this.maxRows=z,H=this._daylightSavingAdjust(new Date(te,Z,1-P)),E=0;z>E;E++){for(M+="<tr>",F=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(H)+"</td>":"",x=0;7>x;x++)O=g?g.apply(t.input?t.input[0]:null,[H]):[!0,""],W=H.getMonth()!==Z,j=W&&!_||!O[0]||G&&G>H||$&&H>$,F+="<td class='"+((x+c+6)%7>=5?" ui-datepicker-week-end":"")+(W?" ui-datepicker-other-month":"")+(H.getTime()===T.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===H.getTime()&&b.getTime()===T.getTime()?" "+this._dayOverClass:"")+(j?" "+this._unselectableClass+" ui-state-disabled":"")+(W&&!v?"":" "+O[1]+(H.getTime()===X.getTime()?" "+this._currentClass:"")+(H.getTime()===L.getTime()?" ui-datepicker-today":""))+"'"+(W&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"&#39;")+"'")+(j?"":" data-handler='selectDay' data-event='click' data-month='"+H.getMonth()+"' data-year='"+H.getFullYear()+"'")+">"+(W&&!v?"&#xa0;":j?"<span class='ui-state-default'>"+H.getDate()+"</span>":"<a class='ui-state-default"+(H.getTime()===L.getTime()?" ui-state-highlight":"")+(H.getTime()===X.getTime()?" ui-state-active":"")+(W?" ui-priority-secondary":"")+"' href='#'>"+H.getDate()+"</a>")+"</td>",H.setDate(H.getDate()+1),H=this._daylightSavingAdjust(H);M+=F+"</tr>"}Z++,Z>11&&(Z=0,te++),M+="</tbody></table>"+(q?"</div>"+(Q[0]>0&&D===Q[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),w+=M}y+=w}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,a,r,o){var h,l,c,u,d,p,f,m,g=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(a||!g)y+="<span class='ui-datepicker-month'>"+r[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+o[c]+"</option>");y+="</select>"}if(_||(b+=y+(!a&&g&&v?"":"&#xa0;")),!t.yearshtml)if(t.yearshtml="",a||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);
+return isNaN(e)?d:e},f=p(u[0]),m=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";m>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!a&&g&&v?"":"&#xa0;")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),a=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),r=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,a)));t.selectedDay=r.getDate(),t.drawMonth=t.selectedMonth=r.getMonth(),t.drawYear=t.selectedYear=r.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),a=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(t,a)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),a=this._getMinMaxDate(t,"max"),r=null,o=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),r=parseInt(i[0],10),o=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(r+=s),i[1].match(/[+\-].*/)&&(o+=s)),(!n||e.getTime()>=n.getTime())&&(!a||e.getTime()<=a.getTime())&&(!r||e.getFullYear()>=r)&&(!o||o>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.3"})(jQuery);(function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.3",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._destroyOverlay(),this.opener.filter(":focusable").focus().length||t(this.document[0].activeElement).blur(),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html("&#160;"),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,a;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(a).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,a){s.position=[a.position.left-i.document.scrollLeft(),a.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(a))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,a){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(a))}}).css("position",a)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,a=!1,o={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(a=!0),t in i&&(o[t]=s)}),a&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",o)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})})(jQuery);(function(t){t.widget("ui.menu",{version:"1.10.3",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.mouseHandled=!0,this.select(e),i.has(".ui-menu").length?this.expand(e):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,a,o,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",a=String.fromCharCode(e.keyCode),o=!1,clearTimeout(this.filterTimer),a===n?o=!0:a=n+a,r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=o&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(a=String.fromCharCode(e.keyCode),r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=a,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})})(jQuery);(function(t,e){t.widget("ui.progressbar",{version:"1.10.3",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})})(jQuery);(function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.3",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)o.push(a);this.handles=n.add(t(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):this.range=t([])},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,a,o,r,h,l,u=this,c=this.options;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-u.values(e));(n>i||n===i&&(e===u._lastChangedValue||u.values(e)===c.min))&&(n=i,a=t(this),o=e)}),r=this._start(e,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),h=a.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-a.width()/2,top:e.pageY-h.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,a;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,a=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),a!==!1&&this.values(e,i,!0))):i!==this.value()&&(a=this._trigger("slide",t,{handle:this.handles[e],value:i}),a!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,a;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,a,o=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](u,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,a,o,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(o=this.options.step,n=a=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:a=this._valueMin();break;case t.ui.keyCode.END:a=this._valueMax();break;case t.ui.keyCode.PAGE_UP:a=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:a=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;a=this._trimAlignValue(n+o);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;a=this._trimAlignValue(n-o)}this._slide(i,r,a)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})})(jQuery);(function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.3",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})})(jQuery);(function(t,e){function i(){return++n}function s(t){return t.hash.length>1&&decodeURIComponent(t.href.replace(a,""))===decodeURIComponent(location.href.replace(a,""))}var n=0,a=/#.*$/;t.widget("ui.tabs",{version:"1.10.3",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,a){return t(a).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),a=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:a=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,a),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var a,o,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),u=l.attr("aria-controls");s(n)?(a=n.hash,o=e.element.find(e._sanitizeSelector(a))):(r=e._tabId(l),a="#"+r,o=e.element.find(a),o.length||(o=e._createPanel(r),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),u&&l.data("ui-tabs-aria-controls",u),l.attr({"aria-controls":a.substring(1),"aria-labelledby":h}),o.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?t():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):t(),u={oldTab:s,oldPanel:l,newTab:r?t():a,newPanel:h};e.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",e,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?t():a,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),e),this._toggle(e,u))},_toggle:function(e,i){function s(){a.running=!1,a._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,a=this.tabs.eq(e),o=a.find(".ui-tabs-anchor"),r=this._getPanelForTab(a),h={tab:a,panel:r};s(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(a.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),a.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,a){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:a},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})})(jQuery);(function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.3",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,a=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=a),this._open(e,t,i)})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function a(t){l.of=t,o.is(":hidden")||o.position(l)}var o,r,h,l=t.extend({},this.options.position);if(n){if(o=this._find(s),o.length)return o.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),o=this._tooltip(s),e(s,o.attr("id")),o.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:a}),a(i)):o.position(t.extend({of:s},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){o.is(":visible")&&(a(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:o}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(o)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),a=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),a.stop(!0),this._hide(a,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:a}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})})(jQuery);(function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[c[l].cache]=o[c[l].cache],n=s._rgba=o._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,a.transparent),s):a[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,o,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(o),o=e);var u=this,d=t.type(n),p=this._rgba=[];return o!==e&&(n=[n,o,r,h],d="array"),"string"===d?this.parse(s(n)||a._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var a=s.cache;f(s.props,function(t,e){if(!u[a]&&s.to){if("alpha"===t||null==n[t])return;u[a]=s.to(u._rgba)}u[a][e.idx]=i(n[t],e,!0)}),u[a]&&0>t.inArray(null,u[a].slice(0,3))&&(u[a][3]=1,s.from&&(u._rgba=s.from(u[a])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),a=c[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(t,n){var a=n.idx,o=r[a],l=s[a],c=u[n.type]||{};null!==l&&(null===o?h[a]=l:(c.mod&&(l-o>c.mod/2?o+=c.mod:o-l>c.mod/2&&(o-=c.mod)),h[a]=i((l-o)*e+o,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,a=t[2]/255,o=t[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==o?1:o]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],a=t[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,e+1/3)),Math.round(255*n(r,o,e)),Math.round(255*n(r,o,e-1/3)),a]},f(c,function(s,n){var a=n.props,o=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===e)return this[o].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[o].slice();return f(a,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[o]=d,n):l(d)},f(a,function(e,i){l.fn[e]||(l.fn[e]=function(n){var a,o=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===o?c:("function"===o&&(n=n.call(this,c),o=t.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=c+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var a,o,r="";if("transparent"!==n&&("string"!==t.type(n)||(a=s(n)))){if(n=l(a||n),!d.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&o&&o.style;)try{r=t.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(o),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},a=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function s(e,i){var s,n,o={};for(s in i)n=i[s],e[s]!==n&&(a[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(o[s]=n));return o}var n=["add","remove","toggle"],a={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,a,o,r){var h=t.speed(a,o,r);return this.queue(function(){var a,o=t(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),a=function(){t.each(n,function(t,i){e[i]&&o[i+"Class"](e[i])})},a(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){a(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(o[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,a){return s?t.effects.animateClass.call(this,{add:i},s,n,a):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,a){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,a):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,a,o,r){return"boolean"==typeof n||n===e?a?t.effects.animateClass.call(this,n?{add:s}:{remove:s},a,o,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,a,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,a){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,a)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.3",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,a;for(a=0;s.length>a;a++)null!==s[a]&&(n=t.data(i+s[a]),n===e&&(n=""),t.css(s[a],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return e.wrap(s),(e[0]===a||t.contains(e[0],a))&&t(a).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var a=e.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(a)&&a.call(n[0]),t.isFunction(e)&&e()}var n=t(this),a=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):o.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,a=i.queue,o=t.effects.effect[i.effect];return t.fx.off||!o?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):a===!1?this.each(e):this.queue(a||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()})(jQuery);(function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var a,o,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",m=i.test(u),g={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),a=t.effects.createWrapper(h).css({overflow:"hidden"}),o=a[p](),r=parseFloat(a.css(f))||0,g[p]=v?o:0,m||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),g[f]=v?r:o+r),v&&(a.css(p,0),m||a.css(f,r+o)),a.animate(g,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}})(jQuery);(function(t){t.effects.effect.bounce=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(o,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),m=e.duration/f,g=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=o.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(o,r),o.show(),t.effects.createWrapper(o),d||(d=o["top"===v?"outerHeight":"outerWidth"]()/3),c&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,_?2*-d:2*d).animate(a,m,g)),l&&(d/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,o.animate(n,m,g).animate(a,m,g),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),o.dequeue()}})(jQuery);(function(t){t.effects.effect.clip=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(o,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(o,r),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[d](),l&&(n.css(d,0),n.css(p,a/2)),f[d]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","opacity","height","width"],o=t.effects.setMode(n,e.mode||"hide"),r="show"===o,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,a),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),m||p.hide(),i()}var a,o,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(a=0;u>a;a++)for(h=g.top+a*_,c=a-(u-1)/2,o=0;d>o;o++)r=g.left+o*v,l=o-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(m?l*v:0),top:h+(m?c*_:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:c*_),opacity:m?1:0},e.duration||500,e.easing,s)}})(jQuery);(function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}})(jQuery);(function(t){t.effects.effect.fold=function(e,i){var s,n,a=t(this),o=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(a,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],m=e.duration/2,g={},v={};t.effects.save(a,o),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),g[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(g,m,e.easing).animate(v,m,e.easing,function(){l&&a.hide(),t.effects.restore(a,o),t.effects.removeWrapper(a),i()})}})(jQuery);(function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],a=t.effects.setMode(s,e.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(o,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&s.hide(),t.effects.restore(s,n),i()}})}})(jQuery);(function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),a=t.effects.setMode(n,e.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),a="hide"===n,o=parseInt(e.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),a=t.effects.setMode(s,e.mode||"effect"),o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===a?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(o,e.mode||"effect"),f=e.restore||"effect"!==p,m=e.scale||"both",g=e.origin||["middle","center"],v=o.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===e.mode&&"show"===p?(o.from=e.to||b,o.to=e.from||s):(o.from=e.from||("show"===p?b:s),o.to=e.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(_=_.concat(u),o.from=t.effects.setTransition(o,u,a.from.y,o.from),o.to=t.effects.setTransition(o,u,a.to.y,o.to)),a.from.x!==a.to.x&&(_=_.concat(d),o.from=t.effects.setTransition(o,d,a.from.x,o.from),o.to=t.effects.setTransition(o,d,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(_=_.concat(c).concat(l),o.from=t.effects.setTransition(o,c,a.from.y,o.from),o.to=t.effects.setTransition(o,c,a.to.y,o.to)),t.effects.save(o,_),o.show(),t.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=t.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),o.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=t.effects.setTransition(i,u,a.from.y,i.from),i.to=t.effects.setTransition(i,u,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=t.effects.setTransition(i,d,a.from.x,i.from),i.to=t.effects.setTransition(i,d,a.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),t.effects.restore(o,_),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):t.each(["top","left"],function(t,e){o.css(e,function(e,i){var s=parseInt(i,10),n=t?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","height","width"],o=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),_=v.length;for(t.effects.save(n,a),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,m[d]=(p?"+=":"-=")+2*h,g[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(m,u,e.easing).animate(g,u,e.easing);n.animate(m,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","width","height"],o=t.effects.setMode(n,e.mode||"show"),r="show"===o,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,a),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),a="fixed"===n.css("position"),o=t("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}})(jQuery);
\ No newline at end of file
diff --git a/dgbuilder/public/jquery/js/jquery.ui.touch-punch.min.js b/dgbuilder/public/jquery/js/jquery.ui.touch-punch.min.js
new file mode 100644 (file)
index 0000000..31272ce
--- /dev/null
@@ -0,0 +1,11 @@
+/*!
+ * jQuery UI Touch Punch 0.2.3
+ *
+ * Copyright 2011–2014, Dave Furfero
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Depends:
+ *  jquery.ui.widget.js
+ *  jquery.ui.mouse.js
+ */
+!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
\ No newline at end of file
diff --git a/dgbuilder/public/node-red.png b/dgbuilder/public/node-red.png
new file mode 100644 (file)
index 0000000..a60c267
Binary files /dev/null and b/dgbuilder/public/node-red.png differ
diff --git a/dgbuilder/public/orion/built-editor.css b/dgbuilder/public/orion/built-editor.css
new file mode 100644 (file)
index 0000000..0204578
--- /dev/null
@@ -0,0 +1,526 @@
+.textview {
+       background-color: white;
+       font-family: "Consolas", "Monaco", "Vera Mono", "monospace";
+       font-size: 10pt;
+       min-width: 50px;
+       min-height: 50px;
+}
+.textviewScroll {
+       padding: 1px 2px;
+}
+.textviewContent {
+  cursor: auto;
+}
+.textviewLeftRuler {
+       border-right: 1px solid #eaeaea;
+}
+.textviewRightRuler {
+       border-left: 1px solid #eaeaea;
+}
+.textviewMarginRuler {
+       border-left: 1px solid #eaeaea;
+}
+.textviewBlockCursor {
+       background: black;
+       opacity: 0.4;
+}
+.ruler {
+}
+.ruler.annotations {
+       width: 16px;
+}
+.ruler.folding {
+       width: 14px;
+}
+.ruler.lines {
+       text-align: right;
+}
+.ruler.overview {
+       width: 14px;
+}
+.rulerLines {
+       color: silver;
+}
+.rulerLines.even
+.rulerLines.odd {
+}
+.tooltipTheme.textview {
+       background-color: InfoBackground !important;
+       color: InfoText !important;
+}
+.tooltipTheme .textviewScroll {
+       padding: 0px;
+}
+.textviewTooltip {
+       font-family: "Consolas", "Monaco", "Vera Mono", "monospace";
+       font-size: 10pt;
+       background-color: InfoBackground;
+       color: InfoText;
+       padding: 2px;
+       border-radius: 4px;
+       border: 1px solid black;
+       z-index: 100;
+       position: fixed;
+       overflow: hidden;
+}
+.textviewTooltip em {
+       font-style: normal;
+       font-weight: bold;
+}
+.textviewTooltip span {
+       vertical-align: baseline;
+}
+.textviewTooltip .tooltipRow {
+       display: table-row;
+}
+.textviewTooltip .tooltipTitle {
+       float: right;
+}
+.tooltipTheme .annotationLine.currentLine {
+       background-color: transparent !important;
+}
+.contentassist {
+       font-size:9pt;
+       display: none;
+       background-color: white;
+       position: fixed;
+       top: 100px;
+       left: 100px;
+       z-index:100;
+       cursor: default;
+       min-width: 70px;
+       max-width: 350px;
+       max-height: 170px;
+       overflow: hidden;
+       white-space: nowrap;
+       border-radius: 5px;
+       box-shadow: rgba(0, 0, 0, 0.3) 2px 2px 10px;
+       line-height: 18px;
+}
+.contentassist:focus {
+       outline: none;
+}
+.contentassist:hover {
+       overflow-y: auto;
+}
+.contentassist .proposal-emphasis {
+       font-weight: normal;
+}
+.contentassist hr{
+       border: 0;
+    height: 0;
+    border-top: 1px solid rgba(0, 0, 0, 0.1);
+    border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+}
+.contentassist .proposal-noemphasis-keyword {
+       background-color: aliceblue;
+       color: #CC4C07;
+       font-weight: bold;
+}
+.contentassist .proposal-noemphasis {
+       background-color: aliceblue;
+       font-weight: lighter;
+       color: black;
+}
+.contentassist .proposal-noemphasis-title-keywords {
+       background-color: aliceblue;
+       color: grey;
+}
+.contentassist .proposal-noemphasis-title {
+       background-color: aliceblue;
+       color: grey;
+       padding-top: 5px;
+}
+.contentassist .proposal-noemphasis-title::before {
+       content: "- ";
+}
+.contentassist .proposal-noemphasis-title::after {
+       content: " -";
+}
+.contentassist .proposal-default {
+       
+}
+.contentassist .proposal-name {
+       font-weight: bold;
+}
+.contentassist > div:hover {
+       background-color: #fab467; 
+       background: linear-gradient(#fabb76, #e1a25c);
+       border-radius: 3px;
+}
+.contentassist>div.proposal-hr:hover {
+       background-color: white; 
+       background: none;
+}
+.contentassist .selected {
+       background-color: rgb(48, 135, 179); 
+       background: linear-gradient(rgb(60, 150, 190), rgb(30, 120, 160));
+       border-radius: 3px;
+       color: white;
+}
+.contentassist .cloneProposal {
+       box-shadow: rgba(0, 0, 0, 0.9) 2px 2px 8px;
+       position: fixed;
+       z-index: 1000; 
+}
+.contentassist>div {
+       padding: 1px 3px 1px 5px;
+}
+.cloneWrapper {
+       display: block;
+       overflow: visible;
+       z-index: 1000; 
+}
+.contentassist.cloneWrapper:hover {
+       overflow: visible;
+}
+.comment.block.documentation, .comment-block-documentation {
+       color: #00008F;
+}
+.comment {
+       color: #3C802C;
+}
+.constant.character.entity, .constant-character-entity {
+       font-style: normal;
+}
+.constant {
+       color: blue;
+}
+.entity.name.function, .entity.name.type, .entity-name-function, .entity-name-type {
+       font-weight: bold;
+}
+.entity.name.tag, .entity-name-tag {
+       color: #CC4C07;
+}
+.entity.other.attribute.name, .entity-other-attribute-name {
+       color: #3C802C;
+}
+.entity {
+       color: #3f7f7f;
+}
+.invalid.illegal, .invalid-illegal {
+       color: white;
+       background-color: red;
+}
+.invalid.deprecated, .invalid-deprecated {
+       text-decoration: line-through;
+}
+.invalid {
+       color: red;
+       font-weight: bold;
+}
+.keyword.other.documentation.markup {
+       color: #7F7F9F;
+}
+.keyword.other.documentation {
+       color: #7F9FBF;
+}
+.keyword.operator, .keyword-operator {
+       color: #ddd;
+}
+.keyword {
+       color: #CC4C07;
+       font-weight: bold;
+}
+.markup.heading, .markup-heading {
+       font-weight: bold;
+}
+.markup.quote, .markup-quote {
+       font-style: italic;
+}
+.meta.annotation.currentLine {
+       background-color: #EAF2FE;
+}
+.meta.tag {
+       color: #3f7f7f;
+}
+.punctuation.definition.comment, .punctuation-definition-comment {
+       color: #3f5fbf;
+}
+.punctuation.definition.string, .punctuation-definition-string {
+       color: blue;
+}
+.punctuation.separator.space {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABVJREFUCNdj3L17938GBgYGJgYoAAAxOAM004kASgAAAABJRU5ErkJggg==");
+       background-repeat: no-repeat;
+       background-position: center center;
+}
+.punctuation.separator.tab {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAFCAYAAABmWJ3mAAAAAXNSR0IArs4c6QAAABtJREFUCNdj2L17938GKEBmYwgQJ0m8IAMDAwDemh/hgxuOkwAAAABJRU5ErkJggg==");
+       background-repeat: no-repeat;
+       background-position: left center;
+}
+.storage {
+       color: #7F0055;
+}
+.string {
+       color: #446fbd;
+}
+.support {
+       color: #21439c;
+}
+.variable.parameter, .variable-parameter {
+       color: black;
+}
+.variable.language, .variable-language {
+       color: #7F0055;
+       font-weight: bold;
+}
+.variable {
+       color: #0000c0;
+}
+.cm-meta { color: #00008F; }
+.cm-keyword { font-weight: bold; color: #7F0055; }
+.cm-atom { color: #21439c; }
+.cm-number { color: black; }
+.cm-def { color: green; }
+.cm-variable { color: black; }
+.cm-variable-2 { color: #004080; }
+.cm-variable-3 { color: #004080; }
+.cm-property { color: black; }
+.cm-operator { color: #222; }
+.cm-comment { color: green; }
+.cm-string { color: blue; }
+.cm-error { color: #ff0000; }
+.cm-qualifier { color: gray; }
+.cm-builtin { color: #7F0055; }
+.cm-bracket { color: white; background-color: gray; }
+.cm-tag { color: #3f7f7f; }
+.cm-attribute { color: #7f007f; }
+.annotation {
+}
+.annotation.error,
+.annotation.warning,
+.annotation.task,
+.annotation.bookmark,
+.annotation.breakpoint,
+.annotation.collapsed,
+.annotation.expanded, 
+.annotation.currentBracket, 
+.annotation.matchingBracket, 
+.annotation.currentLine, 
+.annotation.matchingSearch,  
+.annotation.currentSearch,
+.annotation.readOccurrence,
+.annotation.writeOccurrence, 
+.annotation.linkedGroup, 
+.annotation.currentLinkedGroup,
+.annotation.selectedLinkedGroup {
+}
+.annotation.blame {
+       color: gray;
+       background-color: rgb(255, 132, 44);
+}
+.annotation.currentBlame {
+       color: black;
+       background-color: rgb(184, 103, 163);
+}
+.annotationHTML {
+       cursor: pointer;
+       width: 16px;
+       height: 16px;
+       display: inline-block;
+       vertical-align: middle;
+       background-position: center;
+       background-repeat: no-repeat;
+}
+.annotationHTML.error {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjNGNTlDOUMxMUVDNDExRTM4NDU4RjQ3Q0I3NkI4OTBDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjNGNTlDOUMyMUVDNDExRTM4NDU4RjQ3Q0I3NkI4OTBDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6M0Y1OUM5QkYxRUM0MTFFMzg0NThGNDdDQjc2Qjg5MEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6M0Y1OUM5QzAxRUM0MTFFMzg0NThGNDdDQjc2Qjg5MEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Be44kAAAAqklEQVR42mL8//8/AyWAiYFCQLEBLNgEX+aURgGpAiA2gAqdB+KJ4lO6l6GrZUQPA6DmqUAqC4eF04CGZOP0AtRmkOZ/QHwLSeoWVCwLqgZnGORD6TtA7ArEp6DYFSqGrAZrGBhCaTUgXg3EoVD+aqgYshraRON5JD+HQm2GueQWmhqsBkyE0ipAvBuIzaB4N1QMWQ11opERW16ARlU+UoARn5CGXmYCCDAAPz09iI0KJ9QAAAAASUVORK5CYII=");
+}
+.annotationHTML.warning {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkREMTE1OUNDMUVDMjExRTM4NDU4RjQ3Q0I3NkI4OTBDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkREMTE1OUNEMUVDMjExRTM4NDU4RjQ3Q0I3NkI4OTBDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REQxMTU5Q0ExRUMyMTFFMzg0NThGNDdDQjc2Qjg5MEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REQxMTU5Q0IxRUMyMTFFMzg0NThGNDdDQjc2Qjg5MEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Kzt/qAAAA0ElEQVR42mL8//8/AyWAiYFCQLEBLLgkfl8obARSZUD8HYiLWQ3652NTx4gtDICao4HUbCDeBRVyBmI3oCHHCRoA1MwOpO4A8V+gBgWo2AMg9QaITYFi/wl5IRaIZYD4K1AjI8gSIBYBYnkg9gLirYQCMRdKc0M1KUDZIFCM1wtAG02B1Ckk+WlQSzKQxLSA3riOywUpaHxHILZHE8vA54VQNL4XFCODaHyB+B6IBZH4s7CE0Ud8LvCHhsFfKN8VihmgYqegavAnpKGVmQACDACxJDv3vmRk+gAAAABJRU5ErkJggg==");
+}
+.annotationHTML.task {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjdEMjg0RkI2MUVFMzExRTM4NDU4RjQ3Q0I3NkI4OTBDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjdEMjg0RkI3MUVFMzExRTM4NDU4RjQ3Q0I3NkI4OTBDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6N0QyODRGQjQxRUUzMTFFMzg0NThGNDdDQjc2Qjg5MEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6N0QyODRGQjUxRUUzMTFFMzg0NThGNDdDQjc2Qjg5MEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Utm8RAAAAl0lEQVR42mL8//8/AyWAiYFCQLEBLMicqtVRRPmnLXQZIzkuuEuJF04BsTEQ15JjAEizGxB/AmJpYgz4DsTLoewrQOwJ9PNHID0ViDPwBiIURAPxBqjm2UDN74CB2wFkZxKMBSioAOJ9QI1t0JgBaS4nKhqhwAyIdwE1ugLpLHyacRkAM+QcECtTkhKViYlfxqGfmQACDAAjXCa0hW/NdQAAAABJRU5ErkJggg==");
+}
+.annotationHTML.bookmark {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjdEMjg0RkIyMUVFMzExRTM4NDU4RjQ3Q0I3NkI4OTBDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjdEMjg0RkIzMUVFMzExRTM4NDU4RjQ3Q0I3NkI4OTBDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6N0QyODRGQjAxRUUzMTFFMzg0NThGNDdDQjc2Qjg5MEMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6N0QyODRGQjExRUUzMTFFMzg0NThGNDdDQjc2Qjg5MEMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz54SgjJAAAAuUlEQVR42mL8//8/AyWAiYFCQFsDWrdcMAViY3xqWAhYEADEv4H4LLle8IVinIARORaAzpUHiUG5qkC8C8p2AOKHQPwDhKt9DD7gcoEREJ8H4vtImkHgAFTsKhB743QB1BWyQGo+EDujGb4JiNOBtr/AawDUEH0gdQFNWBGo+QGxgRgEpV8C8SsoO4KUWAAZsAeIDYBYB4g3A3EUwViAOl8Falsb0Mn/kMRTQYYCxe4TDIOhlZkAAgwAunFAhB2QB2cAAAAASUVORK5CYII=");
+}
+.annotationHTML.breakpoint {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAFheoFxkoFxnpmt0pmZxpnF7rYyWwmJwpnaFs3aDrWt8rXGBrYycwmZ3mXuNs42cu77F03GIs3aJrYGVu2J5oKCuxeDj6LK/03GLrYieu3aIoIygu6m4zcLN3MTM1m6Rs2aLriRgkSZilXGXtoGcs7LD0QBLhSZikihol3ScubrO2Yaqu5q4xpO0wpm7yabF0ZO9yaXI0r3X3tHj6P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADQALAAAAAAQABAAAAafQJpwSCwWLYZBIDAwWIw0A+FFpW6aRUPCxe1yE4ahhdCCxWSzmSwGgxGeUceKpUqhUCkVa7UK0wgkJCUjJoUmIyWBBEIEGhoeJ4YmJx6OAUIADQ0QIZIhEJoAQgEUFBUgkiAVpZdRCxIPFx8iIh8XDw4FfhYHDhgZHB0dHBkYEwdwUQoTEc3OEwp+QwYHCBMMDBMIB9JESAJLAk5Q5EVBADs=");
+}
+.annotationHTML.collapsed {
+       
+       width: 14px;
+       height: 14px;
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNpi/P//PwMlgImBQkCxASzoAp++fo+6de+Z+fXbD/Jev/nAICoiwKCpqrBBTUlqNR835zJ09YzIYfDxy7eo/cevLmXlYGNQUJAEahZieP3mHcODB08Zfv/4w+BoqR3Nz8O1DKcXzt94HPqXmZlBU1+LgZNfkMHazIOBA0hr6uswgMTP33gYijcMLlx/EMAnLs7w7sc/hg9AG0HgPZB+B8S84hJA+UcBeMPg+at3DJIMnAxZzt5wsUhnXzDdsmIVWB6vAcLCfAys3z4wzN64huEfkJ/uH8IwexOQDQymD2/fgeXxekFLRWHD51evGDhZGRi4WSFSnCwgNjB2Xr1m0AbK4zXAQkdhNdPf3wx3r91g+PruLcOqnasYvn54x3Dv2k0G5r+/GMyB8nijEQTefvoadeH6w9Cbtx8GvH//kUFQkJ9BQ1V+g76m/GphPu5lBA0YenmBYgMAAgwA34GIKjmLxOUAAAAASUVORK5CYII=");
+}
+.annotationHTML.expanded {
+       
+       width: 14px;
+       height: 14px;   
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAT5JREFUeNrUksFKw0AURW+mTWw67SSEiG209U90r4jddFO34l+5U0HdZCHiFwiCOz9AlMSmGEpMOqk1TWJSFGyFbATR2dyZd+Dw3mOENE3xkyP8PYHrBT3OX7uW43ZefA6FUaw1dJPSyrmu1k8KBYOh37Od4XFZLEPXFdRrFMGIw3U9TKMYqw1tb0VjcxLy9eEF425CCIxWE5JcxSQGxCyNloG87gXhwWIHc4J767lTZQw8ShFGSZbxRyaQmZJxd3NRUJ6ffwQNEi6PzG/L2tjdmvFCgcKqKL2F2Olu43MzggDka+IjPuOFI7Sbujn2fUglYKkkzFIi+R0I/QDrGS8UqDX5QkhiOHYfE84hkhSTkGNgOyDJFCzjhYLTq+vDtrG8r1LZtB6fcHtzB+uhD5VWzLx+lvF/8JV/XfAuwADsrJbMGG4l4AAAAABJRU5ErkJggg==");
+}
+.annotationHTML.multiple {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAOdpa+yJiuFYXOFYXeBYXONwded8f+NwdmhwkHB4iPr7/ezx+fP2+2h4kOzy+Wh4iPr8/gCBwTaczjaXyjaYyjaXyTaYyfr8/QCMzQCMzACHxzao2jal2Dak1zag03iAgI/Ckn64fZrHmX+4fZLCianPopPCiarOoqbLlafLlbnXq7nWq6fLlMTcsoCIeJCQcIiIeKCYaJiQcO16ee16evGVlfGWlfahn/ahoPWhn/WhoPe1tP///////wAAAAAAACH5BAEAAD0ALAAAAAAQABAAAAaRwJ5wSCwaj8WYcslcDmObaDTGq1Zjzw4mk+FQIRcFTzaUeTRoj4zHaI+HL0lkLnnxFgsH7zWEWSoTFBMwVlUwQy6JMDCJjYwuQx8tk5MfOzk4OjcfkSssKCkqHzY0MzQ1nEIJJSYkJCcJAQCzAQlDDyIjISMiCQYEAgMGD0MNIMfHDQUHBc3EQgjR0tPSSNY9QQA7");
+}
+.annotationHTML.overlay {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII=");
+       background-position: right bottom;
+       position: relative;
+       top: -16px;
+}
+.annotationHTML.currentBracket {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sLEBULCGQmEKAAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAnklEQVQ4y7VTsRHDIBATJg1HCUzAHEzFBExAzwZsRMkE9gifKhc72ODYibr/+xcnoQdugq0LAujEwmbn0UxQh4OxpjX1XgshwFqLnPM5PQTQGlprWpbl3RhJ/CSQUm7qPYLp7i8cEpRSoJT6ju0lIaVEQgiKMQ4lHHpQayVjzHWCn5jIOcc8z9dMBADvPZxz3SC1tzCI8vgWdvL+VzwB8JSj2GFTyxIAAAAASUVORK5CYII=");
+}
+.annotationHTML.matchingBracket {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sLEBUMAsuyb3kAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAoklEQVQ4y61TsQ3EIAw80DcI0USKGIApWIsB2IGGKbJPugxBR3VfvfRRCOSTvw7LPuPzGXgI8f0gwAsFu5rXIYMdDiEOIdnKW5YFzjnEGH+bhwA/KKVwmibu0BhRnpEZY1BrHTaVT7fQJZjnGeu63tOAJFNKVEox53yqQZfAWstt27oidgm01ve3UEqBaBjnspG89wgh3LiFgZXHt3Dh23/FGxKViehm0X85AAAAAElFTkSuQmCC");
+}
+.annotationHTML.currentLine {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQAALxe0bNWzbdZzrlb0KpPx61RybBTy6VLxadNxZGctIeUroyYsG92hHyMqIKRq2l9nmyAoHGDonaIpStXj6q80k1aXf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABYALAAAAAAQABAAAAVCoCWOZGmeKDql5ppOMGXBk/zOoltSNO6XrlXwxIPNYiMGq8SoLC2MaNPygEQkDYdikUg6LQcEoWAICAaA5HPNLoUAADs=");
+}
+.annotationHTML.matchingSearch {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAALClrLu1ubOpsKqdp6eapKufqMTAw7attLSrsrGnr62jq8C7v765vaebpb22vLmyuMbCxsnGycfEx8G+wcrIysTBxUltof//yf///v70jergpPvws+nWc/npqvrpqvrpq/raffffnvXVkfTVkvXUkd+9f+SiOemvV+uyXa2OX7mYZqeIXKuNX/ClO7KQYqiIXJ59Vp19VpFvTo9uTZBvTpNyUJNyUf///////wAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADgALAAAAAAQABAAAAZ4QJxwSCwajS2aS1U6DlunzcagcuKgG4sn5HJiLZ2QiHbEbj6hEapVTKVYr3OItG5TIhVGLF0npigUEAsPAjV9Q24pEhMBCAoybEUmGRcrDgcAAzNGkxcYNzAJBQSbRJ0YqBc2DaVEHJ6pGTStRBqfGBcZILRWvThBADs=");
+}
+.annotationHTML.currentSearch {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAALClrLu1ubOpsKqdp6eapKufqMTAw7attLSrsrGnr62jq8C7v765vaebpb22vLmyuMbCxsnGycfEx8G+wcrIysTBxUltof//yf///v70jergpPvws+nWc/npqvrpqvrpq/raffffnvXVkfTVkvXUkd+9f+SiOemvV+uyXa2OX7mYZqeIXKuNX/ClO7KQYqiIXJ59Vp19VpFvTo9uTZBvTpNyUJNyUf///////wAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADgALAAAAAAQABAAAAZ4QJxwSCwajS2aS1U6DlunzcagcuKgG4sn5HJiLZ2QiHbEbj6hEapVTKVYr3OItG5TIhVGLF0npigUEAsPAjV9Q24pEhMBCAoybEUmGRcrDgcAAzNGkxcYNzAJBQSbRJ0YqBc2DaVEHJ6pGTStRBqfGBcZILRWvThBADs=");
+}
+.annotationHTML.readOccurrence {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP3ykf3zn/7lIv7kI/fbI/7nRf7scLe0oMXDtfXXHsG4gaKdgOXBF+rIJqKdhaijjNWxHeLBL6GafLuYJpmQcvvdg5OHZpyRcJ+UdLavm4+BXqGWeYZ1TYx7VZ6QcJ2NbI+Ebv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACEALAAAAAAQABAAAAZewJBwSCwaj0KMBFlULphDJwIakh6gGckCcXgyLxjuYol0PA6YMQbZqFAOhw/Gc2wHABaJhAMy2gEGBRoSHRtFf4ECDRpGERV3iQ0TRwyQBQSSRAmbAwEMnxAQClRQQQA7");
+}
+.annotationHTML.writeOccurrence {
+       
+       background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP3ykf3zn/7lIv7kI/fbI/7nRf7scLe0oMXDtfXXHsG4gaKdgOXBF+rIJqKdhaijjNWxHeLBL6GafLuYJpmQcvvdg5OHZpyRcJ+UdLavm4+BXqGWeYZ1TYx7VZ6QcJ2NbI+Ebv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACEALAAAAAAQABAAAAZewJBwSCwaj0KMBFlULphDJwIakh6gGckCcXgyLxjuYol0PA6YMQbZqFAOhw/Gc2wHABaJhAMy2gEGBRoSHRtFf4ECDRpGERV3iQ0TRwyQBQSSRAmbAwEMnxAQClRQQQA7");
+}
+.annotationHTML.blame {
+       float: left;
+}
+.annotationHTML.currentBlame {
+       float: left;
+}
+.annotationHTML.blame.single {
+       width: 32px;
+       height: 32px;
+}
+.annotationHTML.currentBlame.single {
+       width: 32px;
+       height: 32px;
+}
+.annotationOverview {
+       cursor: pointer;
+       border-radius: 2px;
+       left: 2px;
+       width: 8px;
+}
+.annotationOverview.task {
+       background-color: #93bb7a;
+       border: 1px solid #79aa59;
+}
+.annotationOverview.breakpoint {
+       background-color: lightblue;
+       border: 1px solid blue;
+}
+.annotationOverview.bookmark {
+       background-color: #84b3cf;
+       border: 1px solid #9cc2d8;
+}
+.annotationOverview.error {
+       background-color: #EFA1A7;
+       border: 1px solid #ec8a91;
+}
+.annotationOverview.warning {
+       background-color: #fce1a9;
+       border: 1px solid #face70;
+}
+.annotationOverview.currentBracket {
+       background-color: lightgray;
+       border: 1px solid red;
+}
+.annotationOverview.matchingBracket {
+       background-color: #ff7f7f;
+       border: 1px solid #ff3232;
+}
+.annotationOverview.currentLine {
+       background-color: #f8a852;
+       border: 1px solid #f79327;
+}
+.annotationOverview.matchingSearch {
+background-color: #C3E1FF;
+border: 1px solid #afcae5;
+}
+.annotationOverview.currentSearch {
+       background-color: #53D1FF;
+       border: 1px solid #42a7cc;
+}
+.annotationOverview.readOccurrence {
+       background-color: lightgray;
+       border: 1px solid black;
+}
+.annotationOverview.writeOccurrence {
+       background-color: Gold;
+       border: 1px solid darkred;
+}
+.annotationOverview.currentBlame {
+       background-color: rgb(184, 103, 163);
+       border: 1px solid black;
+}
+.annotationRange {
+       background-repeat: repeat-x;
+       background-position: left bottom;
+}
+.annotationRange.task {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sLDhEoIrb7JmcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAGUlEQVQI12NggIH/DGdhDCM45z/DfyiBAADgdQjGhI/4DAAAAABJRU5ErkJggg==");
+}
+.annotationRange.breakpoint {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sLDhEqHTKradgAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAIklEQVQI11XJMQ0AMAzAMGMafwrFlD19+sUKIJTFo9k+B/kQ+Qr2bIVKOgAAAABJRU5ErkJggg==");
+}
+.annotationRange.bookmark {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
+}
+.annotationRange.error {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
+}
+.annotationRange.warning {
+       
+       background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
+}
+.annotationRange.currentBracket {
+}
+.annotationRange.matchingBracket {
+       outline: 1px solid red;
+}
+.annotationRange.readOccurrence {
+       background-color: lightgray;
+}
+.annotationRange.writeOccurrence {
+       background-color: yellow;
+}
+.annotationRange.matchingSearch {
+       background-color: #C3E1FF;
+}
+.annotationRange.currentSearch {
+       background-color: #53D1FF;
+}
+.annotationRange.linkedGroup {
+       outline: 1px solid grey;
+}
+.annotationRange.currentLinkedGroup {
+       background-color: #C3E1FF;
+}
+.annotationRange.selectedLinkedGroup {
+       background-color: #53D1FF;
+}
+.annotationLine {
+}
+.annotationLine.currentLine {
+       background-color: #EAF2FE;
+}
diff --git a/dgbuilder/public/orion/built-editor.min.js b/dgbuilder/public/orion/built-editor.min.js
new file mode 100644 (file)
index 0000000..b7d1209
--- /dev/null
@@ -0,0 +1,1081 @@
+/*
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2010, 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+ Mihai Sucan (Mozilla Foundation) - fix for Bug#334583 Bug#348471 Bug#349485 Bug#350595 Bug#360726 Bug#361180 Bug#362835 Bug#362428 Bug#362286 Bug#354270 Bug#361474 Bug#363945 Bug#366312 Bug#370584
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: 
+ Felipe Heidrich (IBM Corporation) - initial API and implementation
+ Silenio Quarti (IBM Corporation) - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2009, 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made
+ available under the terms of the Eclipse Public License v1.0
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2010, 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2014 IBM Corporation and others.
+ Copyright (c) 2012 VMware, Inc.
+ All rights reserved. This program and the accompanying materials are made
+ available under the terms of the Eclipse Public License v1.0
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+ Andrew Eisenberg - rename to jsTemplateContentAssist.js
+
+ Copyright (c) 2011, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation 
+
+ Copyright (c) 2011, 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+
+ Copyright (c) 2011, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation 
+
+ Copyright (c) 2011, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation 
+
+ Copyright (c) 2010, 2012 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made
+ available under the terms of the Eclipse Public License v1.0
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+
+ Contributors: IBM Corporation - initial API and implementation
+ Alex Lakatos - fix for bug#369781
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made
+ available under the terms of the Eclipse Public License v1.0
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2014 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors: IBM Corporation - initial API and implementation
+
+ Copyright (c) 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+ RequireJS i18n 2.0.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
+ Available via the MIT or new BSD license.
+ see: http://github.com/requirejs/i18n for details
+
+ Copyright (c) 2011, 2013 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials are made 
+ available under the terms of the Eclipse Public License v1.0 
+ (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+*/
+var requirejs,require,define;
+(function(k){function m(a,b){var e,j,w,x,f,l,c,d,o,g=b&&b.split("/"),h=q.map,p=h&&h["*"]||{};if(a&&a.charAt(0)===".")if(b){g=g.slice(0,g.length-1);a=g.concat(a.split("/"));for(d=0;d<a.length;d+=1)if(e=a[d],e===".")a.splice(d,1),d-=1;else if(e==="..")if(d===1&&(a[2]===".."||a[0]===".."))break;else d>0&&(a.splice(d-1,2),d-=2);a=a.join("/")}else a.indexOf("./")===0&&(a=a.substring(2));if((g||p)&&h){e=a.split("/");for(d=e.length;d>0;d-=1){j=e.slice(0,d).join("/");if(g)for(o=g.length;o>0;o-=1)if(w=h[g.slice(0,
+o).join("/")])if(w=w[j]){x=w;f=d;break}if(x)break;!l&&p&&p[j]&&(l=p[j],c=d)}!x&&l&&(x=l,f=c);x&&(e.splice(0,f,x),a=e.join("/"))}return a}function n(a,e){return function(){return b.apply(k,t.call(arguments,0).concat([a,e]))}}function i(a){return function(b){return m(b,a)}}function c(a){return function(b){l[a]=b}}function d(a){if(p.call(o,a)){var b=o[a];delete o[a];r[a]=!0;h.apply(k,b)}if(!p.call(l,a)&&!p.call(r,a))throw Error("No "+a);return l[a]}function f(a){var b,e=a?a.indexOf("!"):-1;e>-1&&(b=
+a.substring(0,e),a=a.substring(e+1,a.length));return[b,a]}function g(a){return function(){return q&&q.config&&q.config[a]||{}}}var h,b,a,e,l={},o={},q={},r={},p=Object.prototype.hasOwnProperty,t=[].slice;a=function(a,b){var e,j=f(a),w=j[0],a=j[1];w&&(w=m(w,b),e=d(w));w?a=e&&e.normalize?e.normalize(a,i(b)):m(a,b):(a=m(a,b),j=f(a),w=j[0],a=j[1],w&&(e=d(w)));return{f:w?w+"!"+a:a,n:a,pr:w,p:e}};e={require:function(a){return n(a)},exports:function(a){var b=l[a];return typeof b!=="undefined"?b:l[a]={}},
+module:function(a){return{id:a,uri:"",exports:l[a],config:g(a)}}};h=function(b,f,g,j){var w,x,D,y,h=[],q,j=j||b;if(typeof g==="function"){f=!f.length&&g.length?["require","exports","module"]:f;for(y=0;y<f.length;y+=1)if(D=a(f[y],j),x=D.f,x==="require")h[y]=e.require(b);else if(x==="exports")h[y]=e.exports(b),q=!0;else if(x==="module")w=h[y]=e.module(b);else if(p.call(l,x)||p.call(o,x)||p.call(r,x))h[y]=d(x);else if(D.p)D.p.load(D.n,n(j,!0),c(x),{}),h[y]=l[x];else throw Error(b+" missing "+x);f=g.apply(l[b],
+h);if(b)if(w&&w.exports!==k&&w.exports!==l[b])l[b]=w.exports;else if(f!==k||!q)l[b]=f}else b&&(l[b]=g)};requirejs=require=b=function(f,l,c,j,w){if(typeof f==="string")return e[f]?e[f](l):d(a(f,l).f);else f.splice||(q=f,l.splice?(f=l,l=c,c=null):f=k);l=l||function(){};typeof c==="function"&&(c=j,j=w);j?h(k,f,l,c):setTimeout(function(){h(k,f,l,c)},4);return b};b.config=function(a){q=a;return b};define=function(a,b,e){b.splice||(e=b,b=[]);!p.call(l,a)&&!p.call(o,a)&&(o[a]=[a,b,e])};define.amd={jQuery:!0}})();
+define("almond",function(){});
+define("orion/editor/shim",[],function(){if(!Object.create)Object.create=function(k,m){function n(){}n.prototype=k;var i=new n;if(m)for(var c in m)m.hasOwnProperty(c)&&(i[c]=m[c].hasOwnProperty("value")?m[c].value:function(){if(arguments.length>0)return m[c].get();else m[c].set(arguments)});return i};if(!Object.keys)Object.keys=function(k){var m=[],n;for(n in k)k.hasOwnProperty(n)&&m.push(n);return m};if(!Function.prototype.bind)Function.prototype.bind=function(k){var m=this,n=Array.prototype.slice.call(arguments,
+1);return n.length?function(){return arguments.length?m.apply(k,n.concat(Array.prototype.slice.call(arguments))):m.apply(k,n)}:function(){return arguments.length?m.apply(k,arguments):m.call(k)}};if(!Array.isArray)Array.isArray=function(k){return Object.prototype.toString.call(k)==="[object Array]"};if(!Array.prototype.indexOf)Array.prototype.indexOf=function(k){for(var m=0;m<this.length;m++)if(this[m]===k)return m;return-1};if(!Array.prototype.forEach)Array.prototype.forEach=function(k){for(var m=
+0;m<this.length;m++)k(this[m],m)};if(!Array.prototype.map)Array.prototype.map=function(k){for(var m=Array(this.length),n=0;n<this.length;n++)m[n]=k(this[n]);return m};if(!Array.prototype.reduce)Array.prototype.reduce=function(k,m){var n,i=!1;1<arguments.length&&(n=m,i=!0);for(var c=0;this.length>c;++c)i?n=k(n,this[c],c,this):(n=this[c],i=!0);return n};if(!String.prototype.trim)String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")};if(!String.prototype.trimLeft)String.prototype.trimLeft=
+function(){return this.replace(/^\s+/g,"")};if(!String.prototype.trimRight)String.prototype.trimRight=function(){return this.replace(/\s+$/g,"")};return{}});
+(function(){function k(c,d,f,g,h,b){d[c]&&(f.push(c),(d[c]===!0||d[c]===1)&&g.push(h+c+"/"+b))}function m(c,d,f,g,h){d=g+d+"/"+h;require._fileExists(c.toUrl(d+".js"))&&f.push(d)}function n(c,d,f){for(var g in d)d.hasOwnProperty(g)&&(!c.hasOwnProperty(g)||f)?c[g]=d[g]:typeof d[g]==="object"&&n(c[g],d[g],f)}var i=/(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/;define("i18n",["module"],function(c){var d=c.config?c.config():{};return{version:"2.0.1+",load:function(f,c,h,b){b=b||{};if(b.locale)d.locale=b.locale;
+var a=i.exec(f),e=a[1],l=a[4],o=a[5],q=l.split("-"),r=[],p={},t,v="";if(a[5])e=a[1],f=e+o;else{o=a[4];l=d.locale;if(!l)l=d.locale=typeof navigator==="undefined"?"root":(navigator.language||navigator.userLanguage||"root").toLowerCase();q=l.split("-")}if(b.isBuild){r.push(f);m(c,"root",r,e,o);for(t=0;t<q.length;t++)b=q[t],v+=(v?"-":"")+b,m(c,v,r,e,o);c(r,function(){h()})}else c([f],function(a){var b=[],j;k("root",a,b,r,e,o);for(t=0;t<q.length;t++)j=q[t],v+=(v?"-":"")+j,k(v,a,b,r,e,o);c(r,function(){var j,
+x,f;for(j=b.length-1;j>-1&&b[j];j--){f=b[j];x=a[f];if(x===!0||x===1)x=c(e+f+"/"+o);n(p,x)}h(p)})})}}})})();define("orion/editor/i18n",{load:function(k,m,n){m.specified&&m.specified("orion/bootstrap")?m(["orion/i18n!"+k],function(i){n(i)}):n({})}});
+define("orion/editor/nls/root/messages",{multipleAnnotations:"Multiple annotations:",line:"Line: ${0}",breakpoint:"Breakpoint",bookmark:"Bookmark",task:"Task",error:"Error",warning:"Warning",matchingSearch:"Matching Search",currentSearch:"Current Search",currentLine:"Current Line",matchingBracket:"Matching Bracket",currentBracket:"Current Bracket",lineUp:"Line Up",lineDown:"Line Down",lineStart:"Line Start",lineEnd:"Line End",charPrevious:"Previous Character",charNext:"Next Character",pageUp:"Page Up",
+pageDown:"Page Down",scrollPageUp:"Scroll Page Up",scrollPageDown:"Scroll Page Down",scrollLineUp:"Scroll Line Up",scrollLineDown:"Scroll Line Down",wordPrevious:"Previous Word",wordNext:"Next Word",textStart:"Document Start",textEnd:"Document End",scrollTextStart:"Scroll Document Start",scrollTextEnd:"Scroll Document End",centerLine:"Center Line",selectLineUp:"Select Line Up",selectLineDown:"Select Line Down",selectWholeLineUp:" Select Whole Line Up",selectWholeLineDown:"Select Whole Line Down",
+selectLineStart:"Select Line Start",selectLineEnd:"Select Line End",selectCharPrevious:"Select Previous Character",selectCharNext:"Select Next Character",selectPageUp:"Select Page Up",selectPageDown:"Select Page Down",selectWordPrevious:"Select Previous Word",selectWordNext:"Select Next Word",selectTextStart:"Select Document Start",selectTextEnd:"Select Document End",deletePrevious:"Delete Previous Character",deleteNext:"Delete Next Character",deleteWordPrevious:"Delete Previous Word",deleteWordNext:"Delete Next Word",
+deleteLineStart:"Delete Line Start",deleteLineEnd:"Delete Line End",tab:"Insert Tab",enter:"Insert Line Delimiter",enterNoCursor:"Insert Line Delimiter",selectAll:"Select All",copy:"Copy",cut:"Cut",paste:"Paste",uppercase:"To Upper Case",lowercase:"To Lower Case",capitalize:"Capitalize",reversecase:"Reverse Case",toggleWrapMode:"Toggle Wrap Mode",toggleTabMode:"Toggle Tab Mode",toggleOverwriteMode:"Toggle Overwrite Mode",committerOnTime:"${0} on ${1}",emacs:"Emacs",exchangeMarkPoint:"Exchange Mark and Point",
+setMarkCommand:"Set Mark",clearMark:"Clear Mark",digitArgument:"Digit Argument ${0}",negativeArgument:"Negative Argument",Comment:"Comment","Flat outline":"Flat outline",incrementalFindStr:"Incremental find: ${0}",incrementalFindStrNotFound:"Incremental find: ${0} (not found)",incrementalFindReverseStr:"Reverse Incremental find: ${0}",incrementalFindReverseStrNotFound:"Reverse Incremental find: ${0} (not found)",find:"Find...",undo:"Undo",redo:"Redo",cancelMode:"Cancel Current Mode",findNext:"Find Next Occurrence",
+findPrevious:"Find Previous Occurrence",incrementalFind:"Incremental Find",incrementalFindReverse:"Incremental Find Reverse",indentLines:"Indent Lines",unindentLines:"Unindent Lines",moveLinesUp:"Move Lines Up",moveLinesDown:"Move Lines Down",copyLinesUp:"Copy Lines Up",copyLinesDown:"Copy Lines Down",deleteLines:"Delete Lines",gotoLine:"Goto Line...",gotoLinePrompty:"Goto Line:",nextAnnotation:"Next Annotation",prevAnnotation:"Previous Annotation",expand:"Expand",collapse:"Collapse",expandAll:"Expand All",
+collapseAll:"Collapse All",lastEdit:"Last Edit Location",trimTrailingWhitespaces:"Trim Trailing Whitespaces",toggleLineComment:"Toggle Line Comment",addBlockComment:"Add Block Comment",removeBlockComment:"Remove Block Comment",linkedModeEntered:"Linked Mode entered",linkedModeExited:"Linked Mode exited",syntaxError:"Syntax Error",contentAssist:"Content Assist",lineColumn:"Line ${0} : Col ${1}",vi:"vi",vimove:"(Move)",viyank:"(Yank)",videlete:"(Delete)",vichange:"(Change)",viLeft:"${0} Left",viRight:"${0} Right",
+viUp:"${0} Up",viDown:"${0} Down",viw:"${0} Next Word",vib:"${0} Beginning of Word",viW:"${0} Next Word (ws stop)",viB:"${0} Beginning of Word (ws stop)",vie:"${0} End of Word",viE:"${0} End of Word (ws stop)",vi$:"${0} End of the line","vi^_":"${0} First non-blank Char Current Line","vi+":"${0} First Char Next Line","vi-":"${0} First Char Previous Line","vi|":"${0} nth Column in Line",viH:"${0} Top of Page",viM:"${0} Middle of Page",viL:"${0} Bottom of Page","vi/":"${0} Search Forward","vi?":"${0} Search Backward",
+vin:"${0} Next Search",viN:"${0} Previous Search",vif:"${0} Search Char Fwd",viF:"${0} Search Char Bckwd",vit:"${0} Search Before Char Fwd",viT:"${0} Search Before Char Bckwd","vi,":"${0} Repeat Reverse Char Search","vi;":"${0} Repeat Char Search",viG:"${0} Go to Line",viycd:"${0} Current Line",via:"Append After Cursor",viA:"Append to End of Line",vii:"Insert Before Cursor",viI:"Insert at Beginning of Line",viO:"Insert Line Above",vio:"Insert Line Below",viR:"Begin Overwriting Text",vis:"Substitute a Character",
+viS:"Substitute Entire Line",viC:"Change Text Until Line End",vip:"Paste After Char or Line",viP:"Paste Before Char or Line",viStar:"Search Word Under Cursor",replaceAll:"Replacing all...",replacedMatches:"Replaced ${0} matches",nothingReplaced:"Nothing replaced",notFound:"Not found"});
+define("orion/editor/nls/messages",["orion/editor/i18n!orion/editor/nls/messages","orion/editor/nls/root/messages"],function(k,m){var n={root:m},i;for(i in k)k.hasOwnProperty(i)&&typeof n[i]==="undefined"&&(n[i]=k[i]);return n});
+define("orion/editor/eventTarget",[],function(){function k(){}k.addMixin=function(m){var n=k.prototype,i;for(i in n)n.hasOwnProperty(i)&&(m[i]=n[i])};k.prototype={addEventListener:function(k,n,i){if(!this._eventTypes)this._eventTypes={};var c=this._eventTypes[k];c||(c=this._eventTypes[k]={level:0,listeners:[]});c.listeners.push({listener:n,useCapture:i})},dispatchEvent:function(k){var n=k.type;this._dispatchEvent("pre"+n,k);this._dispatchEvent(n,k);this._dispatchEvent("post"+n,k)},_dispatchEvent:function(k,
+n){var i=this._eventTypes?this._eventTypes[k]:null;if(i){var c=i.listeners;try{if(i.level++,c)for(var d=0,f=c.length;d<f;d++)if(c[d]){var g=c[d].listener;typeof g==="function"?g.call(this,n):g.handleEvent&&typeof g.handleEvent==="function"&&g.handleEvent(n)}}finally{if(i.level--,i.compact&&i.level===0){for(d=c.length-1;d>=0;d--)c[d]||c.splice(d,1);c.length===0&&delete this._eventTypes[k];i.compact=!1}}}},isListening:function(k){return!this._eventTypes?!1:this._eventTypes[k]!==void 0},removeEventListener:function(k,
+n,i){if(this._eventTypes){var c=this._eventTypes[k];if(c){for(var d=c.listeners,f=0,g=d.length;f<g;f++){var h=d[f];if(h&&h.listener===n&&h.useCapture===i){c.level!==0?(d[f]=null,c.compact=!0):d.splice(f,1);break}}d.length===0&&delete this._eventTypes[k]}}}};return{EventTarget:k}});define("orion/regex",[],function(){return{escape:function(k){return k.replace(/([\\$\^*\/+?\.\(\)|{}\[\]])/g,"\\$&")},parse:function(k){return(k=/^\s*\/(.+)\/([gim]{0,3})\s*$/.exec(k))?{pattern:k[1],flags:k[2]}:null}}});
+define("orion/util",[],function(){var k=navigator.userAgent,m=k.indexOf("MSIE")!==-1||k.indexOf("Trident")!==-1?document.documentMode:void 0,n=parseFloat(k.split("Firefox/")[1]||k.split("Minefield/")[1])||void 0,i=k.indexOf("Opera")!==-1?parseFloat(k.split("Version/")[1]):void 0,c=parseFloat(k.split("Chrome/")[1])||void 0,d=k.indexOf("Safari")!==-1&&!c,f=parseFloat(k.split("WebKit/")[1])||void 0,g=k.indexOf("Android")!==-1,h=k.indexOf("iPad")!==-1,k=k.indexOf("iPhone")!==-1,b=h||k,a=navigator.platform.indexOf("Mac")!==
+-1,e=navigator.platform.indexOf("Win")!==-1,l=navigator.platform.indexOf("Linux")!==-1;return{formatMessage:function(a){var b=arguments;return a.replace(/\$\{([^\}]+)\}/g,function(a,e){return b[(e<<0)+1]})},createElement:function(a,b){return a.createElementNS?a.createElementNS("http://www.w3.org/1999/xhtml",b):a.createElement(b)},isIE:m,isFirefox:n,isOpera:i,isChrome:c,isSafari:d,isWebkit:f,isAndroid:g,isIPad:h,isIPhone:k,isIOS:b,isMac:a,isWindows:e,isLinux:l,platformDelimiter:e?"\r\n":"\n"}});
+define("orion/editor/textModel",["orion/editor/eventTarget","orion/regex","orion/util"],function(k,m,n){function i(c,d){this._lastLineIndex=-1;this._text=[""];this._lineOffsets=[0];this.setText(c);this.setLineDelimiter(d)}i.prototype={destroy:function(){},find:function(c){if(this._text.length>1)this._text=[this._text.join("")];var d=c.string,f=c.regex,g=d,h="",b=c.caseInsensitive;if(g)if(f){if(d=m.parse(g))g=d.pattern,h=d.flags}else g=d.replace(/([\\$\^*\/+?\.\(\)|{}\[\]])/g,"\\$&"),b&&(g=g.replace(/[iI\u0130\u0131]/g,
+"[Ii\u0130\u0131]"));var a=null,e;if(g){var d=c.reverse,l=c.wrap,f=c.wholeWord,o=c.start||0,c=c.end,q=c!==null&&c!==void 0;h.indexOf("g")===-1&&(h+="g");h.indexOf("m")===-1&&(h+="m");b&&h.indexOf("i")===-1&&(h+="i");f&&(g="\\b"+g+"\\b");var i=this._text[0],p,t,v=0;q&&(b=o<c?o:c,i=i.substring(b,o<c?c:o),v=b);var s=RegExp(g,h);if(d)e=function(){var a=null;for(s.lastIndex=0;;){t=s.lastIndex;p=s.exec(i);if(t===s.lastIndex)return null;if(p){if(!(p.index+v<o)){if(!l||a)break;o=i.length+v}a={start:p.index+
+v,end:s.lastIndex+v}}else break}if(a)o=a.start;return a};else{if(!q)s.lastIndex=o;e=function(){for(;;){t=s.lastIndex;p=s.exec(i);if(t===s.lastIndex)break;if(p)return{start:p.index+v,end:s.lastIndex+v};if(!(t!==0&&l))break}return null}}a=e()}return{next:function(){var b=a;b&&(a=e());return b},hasNext:function(){return a!==null}}},getCharCount:function(){for(var c=0,d=0;d<this._text.length;d++)c+=this._text[d].length;return c},getLine:function(c,d){var f=this.getLineCount();if(!(0<=c&&c<f))return null;
+var g=this._lineOffsets[c];if(c+1<f){f=this.getText(g,this._lineOffsets[c+1]);if(d)return f;for(var g=f.length,h;(h=f.charCodeAt(g-1))===10||h===13;)g--;return f.substring(0,g)}else return this.getText(g)},getLineAtOffset:function(c){var d=this.getCharCount();if(!(0<=c&&c<=d))return-1;var f=this.getLineCount();if(c===d)return f-1;var g,h,b=this._lastLineIndex;if(0<=b&&b<f&&(g=this._lineOffsets[b],h=b+1<f?this._lineOffsets[b+1]:d,g<=c&&c<h))return b;for(var a=f,e=-1;a-e>1;)if(b=Math.floor((a+e)/2),
+g=this._lineOffsets[b],h=b+1<f?this._lineOffsets[b+1]:d,c<=g)a=b;else if(c<h){a=b;break}else e=b;return this._lastLineIndex=a},getLineCount:function(){return this._lineOffsets.length},getLineDelimiter:function(){return this._lineDelimiter},getLineEnd:function(c,d){var f=this.getLineCount();if(!(0<=c&&c<f))return-1;if(c+1<f){f=this._lineOffsets[c+1];if(d)return f;for(var g=this.getText(Math.max(this._lineOffsets[c],f-2),f),h=g.length,b;(b=g.charCodeAt(h-1))===10||b===13;)h--;return f-(g.length-h)}else return this.getCharCount()},
+getLineStart:function(c){return!(0<=c&&c<this.getLineCount())?-1:this._lineOffsets[c]},getText:function(c,d){c===void 0&&(c=0);d===void 0&&(d=this.getCharCount());if(c===d)return"";for(var f=0,g=0,h;g<this._text.length;){h=this._text[g].length;if(c<=f+h)break;f+=h;g++}for(var b=f,a=g;g<this._text.length;){h=this._text[g].length;if(d<=f+h)break;f+=h;g++}if(a===g)return this._text[a].substring(c-b,d-f);b=this._text[a].substring(c-b);f=this._text[g].substring(0,d-f);return b+this._text.slice(a+1,g).join("")+
+f},onChanging:function(c){return this.dispatchEvent(c)},onChanged:function(c){return this.dispatchEvent(c)},setLineDelimiter:function(c,d){c==="auto"&&(c=void 0,this.getLineCount()>1&&(c=this.getText(this.getLineEnd(0),this.getLineEnd(0,!0))));this._lineDelimiter=c?c:n.platformDelimiter;if(d){var f=this.getLineCount();if(f>1){for(var g=Array(f),h=0;h<f;h++)g[h]=this.getLine(h);this.setText(g.join(this._lineDelimiter))}}},setText:function(c,d,f){c===void 0&&(c="");d===void 0&&(d=0);f===void 0&&(f=
+this.getCharCount());if(!(d===f&&c==="")){for(var g=this.getLineAtOffset(d),h=this.getLineAtOffset(f),b=d,a=f-d,e=h-g,l=c.length,o=0,i=this.getLineCount(),r=0,p=0,t=0,v=[];;){r!==-1&&r<=t&&(r=c.indexOf("\r",t));p!==-1&&p<=t&&(p=c.indexOf("\n",t));if(p===-1&&r===-1)break;t=r!==-1&&p!==-1?r+1===p?p+1:(r<p?r:p)+1:r!==-1?r+1:p+1;v.push(d+t);o++}this.onChanging({type:"Changing",text:c,start:b,removedCharCount:a,addedCharCount:l,removedLineCount:e,addedLineCount:o});v.length===0&&(t=this.getLineStart(g),
+h=h+1<i?this.getLineStart(h+1):this.getCharCount(),d!==t&&(c=this.getText(t,d)+c,d=t),f!==h&&(c+=this.getText(f,h),f=h));t=l-a;for(h=g+e+1;h<i;h++)this._lineOffsets[h]+=t;if(v.length<5E4)g=[g+1,e].concat(v),Array.prototype.splice.apply(this._lineOffsets,g);else{t=g+1;this._lineOffsets.splice(t,e);for(i=0;i<v.length;i+=5E4)g=[t,0].concat(v.slice(i,Math.min(v.length,i+5E4))),Array.prototype.splice.apply(this._lineOffsets,g),t+=5E4}for(t=i=0;t<this._text.length;){h=this._text[t].length;if(d<=i+h)break;
+i+=h;t++}g=i;for(v=t;t<this._text.length;){h=this._text[t].length;if(f<=i+h)break;i+=h;t++}h=this._text[t];d=this._text[v].substring(0,d-g);f=h.substring(f-i);v=[v,t-v+1];d&&v.push(d);c&&v.push(c);f&&v.push(f);Array.prototype.splice.apply(this._text,v);if(this._text.length===0)this._text=[""];this.onChanged({type:"Changed",start:b,removedCharCount:a,addedCharCount:l,removedLineCount:e,addedLineCount:o})}}};k.EventTarget.addMixin(i.prototype);return{TextModel:i}});
+define("orion/keyBinding",["orion/util"],function(k){function m(i,c,d,f,g,h){this.type=h||"keydown";this.keyCode=typeof i==="string"&&this.type==="keydown"?i.toUpperCase().charCodeAt(0):i;this.mod1=c!==void 0&&c!==null?c:!1;this.mod2=d!==void 0&&d!==null?d:!1;this.mod3=f!==void 0&&f!==null?f:!1;this.mod4=g!==void 0&&g!==null?g:!1}function n(i){this.keys=i}m.prototype={getKeys:function(){return[this]},match:function(i,c){if(c!==void 0){if(c!==0)return!1}else if(i instanceof Array){if(i.length>1)return!1;
+i=i[0]}return i.type!==this.type?!1:this.keyCode===i.keyCode||this.keyCode===String.fromCharCode(k.isOpera?i.which:i.charCode!==void 0?i.charCode:i.keyCode)?this.mod1!==(k.isMac?i.metaKey:i.ctrlKey)?!1:this.type==="keydown"&&this.mod2!==i.shiftKey?!1:this.mod3!==i.altKey?!1:k.isMac&&this.mod4!==i.ctrlKey?!1:!0:!1},equals:function(i){return!i?!1:this.keyCode!==i.keyCode?!1:this.mod1!==i.mod1?!1:this.mod2!==i.mod2?!1:this.mod3!==i.mod3?!1:this.mod4!==i.mod4?!1:this.type!==i.type?!1:!0}};n.prototype=
+{getKeys:function(){return this.keys.slice(0)},match:function(i,c){var d=this.keys;if(c!==void 0)return c>d.length?!1:d[c].match(i)?c===d.length-1?!0:c+1:!1;else{i instanceof Array||(i=[i]);if(i.length>d.length)return!1;var f;for(f=0;f<i.length;f++)if(!d[f].match(i[f]))return!1;return f===d.length?!0:f}},equals:function(i){if(!i.keys)return!1;if(i.keys.length!==this.keys.length)return!1;for(var c=0;c<i.keys.length;c++)if(!i.keys[c].equals(this.keys[c]))return!1;return!0}};return{KeyBinding:m,KeyStroke:m,
+KeySequence:n}});
+define("orion/editor/keyModes",["orion/keyBinding","orion/util"],function(k,m){function n(c){if(c)this._view=c,this._keyBindings=this.createKeyBindings(),this._keyBindingIndex=0}function i(c){n.call(this,c)}n.prototype={createKeyBindings:function(){return[]},getKeyBindings:function(c){for(var d=[],f=this._keyBindings,g=0;g<f.length;g++)f[g].actionID===c&&d.push(f[g].keyBinding);return d},getView:function(){return this._view},isActive:function(){return this._view.getKeyModes().indexOf(this)!==-1},
+match:function(c){if(c.type==="keydown")switch(c.keyCode){case 16:case 17:case 18:case 91:return}for(var d=this._keyBindingIndex,f=this._matchingKeyBindings||this._keyBindings,g=[],h=0;h<f.length;h++){var b=f[h],a=b.keyBinding.match(c,d);if(a===!0)return this._keyBindingIndex=0,this._matchingKeyBindings=null,b.actionID;else typeof a==="number"&&g.push(b)}if(g.length===0)this._keyBindingIndex=0,this._matchingKeyBindings=null;else return this._keyBindingIndex++,this._matchingKeyBindings=g,"noop"},setKeyBinding:function(c,
+d){for(var f=this._keyBindings,g=0;g<f.length;g++){var h=f[g];if(h.keyBinding.equals(c)){d?h.actionID=d:h.predefined?h.actionID="noop":f.splice(g,1);return}}d&&f.push({keyBinding:c,actionID:d})},setView:function(c){this._view=c}};i.prototype=new n;i.prototype.createKeyBindings=function(){var c=k.KeyBinding,d=[];d.push({actionID:"lineUp",keyBinding:new c(38),predefined:!0});d.push({actionID:"lineDown",keyBinding:new c(40),predefined:!0});d.push({actionID:"charPrevious",keyBinding:new c(37),predefined:!0});
+d.push({actionID:"charNext",keyBinding:new c(39),predefined:!0});m.isMac?(d.push({actionID:"scrollPageUp",keyBinding:new c(33),predefined:!0}),d.push({actionID:"scrollPageDown",keyBinding:new c(34),predefined:!0}),d.push({actionID:"pageUp",keyBinding:new c(33,null,null,!0),predefined:!0}),d.push({actionID:"pageDown",keyBinding:new c(34,null,null,!0),predefined:!0}),d.push({actionID:"lineStart",keyBinding:new c(37,!0),predefined:!0}),d.push({actionID:"lineEnd",keyBinding:new c(39,!0),predefined:!0}),
+d.push({actionID:"wordPrevious",keyBinding:new c(37,null,null,!0),predefined:!0}),d.push({actionID:"wordNext",keyBinding:new c(39,null,null,!0),predefined:!0}),d.push({actionID:"scrollTextStart",keyBinding:new c(36),predefined:!0}),d.push({actionID:"scrollTextEnd",keyBinding:new c(35),predefined:!0}),d.push({actionID:"textStart",keyBinding:new c(38,!0),predefined:!0}),d.push({actionID:"textEnd",keyBinding:new c(40,!0),predefined:!0}),d.push({actionID:"scrollPageUp",keyBinding:new c(38,null,null,null,
+!0),predefined:!0}),d.push({actionID:"scrollPageDown",keyBinding:new c(40,null,null,null,!0),predefined:!0}),d.push({actionID:"lineStart",keyBinding:new c(37,null,null,null,!0),predefined:!0}),d.push({actionID:"lineEnd",keyBinding:new c(39,null,null,null,!0),predefined:!0}),d.push({actionID:"lineStart",keyBinding:new c(38,null,null,!0),predefined:!0}),d.push({actionID:"lineEnd",keyBinding:new c(40,null,null,!0),predefined:!0})):(d.push({actionID:"pageUp",keyBinding:new c(33),predefined:!0}),d.push({actionID:"pageDown",
+keyBinding:new c(34),predefined:!0}),d.push({actionID:"lineStart",keyBinding:new c(36),predefined:!0}),d.push({actionID:"lineEnd",keyBinding:new c(35),predefined:!0}),d.push({actionID:"wordPrevious",keyBinding:new c(37,!0),predefined:!0}),d.push({actionID:"wordNext",keyBinding:new c(39,!0),predefined:!0}),d.push({actionID:"textStart",keyBinding:new c(36,!0),predefined:!0}),d.push({actionID:"textEnd",keyBinding:new c(35,!0),predefined:!0}));m.isFirefox&&m.isLinux&&(d.push({actionID:"lineUp",keyBinding:new c(38,
+!0),predefined:!0}),d.push({actionID:"lineDown",keyBinding:new c(40,!0),predefined:!0}));m.isWindows&&(d.push({actionID:"scrollLineUp",keyBinding:new c(38,!0),predefined:!0}),d.push({actionID:"scrollLineDown",keyBinding:new c(40,!0),predefined:!0}));d.push({actionID:"selectLineUp",keyBinding:new c(38,null,!0),predefined:!0});d.push({actionID:"selectLineDown",keyBinding:new c(40,null,!0),predefined:!0});d.push({actionID:"selectCharPrevious",keyBinding:new c(37,null,!0),predefined:!0});d.push({actionID:"selectCharNext",
+keyBinding:new c(39,null,!0),predefined:!0});d.push({actionID:"selectPageUp",keyBinding:new c(33,null,!0),predefined:!0});d.push({actionID:"selectPageDown",keyBinding:new c(34,null,!0),predefined:!0});m.isMac?(d.push({actionID:"selectLineStart",keyBinding:new c(37,!0,!0),predefined:!0}),d.push({actionID:"selectLineEnd",keyBinding:new c(39,!0,!0),predefined:!0}),d.push({actionID:"selectWordPrevious",keyBinding:new c(37,null,!0,!0),predefined:!0}),d.push({actionID:"selectWordNext",keyBinding:new c(39,
+null,!0,!0),predefined:!0}),d.push({actionID:"selectTextStart",keyBinding:new c(36,null,!0),predefined:!0}),d.push({actionID:"selectTextEnd",keyBinding:new c(35,null,!0),predefined:!0}),d.push({actionID:"selectTextStart",keyBinding:new c(38,!0,!0),predefined:!0}),d.push({actionID:"selectTextEnd",keyBinding:new c(40,!0,!0),predefined:!0}),d.push({actionID:"selectLineStart",keyBinding:new c(37,null,!0,null,!0),predefined:!0}),d.push({actionID:"selectLineEnd",keyBinding:new c(39,null,!0,null,!0),predefined:!0}),
+d.push({actionID:"selectLineStart",keyBinding:new c(38,null,!0,!0),predefined:!0}),d.push({actionID:"selectLineEnd",keyBinding:new c(40,null,!0,!0),predefined:!0})):(m.isLinux&&(d.push({actionID:"selectWholeLineUp",keyBinding:new c(38,!0,!0),predefined:!0}),d.push({actionID:"selectWholeLineDown",keyBinding:new c(40,!0,!0),predefined:!0})),d.push({actionID:"selectLineStart",keyBinding:new c(36,null,!0),predefined:!0}),d.push({actionID:"selectLineEnd",keyBinding:new c(35,null,!0),predefined:!0}),d.push({actionID:"selectWordPrevious",
+keyBinding:new c(37,!0,!0),predefined:!0}),d.push({actionID:"selectWordNext",keyBinding:new c(39,!0,!0),predefined:!0}),d.push({actionID:"selectTextStart",keyBinding:new c(36,!0,!0),predefined:!0}),d.push({actionID:"selectTextEnd",keyBinding:new c(35,!0,!0),predefined:!0}));d.push({actionID:"undo",keyBinding:new k.KeyBinding("z",!0),predefined:!0});m.isMac?d.push({actionID:"redo",keyBinding:new k.KeyBinding("z",!0,!0),predefined:!0}):d.push({actionID:"redo",keyBinding:new k.KeyBinding("y",!0),predefined:!0});
+d.push({actionID:"deletePrevious",keyBinding:new c(8),predefined:!0});d.push({actionID:"deletePrevious",keyBinding:new c(8,null,!0),predefined:!0});d.push({actionID:"deleteNext",keyBinding:new c(46),predefined:!0});d.push({actionID:"deleteWordPrevious",keyBinding:new c(8,!0),predefined:!0});d.push({actionID:"deleteWordPrevious",keyBinding:new c(8,!0,!0),predefined:!0});d.push({actionID:"deleteWordNext",keyBinding:new c(46,!0),predefined:!0});d.push({actionID:"tab",keyBinding:new c(9),predefined:!0});
+d.push({actionID:"shiftTab",keyBinding:new c(9,null,!0),predefined:!0});d.push({actionID:"enter",keyBinding:new c(13),predefined:!0});d.push({actionID:"enter",keyBinding:new c(13,null,!0),predefined:!0});d.push({actionID:"selectAll",keyBinding:new c("a",!0),predefined:!0});d.push({actionID:"toggleTabMode",keyBinding:new c("m",!0),predefined:!0});m.isMac&&(d.push({actionID:"deleteNext",keyBinding:new c(46,null,!0),predefined:!0}),d.push({actionID:"deleteWordPrevious",keyBinding:new c(8,null,null,!0),
+predefined:!0}),d.push({actionID:"deleteWordNext",keyBinding:new c(46,null,null,!0),predefined:!0}));d.push({actionID:"toggleWrapMode",keyBinding:new k.KeyBinding("w",!0,!1,!0)});d.push({actionID:"toggleOverwriteMode",keyBinding:new k.KeyBinding(45)});if(!m.isFirefox){var f=m.isMac&&m.isChrome;d.push({actionID:"noop",keyBinding:new c("u",!f,!1,!1,f),predefined:!0});d.push({actionID:"noop",keyBinding:new c("i",!f,!1,!1,f),predefined:!0});d.push({actionID:"noop",keyBinding:new c("b",!f,!1,!1,f),predefined:!0})}m.isFirefox&&
+(d.push({actionID:"copy",keyBinding:new c(45,!0),predefined:!0}),d.push({actionID:"paste",keyBinding:new c(45,null,!0),predefined:!0}),d.push({actionID:"cut",keyBinding:new c(46,null,!0),predefined:!0}));m.isMac&&(d.push({actionID:"lineStart",keyBinding:new c("a",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"lineEnd",keyBinding:new c("e",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"lineUp",keyBinding:new c("p",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"lineDown",keyBinding:new c("n",!1,!1,
+!1,!0),predefined:!0}),d.push({actionID:"charPrevious",keyBinding:new c("b",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"charNext",keyBinding:new c("f",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"deletePrevious",keyBinding:new c("h",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"deleteNext",keyBinding:new c("d",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"deleteLineEnd",keyBinding:new c("k",!1,!1,!1,!0),predefined:!0}),m.isFirefox?(d.push({actionID:"scrollPageDown",keyBinding:new c("v",!1,
+!1,!1,!0),predefined:!0}),d.push({actionID:"deleteLineStart",keyBinding:new c("u",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"deleteWordPrevious",keyBinding:new c("w",!1,!1,!1,!0),predefined:!0})):(d.push({actionID:"pageDown",keyBinding:new c("v",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"centerLine",keyBinding:new c("l",!1,!1,!1,!0),predefined:!0}),d.push({actionID:"enterNoCursor",keyBinding:new c("o",!1,!1,!1,!0),predefined:!0})));return d};return{KeyMode:n,DefaultKeyMode:i}});
+define("orion/editor/textTheme",["require","orion/editor/eventTarget","orion/util"],function(k,m,n){function i(c){c=c||{};this._document=c.document||document}var c={};i.getTheme=function(d){var d=d||"default",f=c[d];f||(f=c[d]=new i);return f};i.prototype={getThemeClass:function(){return this._themeClass},setThemeClass:function(c,f){var g=this,h=g._themeClass;g._themeClass=c;this._load(c,f,function(){g.onThemeChanged({type:"ThemeChanged",oldValue:h,newValue:g.getThemeClass()})})},onThemeChanged:function(c){return this.dispatchEvent(c)},
+buildStyleSheet:function(c,f){function g(b,a,e){a&&(h.push("."+c+" ."+b+" {"),h.push("\t"+(e?"background-color":"color")+": "+a+";"),h.push("}"))}var h=[];h.push("");h.push("."+c+" {");f.fontFamily&&h.push("\tfont-family: "+f.fontFamily+";");f.fontSize&&h.push("\tfont-size: "+f.fontSize+";");f.fontSize&&h.push("\tcolor: "+f.text+";");h.push("}");h.push("."+c+".textview {");f.background&&h.push("\tbackground-color: "+f.background+";");h.push("}");g("ruler.annotations",f.annotationRuler,!0);g("ruler.lines",
+f.annotationRuler,!0);g("ruler.folding",f.annotationRuler,!0);g("ruler.overview",f.overviewRuler,!0);g("rulerLines",f.lineNumber,!1);g("rulerLines.even",f.lineNumberEven,!1);g("rulerLines.odd",f.lineNumberOdd,!1);g("annotationLine.currentLine",f.currentLine,!0);g("entity-name-tag",f.keyword,!1);g("entity-other-attribute-name",f.attribute,!1);g("string-quoted",f.string,!1);g("meta.annotation.currentLine",f.currentLine,!0);g("keyword",f.keyword,!1);g("string",f.string,!1);g("comment",f.comment,!1);
+g("comment.block.documentation",f.comment,!1);g("keyword.other.documentation.markup",f.comment,!1);return h.join("\n")},_createStyle:function(c,f,g,h){var b=this._document,c="orion-theme-"+c,a=b.getElementById(c);if(a){if(h||a.firstChild.data===f)return;a.removeChild(a.firstChild);a.appendChild(b.createTextNode(f))}else h?(a=n.createElement(b,"link"),a.rel="stylesheet",a.type="text/css",a.href=f,a.addEventListener("load",function(){g()})):(a=n.createElement(b,"style"),a.appendChild(b.createTextNode(f))),
+a.id=c,(b.getElementsByTagName("head")[0]||b.documentElement).appendChild(a);h||g()},_load:function(c,f,g){if(c)if(typeof f==="string")this._createStyle(c,f,g);else if(f=f.href,f.substring(f.length-4)!==".css"&&(f+=".css"),/^\//.test(f)||/[a-zA-Z0-9]+:\/\//i.test(f)||!k.toUrl)this._createStyle(c,f,g,!0);else{var h=this;k(["text!"+f],function(b){h._createStyle(c,b,g,!1)})}else g()}};m.EventTarget.addMixin(i.prototype);return{TextTheme:i}});
+define("orion/editor/util",[],function(){return{contains:function(k,m){if(!m)return!1;if(!k.compareDocumentPosition){for(var n=m;n;){if(k===n)return!0;n=n.parentNode}return!1}return k===m||(k.compareDocumentPosition(m)&16)!==0},addEventListener:function(k,m,n,i){typeof k.addEventListener==="function"?k.addEventListener(m,n,i===!0):k.attachEvent("on"+m,n)},removeEventListener:function(k,m,n,i){typeof k.removeEventListener==="function"?k.removeEventListener(m,n,i===!0):k.detachEvent("on"+m,n)}}});
+define("orion/editor/textView","i18n!orion/editor/nls/messages,orion/editor/textModel,orion/editor/keyModes,orion/editor/eventTarget,orion/editor/textTheme,orion/editor/util,orion/util".split(","),function(k,m,n,i,c,d,f){function g(j,a,b){if(b){a.className="";for(var b=a.attributes,e=b.length;e-- >0;)(!f.isIE||f.isIE>=9||f.isIE<9&&b[e].specified)&&a.removeAttribute(b[e].name)}if(j){if(j.styleClass)a.className=j.styleClass;if(b=j.style)for(var c in b)b.hasOwnProperty(c)&&(a.style[c]=b[c]);if(j=j.attributes)for(var l in j)j.hasOwnProperty(l)&&
+a.setAttribute(l,j[l])}}function h(j){return j instanceof Array?j.slice(0):j}function b(j,a){if(!j)return a;if(!a)return j;for(var b in a)a.hasOwnProperty(b)&&(j.hasOwnProperty(b)||(j[b]=a[b]));return j}function a(j,w){if(j===w)return!0;if(j&&!w||!j&&w)return!1;if(j&&j.constructor===String||w&&w.constructor===String)return!1;if(j instanceof Array||w instanceof Array){if(!(j instanceof Array&&w instanceof Array))return!1;if(j.length!==w.length)return!1;for(var b=0;b<j.length;b++)if(!a(j[b],w[b]))return!1;
+return!0}if(!(j instanceof Object)||!(w instanceof Object))return!1;for(b in j)if(j.hasOwnProperty(b)){if(!w.hasOwnProperty(b))return!1;if(!a(j[b],w[b]))return!1}for(b in w)if(!j.hasOwnProperty(b))return!1;return!0}function e(j,a,b){for(var e=0,c=0,f=0,l=j.length;f<l;){e!==-1&&e<=f&&(e=j.indexOf("\r",f));c!==-1&&c<=f&&(c=j.indexOf("\n",f));var d=f,o;if(c===-1&&e===-1){a(j.substring(f));break}e!==-1&&c!==-1?e+1===c?(o=e,f=c+1):(o=e<c?e:c,f=(e<c?e:c)+1):e!==-1?(o=e,f=e+1):(o=c,f=c+1);a(j.substring(d,
+o));b()}}function l(j){var a,b,e,c,f=j.ownerDocument.defaultView||j.ownerDocument.parentWindow;if(f.getComputedStyle)j=f.getComputedStyle(j,null),a=j.getPropertyValue("padding-left"),b=j.getPropertyValue("padding-top"),e=j.getPropertyValue("padding-right"),c=j.getPropertyValue("padding-bottom");else if(j.currentStyle)a=j.currentStyle.paddingLeft,b=j.currentStyle.paddingTop,e=j.currentStyle.paddingRight,c=j.currentStyle.paddingBottom;return{left:parseInt(a,10)||0,top:parseInt(b,10)||0,right:parseInt(e,
+10)||0,bottom:parseInt(c,10)||0}}function o(j){var a,b,e,c,f=j._trim;if(!f){var f=l(j),d=j.ownerDocument.defaultView||j.ownerDocument.parentWindow;if(d.getComputedStyle)c=d.getComputedStyle(j,null),a=c.getPropertyValue("border-left-width"),b=c.getPropertyValue("border-top-width"),e=c.getPropertyValue("border-right-width"),c=c.getPropertyValue("border-bottom-width");else if(j.currentStyle)a=j.currentStyle.borderLeftWidth,b=j.currentStyle.borderTopWidth,e=j.currentStyle.borderRightWidth,c=j.currentStyle.borderBottomWidth;
+a=parseInt(a,10)||0;b=parseInt(b,10)||0;e=parseInt(e,10)||0;c=parseInt(c,10)||0;f.left+=a;f.top+=b;f.right+=e;f.bottom+=c;j._trim=f}return f}function q(j,a,b){this.start=j;this.end=a;this.caret=b}function r(j){this.left=j.left;this.top=j.top;this.right=j.right;this.bottom=j.bottom}function p(j,a,b){this.view=j;this.lineIndex=a;this._lineDiv=b}function t(j){this._init(j||{})}var v=d.addEventListener,s=d.removeEventListener,u=function(){function j(j){this.options=j}j.prototype.play=function(){var j=
+typeof this.options.duration==="number"?this.options.duration:350,a=this.options.easing||this.defaultEasing,b=this.options.onAnimate||function(){},e=this.options.curve[0],c=this.options.curve[1],f=c-e,l=-1,d,o=this;this.interval=this.options.window.setInterval(function(){l=l===-1?(new Date).getTime():l;var g=((new Date).getTime()-l)/j;g<1?(g=a(g),d=e+g*f,b(d)):(b(c),o.stop())},typeof this.options.rate==="number"?this.options.rate:20)};j.prototype.stop=function(){this.options.window.clearInterval(this.interval);
+(this.options.onEnd||function(){})()};j.prototype.defaultEasing=function(j){return Math.sin(j*(Math.PI/2))};return j}();q.prototype={clone:function(){return new q(this.start,this.end,this.caret)},collapse:function(){this.caret?this.end=this.start:this.start=this.end},extend:function(j){this.caret?this.start=j:this.end=j;if(this.start>this.end)j=this.start,this.start=this.end,this.end=j,this.caret=!this.caret},setCaret:function(j){this.end=this.start=j;this.caret=!1},getCaret:function(){return this.caret?
+this.start:this.end},toString:function(){return"start="+this.start+" end="+this.end+(this.caret?" caret is at start":" caret is at end")},isEmpty:function(){return this.start===this.end},equals:function(j){return this.caret===j.caret&&this.start===j.start&&this.end===j.end}};r.prototype={toString:function(){return"{l="+this.left+", t="+this.top+", r="+this.right+", b="+this.bottom+"}"}};p.prototype={create:function(j,a){if(!this._lineDiv){var b=this._lineDiv=this._createLine(j,a,this.lineIndex);b._line=
+this;return b}},_createLine:function(j,w,b){var e=this.view,c=e._model,l=c.getLine(b),d=c.getLineStart(b),o={type:"LineStyle",textView:e,lineIndex:b,lineText:l,lineStart:d};if(l.length<2E3)e.onLineStyle(o);c=w||f.createElement(j.ownerDocument,"div");if(!w||!a(w.viewStyle,o.style)){g(o.style,c,w);if(w)w._trim=null;c.viewStyle=o.style;c.setAttribute("role","presentation")}c.lineIndex=b;b=[];this._createRanges(o.ranges,l,0,l.length,d,{tabOffset:0,ranges:b});l=" ";!e._fullSelection&&f.isIE<9&&(l="\ufeff");
+o={text:l,style:e._metrics.largestFontStyle,ignoreChars:1};b.length===0||!b[b.length-1].style||b[b.length-1].style.tagName!=="div"?b.push(o):b.splice(b.length-1,0,o);var h,p,i,q,r,l=e=0,s,t;if(w){if(p=w.modelChangedEvent)p.removedLineCount===0&&p.addedLineCount===0?(t=p.start-d,s=p.addedCharCount-p.removedCharCount):t=-1,w.modelChangedEvent=void 0;p=w.firstChild}for(d=0;d<b.length;d++){o=b[d];q=o.text;e+=q.length;h=o.style;if(p)if(r=p.firstChild.data,i=p.viewStyle,r===q&&a(h,i)){l+=r.length;p._rectsCache=
+void 0;h=p=p.nextSibling;continue}else for(;p;){if(t!==-1){i=e;i>=t&&(i-=s);r=(r=p.firstChild.data)?r.length:0;if(l+r>i)break;l+=r}i=p.nextSibling;c.removeChild(p);p=i}h=this._createSpan(c,q,h,o.ignoreChars);p?c.insertBefore(h,p):c.appendChild(h);if(w)w.lineWidth=void 0}if(w)for(j=h?h.nextSibling:null;j;)i=j.nextSibling,w.removeChild(j),j=i;else j.appendChild(c);return c},_createRanges:function(j,w,b,e,c,f){if(!(b>e)){if(j)for(var l=0;l<j.length;l++){var d=j[l];if(!(d.end<c+b)){var o=Math.max(c+b,
+d.start)-c;if(o>e)break;var g=Math.min(c+e,d.end)-c;if(o<=g){o=Math.max(b,o);g=Math.min(e,g);b<o&&this._createRange(w,b,o,null,f);if(!d.style||!d.style.unmergeable)for(;l+1<j.length&&j[l+1].start-c===g&&a(d.style,j[l+1].style);)d=j[l+1],g=Math.min(c+e,d.end)-c,l++;this._createRange(w,o,g,d.style,f);b=g}}}b<e&&this._createRange(w,b,e,null,f)}},_createRange:function(j,a,b,e,c){if(!(a>b)){var f=this.view._customTabSize;if(f&&f!==8)for(var l=j.indexOf("\t",a);l!==-1&&l<b;){a<l&&(a={text:j.substring(a,
+l),style:e},c.ranges.push(a),c.tabOffset+=a.text.length);a=f-c.tabOffset%f;if(a>0){for(var d="\u00a0",o=1;o<a;o++)d+=" ";a={text:d,style:e,ignoreChars:a-1};c.ranges.push(a);c.tabOffset+=a.text.length}a=l+1;if(a===b)return;l=j.indexOf("\t",a)}a<=b&&(a={text:j.substring(a,b),style:e},c.ranges.push(a),c.tabOffset+=a.text.length)}},_createSpan:function(j,a,b,e){var c=this.view,l="span";b&&b.tagName&&(l=b.tagName.toLowerCase());var d=l==="a";if(d)j.hasLink=!0;d&&!c._linksVisible&&(l="span");d=j.ownerDocument;
+j=f.createElement(j.ownerDocument,l);b&&b.html?(j.innerHTML=b.html,j.ignore=!0):b&&b.node?(j.appendChild(b.node),j.ignore=!0):j.appendChild(d.createTextNode(b&&b.text?b.text:a));g(b,j);if(l==="a"){var o=c._getWindow();v(j,"click",function(j){return c._handleLinkClick(j?j:o.event)},!1)}j.viewStyle=b;if(e)j.ignoreChars=e;return j},_ensureCreated:function(){return this._lineDiv?this._lineDiv:this._createdDiv=this.create(this.view._clientDiv,null)},getBoundingClientRect:function(j,a){var b=this._ensureCreated(),
+e=this.view;if(j===void 0)return this._getLineBoundingClientRect(b,!0);var c=e._model,l=b.ownerDocument,d=this.lineIndex,o=null;if(j<c.getLineEnd(d)){d=c.getLineStart(d);for(c=b.firstChild;c;){if(!c.ignore){var g=c.firstChild,p=g.length;c.ignoreChars&&(p-=c.ignoreChars);if(d+p>j){o=j-d;if(g.length===1)o=new r(c.getBoundingClientRect());else if(e._isRangeRects)l=l.createRange(),l.setStart(g,o),l.setEnd(g,o+1),o=new r(l.getBoundingClientRect());else if(f.isIE){if(l=l.body.createTextRange(),l.moveToElementText(c),
+l.collapse(),(d=o===0&&f.isIE===8)&&(o=1),l.moveEnd("character",o+1),l.moveStart("character",o),o=new r(l.getBoundingClientRect()),d)o.left=c.getClientRects()[0].left}else{var h=g.data;c.removeChild(g);c.appendChild(l.createTextNode(h.substring(0,o)));var i=f.createElement(l,"span");i.appendChild(l.createTextNode(h.substring(o,o+1)));c.appendChild(i);c.appendChild(l.createTextNode(h.substring(o+1)));o=new r(i.getBoundingClientRect());c.innerHTML="";c.appendChild(g);this._createdDiv||(l=e._getSelection(),
+(d<=l.start&&l.start<d+p||d<=l.end&&l.end<d+p)&&e._updateDOMSelection())}f.isIE&&(l=b.ownerDocument.defaultView||b.ownerDocument.parentWindow,b=l.screen.logicalXDPI/l.screen.deviceXDPI,l=l.screen.logicalYDPI/l.screen.deviceYDPI,o.left*=b,o.right*=b,o.top*=l,o.bottom*=l);break}d+=p}c=c.nextSibling}}b=this.getBoundingClientRect();if(!o)e._wrapMode?(e=this.getClientRects(),o=e[e.length-1],o.left=o.right,o.left+=b.left,o.top+=b.top,o.right+=b.left,o.bottom+=b.top):(o=new r(b),o.left=o.right);if(a||a===
+void 0)o.left-=b.left,o.top-=b.top,o.right-=b.left,o.bottom-=b.top;return o},_getClientRects:function(j,a){var b,e,c,l;if(!j._rectsCache){b=j.getClientRects();e=Array(b.length);for(l=0;l<b.length;l++)c=e[l]=new r(b[l]),c.left-=a.left,c.top-=a.top,c.right-=a.left,c.bottom-=a.top;j._rectsCache=e}b=j._rectsCache;e=[b.length];for(l=0;l<b.length;l++)e[l]=new r(b[l]);return e},getClientRects:function(j){if(!this.view._wrapMode)return[this.getBoundingClientRect()];for(var a=this._ensureCreated(),b=[],e=
+a.firstChild,c,l=a.getBoundingClientRect();e;){if(!e.ignore)for(var f=this._getClientRects(e,l),a=0;a<f.length;a++){var o=f[a],d;if(o.top!==o.bottom){var g=o.top+(o.bottom-o.top)/2;for(d=0;d<b.length;d++)if(c=b[d],c.top<=g&&g<c.bottom)break;if(d===b.length)b.push(o);else{if(o.left<c.left)c.left=o.left;if(o.top<c.top)c.top=o.top;if(o.right>c.right)c.right=o.right;if(o.bottom>c.bottom)c.bottom=o.bottom}}}e=e.nextSibling}return j!==void 0?b[j]:b},_getLineBoundingClientRect:function(j,a){var b=new r(j.getBoundingClientRect());
+if(!this.view._wrapMode){b.right=b.left;for(var e=j.lastChild;e&&e.ignoreChars===e.firstChild.length;)e=e.previousSibling;if(e)e=e.getBoundingClientRect(),b.right=e.right+o(j).right}a&&(e=o(j),b.left+=e.left,b.right-=e.right);return b},getLineCount:function(){return!this.view._wrapMode?1:this.getClientRects().length},getLineIndex:function(j){if(!this.view._wrapMode)return 0;for(var a=this.getClientRects(),j=this.getBoundingClientRect(j),j=j.top+(j.bottom-j.top)/2,b=0;b<a.length;b++)if(a[b].top<=j&&
+j<a[b].bottom)return b;return a.length-1},getLineStart:function(j){if(!this.view._wrapMode||j===0)return this.view._model.getLineStart(j);var a=this.getClientRects();return this.getOffset(a[j].left+1,a[j].top+1)},getOffset:function(j,a){var b=this.view,e=b._model,c=this.lineIndex,l=e.getLineStart(c),o=e.getLineEnd(c);if(l===o)return l;var d=this._ensureCreated(),g=this.getBoundingClientRect(),p,h;if(b._wrapMode){p=this.getClientRects();if(a<p[0].top)a=p[0].top;for(var i=0;i<p.length;i++)if(h=p[i],
+h.top<=a&&a<h.bottom)break;if(j<h.left)j=h.left;j>h.right&&(j=h.right-1)}else j<0&&(j=0),j>g.right-g.left&&(j=g.right-g.left);var q=d.ownerDocument,i=q.defaultView||q.parentWindow,r=f.isIE?i.screen.logicalXDPI/i.screen.deviceXDPI:1,s=f.isIE?i.screen.logicalYDPI/i.screen.deviceYDPI:1,i=l,t=d.firstChild;a:for(;t;){if(!t.ignore){var u=t.firstChild,d=u.length;t.ignoreChars&&(d-=t.ignoreChars);var v,k,n;p=this._getClientRects(t,g);for(var m=0;m<p.length;m++)if(h=p[m],h.left<=j&&j<h.right&&(!b._wrapMode||
+h.top<=a&&a<h.bottom)){var m=h.left+g.left,A;if(f.isIE||b._isRangeRects){for(var q=b._isRangeRects?q.createRange():q.body.createTextRange(),z=d,C=-1;z-C>1;){var J=Math.floor((z+C)/2);p=C+1;h=J===d-1&&t.ignoreChars?u.length:J+1;A=p===0&&f.isIE===8;b._isRangeRects?(q.setStart(u,p),q.setEnd(u,h)):(A&&(p=1),q.moveToElementText(t),q.move("character",p),q.moveEnd("character",h-p));p=q.getClientRects();for(var N=!1,L=0;L<p.length;L++)if(h=p[L],v=(A?m:h.left)*r-g.left,n=h.right*r-g.left,k=h.top*s-g.top,h=
+h.bottom*s-g.top,v<=j&&j<n&&(!b._wrapMode||k<=a&&a<h)){N=!0;break}N?z=J:C=J}i+=z;p=z;h=z===d-1&&t.ignoreChars?u.length:Math.min(z+1,u.length);b._isRangeRects?(q.setStart(u,p),q.setEnd(u,h)):(q.moveToElementText(t),q.move("character",p),q.moveEnd("character",h-p));p=q.getClientRects();b=!1;p.length>0&&(h=p[0],v=(A?m:h.left)*r-g.left,n=h.right*r-g.left,b=j>v+(n-v)/2);g=i-l;e=e.getLine(c);c=e.charCodeAt(g);55296<=c&&c<=56319&&b?g<e.length&&(c=e.charCodeAt(g+1),56320<=c&&c<=57343&&(i+=1)):56320<=c&&c<=
+57343&&!b&&g>0&&(c=e.charCodeAt(g-1),55296<=c&&c<=56319&&(i-=1));b&&i++}else{e=[];for(c=0;c<d;c++)e.push("<span>"),c===d-1?e.push(u.data.substring(c)):e.push(u.data.substring(c,c+1)),e.push("</span>");t.innerHTML=e.join("");for(e=t.firstChild;e;){h=e.getBoundingClientRect();v=h.left-g.left;n=h.right-g.left;if(v<=j&&j<n){j>v+(n-v)/2&&i++;break}i++;e=e.nextSibling}if(!this._createdDiv)t.innerHTML="",t.appendChild(u),g=b._getSelection(),(i<=g.start&&g.start<i+d||i<=g.end&&g.end<i+d)&&b._updateDOMSelection()}break a}i+=
+d}t=t.nextSibling}return Math.min(o,Math.max(l,i))},getNextOffset:function(j,a){if(a.unit==="line"){var b=this.view._model,e=b.getLineAtOffset(j);if(a.count>0)return a.count--,b.getLineEnd(e);a.count++;return b.getLineStart(e)}return a.unit==="wordend"||a.unit==="wordWS"||a.unit==="wordendWS"?this._getNextOffset_W3C(j,a):f.isIE?this._getNextOffset_IE(j,a):this._getNextOffset_W3C(j,a)},_getNextOffset_W3C:function(j,a){function b(j){return 33<=j&&j<=47||58<=j&&j<=64||91<=j&&j<=94||j===96||123<=j&&j<=
+126}function e(j){return j===32||j===9}var c=this.view._model,l=c.getLineAtOffset(j),f=c.getLine(l),o=c.getLineStart(l),c=c.getLineEnd(l),l=f.length,d=j-o,g,h=a.count<0?-1:1;if(a.unit==="word"||a.unit==="wordend"||a.unit==="wordWS"||a.unit==="wordendWS")for(var p,i,q;a.count!==0;){if(a.count>0){if(d===l)return c;g=f.charCodeAt(d);p=b(g);i=!p&&!e(g);for(d++;d<l;){g=f.charCodeAt(d);if(a.unit!=="wordWS"&&a.unit!=="wordendWS"){q=b(g);if(a.unit==="wordend"){if(!q&&p)break}else if(q&&!p)break;g=!q&&!e(g)}else g=
+!e(g);if(a.unit==="wordend"||a.unit==="wordendWS"){if(!g&&i)break}else if(g&&!i)break;i=g;p=q;d++}}else{if(d===0)return o;d--;g=f.charCodeAt(d);p=b(g);for(i=!p&&!e(g);0<d;){g=f.charCodeAt(d-1);if(a.unit!=="wordWS"&&a.unit!=="wordendWS"){q=b(g);if(a.unit==="wordend"){if(q&&!p)break}else if(!q&&p)break;g=!q&&!e(g)}else g=!e(g);if(a.unit==="wordend"||a.unit==="wordendWS"){if(g&&!i)break}else if(!g&&i)break;i=g;p=q;d--}}a.count-=h}else for(;a.count!==0&&0<=d+h&&d+h<=l;)d+=h,g=f.charCodeAt(d),56320<=g&&
+g<=57343&&d>0&&(g=f.charCodeAt(d-1),55296<=g&&g<=56319&&(d+=h)),a.count-=h;return o+d},_getNextOffset_IE:function(j,a){var b=this._ensureCreated(),e=this.view._model,c=this.lineIndex,l=0,f;f=e.getLineStart(c);var d=b.ownerDocument,o=a.count<0?-1:1;if(j===e.getLineEnd(c)){for(b=b.lastChild;b&&b.ignoreChars===b.firstChild.length;)b=b.previousSibling;if(!b)return f;l=d.body.createTextRange();l.moveToElementText(b);f=l.text.length;l.moveEnd(a.unit,o);l=j+l.text.length-f}else if(j===f&&a.count<0)l=f;else for(b=
+b.firstChild;b;){e=b.firstChild.length;b.ignoreChars&&(e-=b.ignoreChars);if(f+e>j){l=d.body.createTextRange();if(j===f&&a.count<0){for(f=b.previousSibling;f;){if(f.firstChild&&f.firstChild.length)break;f=f.previousSibling}l.moveToElementText(f?f:b.previousSibling)}else l.moveToElementText(b),l.collapse(),l.moveEnd("character",j-f);f=l.text.length;l.moveEnd(a.unit,o);l=j+l.text.length-f;break}f=e+f;b=b.nextSibling}a.count-=o;return l},destroy:function(){var j=this._createdDiv;if(j)j.parentNode.removeChild(j),
+this._createdDiv=null}};t.prototype={addKeyMode:function(j,a){var b=this._keyModes;a!==void 0?b.splice(a,0,j):b.push(j);j._modeAdded&&j._modeAdded()},addRuler:function(j,a){j.setView(this);var b=this._rulers;if(a!==void 0){var e,c;for(e=0,c=0;e<b.length&&c<a;e++)j.getLocation()===b[e].getLocation()&&c++;b.splice(c,0,j);a=c}else b.push(j);this._createRuler(j,a);this._update()},computeSize:function(){var j=0,a=0,b=this._model,e=this._clientDiv;if(!e)return{width:j,height:a};var c=e.style.width;if(f.isWebkit)e.style.width=
+"0x7fffffffpx";for(var b=b.getLineCount(),l=0;l<b;l++){var d=this._getLine(l),o=d.getBoundingClientRect(),j=Math.max(j,o.right-o.left);a+=o.bottom-o.top;d.destroy()}if(f.isWebkit)e.style.width=c;e=this._getViewPadding();j+=e.right+e.left+this._metrics.scrollWidth;a+=e.bottom+e.top+this._metrics.scrollWidth;return{width:j,height:a}},convert:function(j,a,b){if(this._clientDiv){var e=this._getScroll(),c=this._getViewPadding(),l=this._viewDiv.getBoundingClientRect();a==="document"&&(j.x!==void 0&&(j.x+=
+-e.x+l.left+c.left),j.y!==void 0&&(j.y+=-e.y+l.top+c.top));b==="document"&&(j.x!==void 0&&(j.x+=e.x-l.left-c.left),j.y!==void 0&&(j.y+=e.y-l.top-c.top));return j}},destroy:function(){for(var j=0;j<this._rulers.length;j++)this._rulers[j].setView(null);this.rulers=null;this._destroyView();this.onDestroy({type:"Destroy"});this._parent=null;this._model&&this._model.destroy&&this._model.destroy();this._actions=this._keyModes=this._doubleClickSelection=this._selection=this._theme=this._model=null},focus:function(){this._clientDiv&&
+(this._updateDOMSelection(),this._clientDiv.focus(),this._updateDOMSelection())},hasFocus:function(){return this._hasFocus},getActionDescription:function(j){if(j=this._actions[j])return j.actionDescription},getActions:function(j){var a=[],b=this._actions,e;for(e in b)b.hasOwnProperty(e)&&(j||!b[e].defaultHandler)&&a.push(e);return a},getBottomIndex:function(j){return!this._clientDiv?0:this._getBottomIndex(j)},getBottomPixel:function(){return!this._clientDiv?0:this._getScroll().y+this._getClientHeight()},
+getCaretOffset:function(){return this._getSelection().getCaret()},getClientArea:function(){if(!this._clientDiv)return{x:0,y:0,width:0,height:0};var j=this._getScroll();return{x:j.x,y:j.y,width:this._getClientWidth(),height:this._getClientHeight()}},getHorizontalPixel:function(){return!this._clientDiv?0:this._getScroll().x},getKeyBindings:function(j){for(var a=[],b=this._keyModes,e=0;e<b.length;e++)a=a.concat(b[e].getKeyBindings(j));return a},getKeyModes:function(){return this._keyModes.slice(0)},
+getLineHeight:function(j){return!this._clientDiv?0:this._getLineHeight(j)},getLineIndex:function(j){return!this._clientDiv?0:this._getLineIndex(j)},getLinePixel:function(j){return!this._clientDiv?0:this._getLinePixel(j)},getLocationAtOffset:function(j){if(!this._clientDiv)return{x:0,y:0};var a=this._model,j=Math.min(Math.max(0,j),a.getCharCount()),a=a.getLineAtOffset(j),b=this._getLine(a),j=b.getBoundingClientRect(j);b.destroy();b=j.left;a=this._getLinePixel(a)+j.top;return{x:b,y:a}},getNextOffset:function(j,
+a){var b=new q(j,j,!1);this._doMove(a,b);return b.getCaret()},getOptions:function(){var j;if(arguments.length===0)j=this._defaultOptions();else if(arguments.length===1){if(j=arguments[0],typeof j==="string")return h(this["_"+j])}else{j={};for(var a in arguments)arguments.hasOwnProperty(a)&&(j[arguments[a]]=void 0)}for(var b in j)j.hasOwnProperty(b)&&(j[b]=h(this["_"+b]));return j},getModel:function(){return this._model},getOffsetAtLocation:function(j,a){if(!this._clientDiv)return 0;var b=this._getLineIndex(a),
+e=this._getLine(b),b=e.getOffset(j,a-this._getLinePixel(b));e.destroy();return b},getLineAtOffset:function(j){this.getModel().getLineAtOffset(j)},getLineStart:function(j){this.getModel().getLineStart(j)},getRulers:function(){return this._rulers.slice(0)},getSelection:function(){var j=this._getSelection();return{start:j.start,end:j.end}},getText:function(j,a){return this._model.getText(j,a)},getTopIndex:function(j){return!this._clientDiv?0:this._getTopIndex(j)},getTopPixel:function(){return!this._clientDiv?
+0:this._getScroll().y},invokeAction:function(j,a,b){if(this._clientDiv){if(j=this._actions[j]){if(!a&&j.handler&&j.handler(b))return!0;if(j.defaultHandler)return typeof j.defaultHandler(b)==="boolean"}return!1}},isDestroyed:function(){return!this._clientDiv},onContextMenu:function(j){return this.dispatchEvent(j)},onDragStart:function(j){return this.dispatchEvent(j)},onDrag:function(j){return this.dispatchEvent(j)},onDragEnd:function(j){return this.dispatchEvent(j)},onDragEnter:function(j){return this.dispatchEvent(j)},
+onDragOver:function(j){return this.dispatchEvent(j)},onDragLeave:function(j){return this.dispatchEvent(j)},onDrop:function(j){return this.dispatchEvent(j)},onDestroy:function(j){return this.dispatchEvent(j)},onLineStyle:function(j){return this.dispatchEvent(j)},onKeyDown:function(j){return this.dispatchEvent(j)},onKeyPress:function(j){return this.dispatchEvent(j)},onKeyUp:function(j){return this.dispatchEvent(j)},onModelChanged:function(j){return this.dispatchEvent(j)},onModelChanging:function(j){return this.dispatchEvent(j)},
+onModify:function(j){return this.dispatchEvent(j)},onMouseDown:function(j){return this.dispatchEvent(j)},onMouseUp:function(j){return this.dispatchEvent(j)},onMouseMove:function(j){return this.dispatchEvent(j)},onMouseOver:function(j){return this.dispatchEvent(j)},onMouseOut:function(j){return this.dispatchEvent(j)},onSelection:function(j){return this.dispatchEvent(j)},onScroll:function(j){return this.dispatchEvent(j)},onVerify:function(j){return this.dispatchEvent(j)},onFocus:function(j){return this.dispatchEvent(j)},
+onBlur:function(j){return this.dispatchEvent(j)},redraw:function(){if(!(this._redrawCount>0)){var j=this._model.getLineCount();this.redrawRulers(0,j);this.redrawLines(0,j)}},redrawRulers:function(j,a){if(!(this._redrawCount>0))for(var b=this.getRulers(),e=0;e<b.length;e++)this.redrawLines(j,a,b[e])},redrawLines:function(j,a,b){if(!(this._redrawCount>0)&&(j===void 0&&(j=0),a===void 0&&(a=this._model.getLineCount()),j!==a)){var e=this._clientDiv;if(e){if(b)for(e=this._getRulerParent(b).firstChild;e;){if(e._ruler===
+b)break;e=e.nextSibling}b?e.rulerChanged=!0:this._lineHeight&&this._resetLineHeight(j,a);if(!b||b.getOverview()==="page")for(e=e.firstChild;e;){var c=e.lineIndex;if(j<=c&&c<a)e.lineChanged=!0;e=e.nextSibling}if(!b&&!this._wrapMode&&j<=this._maxLineIndex&&this._maxLineIndex<a)this._checkMaxLineIndex=this._maxLineIndex,this._maxLineIndex=-1,this._maxLineWidth=0;this._queueUpdate()}}},redrawRange:function(j,a){if(!(this._redrawCount>0)){var b=this._model;j===void 0&&(j=0);a===void 0&&(a=b.getCharCount());
+var e=b.getLineAtOffset(j),b=b.getLineAtOffset(Math.max(j,a-1))+1;this.redrawLines(e,b)}},removeKeyMode:function(j){for(var a=this._keyModes,b=0;b<a.length;b++)if(a[b]===j){a.splice(b,1);break}j._modeRemoved&&j._modeRemoved()},removeRuler:function(j){for(var a=this._rulers,b=0;b<a.length;b++)if(a[b]===j){a.splice(b,1);j.setView(null);this._destroyRuler(j);this._update();break}},resize:function(){this._clientDiv&&this._handleResize(null)},setAction:function(j,a,b){if(j){var e=this._actions,c=e[j];
+c||(c=e[j]={});c.handler=a;if(b!==void 0)c.actionDescription=b}},setKeyBinding:function(j,a){this._keyModes[0].setKeyBinding(j,a)},setCaretOffset:function(j,a,b){var e=this._model.getCharCount(),j=Math.max(0,Math.min(j,e));this._setSelection(new q(j,j,!1),a===void 0||a,!0,b)},setHorizontalPixel:function(j){this._clientDiv&&(j=Math.max(0,j),this._scrollView(j-this._getScroll().x,0))},setRedraw:function(j){j?--this._redrawCount===0&&this.redraw():this._redrawCount++},setModel:function(j){if(j&&j!==
+this._model){this._model.removeEventListener("preChanging",this._modelListener.onChanging);this._model.removeEventListener("postChanged",this._modelListener.onChanged);var a=this._model.getLineCount(),b=this._model.getCharCount(),e=j.getLineCount(),c=j.getCharCount(),l={type:"ModelChanging",text:j.getText(),start:0,removedCharCount:b,addedCharCount:c,removedLineCount:a,addedLineCount:e};this.onModelChanging(l);this._model=j;l={type:"ModelChanged",start:0,removedCharCount:b,addedCharCount:c,removedLineCount:a,
+addedLineCount:e};this.onModelChanged(l);this._model.addEventListener("preChanging",this._modelListener.onChanging);this._model.addEventListener("postChanged",this._modelListener.onChanged);this._reset();this._update()}},setOptions:function(j){var b=this._defaultOptions(),e;for(e in j)if(j.hasOwnProperty(e)){var c=j[e];if(!a(this["_"+e],c)){var l=b[e]?b[e].update:null;l?l.call(this,c):this["_"+e]=h(c)}}},setSelection:function(j,a,b,e){var c=j>a;if(c)var l=j,j=a,a=l;l=this._model.getCharCount();j=
+Math.max(0,Math.min(j,l));a=Math.max(0,Math.min(a,l));this._setSelection(new q(j,a,c),b===void 0||b,!0,e)},setText:function(j,a,b){var e=a===void 0&&b===void 0;a===void 0&&(a=0);b===void 0&&(b=this._model.getCharCount());if(e)this._variableLineHeight=!1;this._modifyContent({text:j,start:a,end:b,_code:!0},!e);if(e)this._columnX=-1,this._setSelection(new q(0,0,!1),!0),f.isFirefox&&this._fixCaret()},setTopIndex:function(j){this._clientDiv&&this._scrollView(0,this._getLinePixel(Math.max(0,j))-this._getScroll().y)},
+setTopPixel:function(j){this._clientDiv&&this._scrollView(0,Math.max(0,j)-this._getScroll().y)},showSelection:function(){return this._showCaret(!0)},update:function(j,a){this._clientDiv&&(j&&this._updateStyle(),a===void 0||a?this._update():this._queueUpdate())},_handleRootMouseDown:function(j){if(!this._ignoreEvent(j)){if(f.isFirefox&&j.which===1)this._clientDiv.contentEditable=!1,this._ignoreBlur=(this._overlayDiv||this._clientDiv).draggable=!0;var a=this._overlayDiv||this._clientDiv;if(f.isIE<9)a=
+this._viewDiv;for(var b=j.target?j.target:j.srcElement;b;){if(a===b)return;b=b.parentNode}j.preventDefault&&j.preventDefault();j.stopPropagation&&j.stopPropagation();if(!this._isW3CEvents){var e=this;this._getWindow().setTimeout(function(){e._clientDiv.focus()},0)}}},_handleRootMouseUp:function(j){if(!this._ignoreEvent(j)&&f.isFirefox&&j.which===1)this._clientDiv.contentEditable=!0,(this._overlayDiv||this._clientDiv).draggable=!1,this._fixCaret(),this._ignoreBlur=!1},_handleBlur:function(){if(!this._ignoreBlur){this._hasFocus=
+!1;if(f.isIE<9&&!this._getSelection().isEmpty()){var j=this._rootDiv,a=f.createElement(j.ownerDocument,"div");j.appendChild(a);j.removeChild(a)}if(this._cursorDiv)this._cursorDiv.style.display="none";if(this._selDiv1)if(this._selDiv1.style.background="lightgray",this._selDiv2.style.background="lightgray",this._selDiv3.style.background="lightgray",j=this._getWindow(),a=this._selDiv1.ownerDocument,j.getSelection){a=j.getSelection();for(j=a.anchorNode;j;){if(j===this._clientDiv){a.rangeCount>0&&a.removeAllRanges();
+break}j=j.parentNode}}else if(a.selection){this._ignoreSelect=!1;for(j=a.selection.createRange().parentElement();j;){if(j===this._clientDiv){a.selection.empty();break}j=j.parentNode}this._ignoreSelect=!0}if(!this._ignoreFocus)this.onBlur({type:"Blur"})}},_handleContextMenu:function(j){if(!this._ignoreEvent(j)){f.isIE&&this._lastMouseButton===3&&this._updateDOMSelection();var a=!1;this.isListening("ContextMenu")?(a=this._createMouseEvent("ContextMenu",j),a.screenX=j.screenX,a.screenY=j.screenY,this.onContextMenu(a),
+a=a.defaultPrevented):f.isMac&&f.isFirefox&&j.button===0&&(a=!0);if(a)return j.preventDefault&&j.preventDefault(),!1}},_handleCopy:function(j){if(!this._ignoreEvent(j)&&!this._ignoreCopy&&this._doCopy(j))return j.preventDefault&&j.preventDefault(),!1},_handleCut:function(j){if(!this._ignoreEvent(j)&&this._doCut(j))return j.preventDefault&&j.preventDefault(),!1},_handleDataModified:function(j){this._ignoreEvent(j)||this._startIME()},_handleDblclick:function(j){if(!this._ignoreEvent(j)&&(this._lastMouseTime=
+j.timeStamp?j.timeStamp:(new Date).getTime(),this._clickCount!==2))this._clickCount=2,this._handleMouse(j)},_handleDragStart:function(j){if(!this._ignoreEvent(j)){if(f.isFirefox){var a=this;this._getWindow().setTimeout(function(){a._clientDiv.contentEditable=!0;a._clientDiv.draggable=!1;a._ignoreBlur=!1},0)}if(this.isListening("DragStart")&&this._dragOffset!==-1)this._isMouseDown=!1,this.onDragStart(this._createMouseEvent("DragStart",j)),this._dragOffset=-1;else return j.preventDefault&&j.preventDefault(),
+!1}},_handleDrag:function(j){if(!this._ignoreEvent(j)&&this.isListening("Drag"))this.onDrag(this._createMouseEvent("Drag",j))},_handleDragEnd:function(j){if(!this._ignoreEvent(j)){this._dropTarget=!1;this._dragOffset=-1;if(this.isListening("DragEnd"))this.onDragEnd(this._createMouseEvent("DragEnd",j));f.isFirefox&&(this._fixCaret(),j.dataTransfer.dropEffect==="none"&&!j.dataTransfer.mozUserCancelled&&this._fixCaret())}},_handleDragEnter:function(j){if(!this._ignoreEvent(j)){var a=!0;this._dropTarget=
+!0;this.isListening("DragEnter")&&(a=!1,this.onDragEnter(this._createMouseEvent("DragEnter",j)));if(f.isWebkit||a)return j.preventDefault&&j.preventDefault(),!1}},_handleDragOver:function(j){if(!this._ignoreEvent(j)){var a=!0;this.isListening("DragOver")&&(a=!1,this.onDragOver(this._createMouseEvent("DragOver",j)));if(f.isWebkit||a){if(a)j.dataTransfer.dropEffect="none";j.preventDefault&&j.preventDefault();return!1}}},_handleDragLeave:function(j){if(!this._ignoreEvent(j)&&(this._dropTarget=!1,this.isListening("DragLeave")))this.onDragLeave(this._createMouseEvent("DragLeave",
+j))},_handleDrop:function(j){if(!this._ignoreEvent(j)){this._dropTarget=!1;if(this.isListening("Drop"))this.onDrop(this._createMouseEvent("Drop",j));j.preventDefault&&j.preventDefault();return!1}},_handleFocus:function(){this._hasFocus=!0;f.isIOS&&this._lastTouchOffset!==void 0?(this.setCaretOffset(this._lastTouchOffset,!0),this._lastTouchOffset=void 0):this._updateDOMSelection();if(this._cursorDiv)this._cursorDiv.style.display="block";if(this._selDiv1){var j=this._highlightRGB;this._selDiv1.style.background=
+j;this._selDiv2.style.background=j;this._selDiv3.style.background=j}if(!this._ignoreFocus)this.onFocus({type:"Focus"})},_handleKeyDown:function(j){if(!this._ignoreEvent(j)){if(this.isListening("KeyDown")){var a=this._createKeyEvent("KeyDown",j);this.onKeyDown(a);if(a.defaultPrevented){if(f.isFirefox)this._keyDownPrevented=!0;j.preventDefault();return}}a=!1;switch(j.keyCode){case 16:case 17:case 18:case 91:a=!0;break;default:this._setLinksVisible(!1)}if(j.keyCode===229){if(this._readonly)return j.preventDefault&&
+j.preventDefault(),!1;a=!0;if(f.isSafari&&f.isMac&&j.ctrlKey)a=!1,j.keyCode=129;a&&this._startIME()}else a||this._commitIME();if((f.isMac||f.isLinux)&&f.isFirefox<4||f.isOpera<12.16)return this._keyDownEvent=j,!0;if(this._doAction(j))return j.preventDefault?(j.preventDefault(),j.stopPropagation()):(j.cancelBubble=!0,j.returnValue=!1,j.keyCode=0),!1}},_handleKeyPress:function(j){if(!this._ignoreEvent(j))if(this._keyDownPrevented)j.preventDefault&&(j.preventDefault(),j.stopPropagation()),this._keyDownPrevented=
+void 0;else{if(f.isMac&&f.isWebkit&&(63232<=j.keyCode&&j.keyCode<=63487||j.keyCode===13||j.keyCode===8))return j.preventDefault&&j.preventDefault(),!1;if(((f.isMac||f.isLinux)&&f.isFirefox<4||f.isOpera<12.16)&&this._doAction(this._keyDownEvent))return j.preventDefault&&j.preventDefault(),!1;var a=f.isMac?j.metaKey:j.ctrlKey;if(j.charCode!==void 0&&a)switch(j.charCode){case 99:case 118:case 120:return!0}if(this.isListening("KeyPress")&&(a=this._createKeyEvent("KeyPress",j),this.onKeyPress(a),a.defaultPrevented)){j.preventDefault();
+return}if(this._doAction(j))return j.preventDefault?(j.preventDefault(),j.stopPropagation()):(j.cancelBubble=!0,j.returnValue=!1,j.keyCode=0),!1;a=!1;if(f.isMac){if(j.ctrlKey||j.metaKey)a=!0}else if(f.isFirefox){if(j.ctrlKey||j.altKey)a=!0}else j.ctrlKey^j.altKey&&(a=!0);if(!a&&(a=f.isOpera?j.which:j.charCode!==void 0?j.charCode:j.keyCode,a>31))return this._doContent(String.fromCharCode(a)),j.preventDefault&&j.preventDefault(),!1}},_handleDocKeyUp:function(j){(f.isMac?j.metaKey:j.ctrlKey)||this._setLinksVisible(!1)},
+_handleKeyUp:function(j){if(!this._ignoreEvent(j)){if(this.isListening("KeyUp")){var a=this._createKeyEvent("KeyUp",j);this.onKeyUp(a);if(a.defaultPrevented){j.preventDefault();return}}this._handleDocKeyUp(j);j.keyCode===13&&this._commitIME()}},_handleLinkClick:function(j){if(!(f.isMac?j.metaKey:j.ctrlKey))return j.preventDefault&&j.preventDefault(),!1},_handleMouse:function(j){var a=this._getWindow(),b=!0,e=a;if(f.isIE||f.isFirefox&&!this._overlayDiv)e=this._clientDiv;if(this._overlayDiv){if(this._hasFocus)this._ignoreFocus=
+!0;var c=this;a.setTimeout(function(){c.focus();c._ignoreFocus=!1},0)}this._clickCount===1?(b=this._setSelectionTo(j.clientX,j.clientY,j.shiftKey,(!f.isOpera||f.isOpera>=12.16)&&this._hasFocus&&this.isListening("DragStart")))&&this._setGrab(e):(this._isW3CEvents&&this._setGrab(e),this._doubleClickSelection=null,this._setSelectionTo(j.clientX,j.clientY,j.shiftKey),this._doubleClickSelection=this._getSelection());return b},_handleMouseDown:function(j){if(!this._ignoreEvent(j)){if(this._linksVisible)if((j.target||
+j.srcElement).tagName!=="A")this._setLinksVisible(!1);else return;this._commitIME();var a=j.which;a||(j.button===4&&(a=2),j.button===2&&(a=3),j.button===1&&(a=1));var b=a!==2&&j.timeStamp?j.timeStamp:(new Date).getTime(),e=b-this._lastMouseTime,c=Math.abs(this._lastMouseX-j.clientX),l=Math.abs(this._lastMouseY-j.clientY),d=this._lastMouseButton===a;this._lastMouseX=j.clientX;this._lastMouseY=j.clientY;this._lastMouseTime=b;this._lastMouseButton=a;if(a===1)this._isMouseDown=!0,d&&e<=this._clickTime&&
+c<=this._clickDist&&l<=this._clickDist?this._clickCount++:this._clickCount=1;if(this.isListening("MouseDown")&&(b=this._createMouseEvent("MouseDown",j),this.onMouseDown(b),b.defaultPrevented)){j.preventDefault();return}if(a===1&&this._handleMouse(j)&&(f.isIE>=9||f.isOpera||f.isChrome||f.isSafari||f.isFirefox&&!this._overlayDiv))this._hasFocus||this.focus(),j.preventDefault();f.isFirefox&&this._lastMouseButton===3&&this._updateDOMSelection()}},_handleMouseOver:function(j){if(!this._ignoreEvent(j)&&
+!this._animation&&this.isListening("MouseOver"))this.onMouseOver(this._createMouseEvent("MouseOver",j))},_handleMouseOut:function(j){if(!this._ignoreEvent(j)&&!this._animation&&this.isListening("MouseOut"))this.onMouseOut(this._createMouseEvent("MouseOut",j))},_handleMouseMove:function(j){if(!this._animation){var a=this._isClientDiv(j);if(this.isListening("MouseMove")&&a)this.onMouseMove(this._createMouseEvent("MouseMove",j));if(!this._dropTarget){var b=this._linksVisible||this._lastMouseMoveX!==
+j.clientX||this._lastMouseMoveY!==j.clientY;this._lastMouseMoveX=j.clientX;this._lastMouseMoveY=j.clientY;this._setLinksVisible(b&&!this._isMouseDown&&(f.isMac?j.metaKey:j.ctrlKey));if(!this._isW3CEvents){if(j.button===0)return this._setGrab(null),!0;if(!this._isMouseDown&&j.button===1&&(this._clickCount&1)!==0&&a)return this._clickCount=2,this._handleMouse(j,this._clickCount)}if(this._isMouseDown&&this._dragOffset===-1){var a=j.clientX,j=j.clientY,e=this._getViewPadding(),c=this._viewDiv.getBoundingClientRect(),
+l=this._getClientWidth(),d=this._getClientHeight(),b=c.left+e.left,o=c.top+e.top,l=c.left+e.left+l,e=c.top+e.top+d;j<o?this._doAutoScroll("up",a,j-o):j>e?this._doAutoScroll("down",a,j-e):a<b&&!this._wrapMode?this._doAutoScroll("left",a-b,j):a>l&&!this._wrapMode?this._doAutoScroll("right",a-l,j):(this._endAutoScroll(),this._setSelectionTo(a,j,!0))}}}},_isClientDiv:function(j){for(var a=this._overlayDiv||this._clientDiv,j=j.target?j.target:j.srcElement;j;){if(a===j)return!0;j=j.parentNode}return!1},
+_createKeyEvent:function(j,a){return{type:j,event:a,preventDefault:function(){this.defaultPrevented=!0}}},_createMouseEvent:function(j,a){var b=this.convert({x:a.clientX,y:a.clientY},"page","document");return{type:j,event:a,clickCount:this._clickCount,x:b.x,y:b.y,preventDefault:function(){this.defaultPrevented=!0}}},_handleMouseUp:function(j){var a=j.which?j.button===0:j.button===1;if(this.isListening("MouseUp")&&(this._isClientDiv(j)||a&&this._isMouseDown))this.onMouseUp(this._createMouseEvent("MouseUp",
+j));if(!this._linksVisible&&a&&this._isMouseDown){if(this._dragOffset!==-1)a=this._getSelection(),a.extend(this._dragOffset),a.collapse(),this._setSelection(a,!0,!0),this._dragOffset=-1;this._isMouseDown=!1;this._endAutoScroll();this._isW3CEvents&&this._setGrab(null);f.isFirefox&&j.preventDefault()}},_handleMouseWheel:function(j){var a=this._getLineHeight(),b=0,e=0;f.isIE||f.isOpera?e=-j.wheelDelta/40*a:f.isFirefox?(a=f.isMac?j.detail*3:Math.max(-256,Math.min(256,j.detail))*a,j.axis===j.HORIZONTAL_AXIS?
+b=a:e=a):f.isMac?(e=j.timeStamp-this._wheelTimeStamp,this._wheelTimeStamp=j.timeStamp,b=j.wheelDeltaX%120!==0?1:e<40?40/(40-e):40,e=j.wheelDeltaY%120!==0?1:e<40?40/(40-e):40,b=Math.ceil(-j.wheelDeltaX/b),-1<b&&b<0&&(b=-1),0<b&&b<1&&(b=1),e=Math.ceil(-j.wheelDeltaY/e),-1<e&&e<0&&(e=-1),0<e&&e<1&&(e=1)):(b=-j.wheelDeltaX,e=-j.wheelDeltaY/120*8*a);if(f.isSafari){for(a=j.target;a&&a.lineIndex===void 0;)a=a.parentNode;this._mouseWheelLine=a}a=this._getScroll();this._scrollView(b,e);b=this._getScroll();
+if(a.x!==b.x||a.y!==b.y)return j.preventDefault&&j.preventDefault(),!1},_handlePaste:function(j){if(!this._ignoreEvent(j)&&!this._ignorePaste&&this._doPaste(j)){if(f.isIE){var a=this;this._ignoreFocus=!0;this._getWindow().setTimeout(function(){a._updateDOMSelection();a._ignoreFocus=!1},0)}j.preventDefault&&j.preventDefault();return!1}},_handleResize:function(){var j=this._rootDiv.clientWidth,b=this._rootDiv.clientHeight;if(this._rootWidth!==j||this._rootHeight!==b){this._rootWidth!==j&&this._wrapMode&&
+this._resetLineHeight();this._rootWidth=j;this._rootHeight=b;j=f.isIE<9;b=this._calculateMetrics();if(!a(b,this._metrics)){if(this._variableLineHeight)this._variableLineHeight=!1,this._resetLineHeight();this._metrics=b;j=!0}j?this._queueUpdate():this._update()}},_handleRulerEvent:function(j){for(var a=j.target?j.target:j.srcElement,b=a.lineIndex;a&&!a._ruler;){if(b===void 0&&a.lineIndex!==void 0)b=a.lineIndex;a=a.parentNode}var e=a?a._ruler:null;if(b===void 0&&e&&e.getOverview()==="document"){var b=
+this._getClientHeight(),c=this._model.getLineCount(),l=this._getViewPadding(),f=this._viewDiv.getBoundingClientRect(),b=Math.floor((j.clientY-f.top-this._metrics.scrollWidth)*c/(b+l.top+l.bottom-2*this._metrics.scrollWidth));0<=b&&b<c||(b=void 0)}if(e)switch(j.type){case "click":if(e.onClick)e.onClick(b,j);break;case "dblclick":if(e.onDblClick)e.onDblClick(b,j);break;case "mousemove":if(e.onMouseMove)e.onMouseMove(b,j);break;case "mouseover":if(e.onMouseOver)e.onMouseOver(b,j);break;case "mouseout":if(e.onMouseOut){for(c=
+j.relatedTarget;c&&c!==this._rootDiv;){if(c===a)return;c=c.parentNode}e.onMouseOut(b,j)}}},_handleScroll:function(){var j=this._getScroll(!1),a=this._hScroll,b=this._vScroll;if(a!==j.x||b!==j.y)this._hScroll=j.x,this._vScroll=j.y,this._commitIME(),this._update(b===j.y),this.onScroll({type:"Scroll",oldValue:{x:a,y:b},newValue:j})},_handleSelectStart:function(j){if(this._ignoreSelect)return j&&j.preventDefault&&j.preventDefault(),!1},_getModelOffset:function(j,a){if(j){var b;b=j.tagName==="DIV"?j:j.parentNode.parentNode;
+var e=0,c=b.lineIndex;if(j.tagName!=="DIV")for(b=b.firstChild;b;){var l=b.firstChild;if(l===j){b.ignoreChars&&(e-=b.ignoreChars);e+=a;break}b.ignoreChars&&(e-=b.ignoreChars);e+=l.data.length;b=b.nextSibling}return Math.max(0,e)+this._model.getLineStart(c)}},_updateSelectionFromDOM:function(){var j=this._getWindow().getSelection(),a=this._getModelOffset(j.anchorNode,j.anchorOffset),j=this._getModelOffset(j.focusNode,j.focusOffset);a===void 0||j===void 0||this._setSelection(new q(a,j),!1,!1)},_handleSelectionChange:function(){if(this._imeOffset===
+-1)if(f.isAndroid){var j=this._getWindow();this._selTimer&&j.clearTimeout(this._selTimer);var a=this;this._selTimer=j.setTimeout(function(){if(a._clientDiv)a._selTimer=null,a._updateSelectionFromDOM()},250)}else this._updateSelectionFromDOM()},_handleTextInput:function(j){if(!this._ignoreEvent(j)){this._imeOffset=-1;var a=this._getWindow().getSelection();if(a.anchorNode!==this._anchorNode||a.focusNode!==this._focusNode||a.anchorOffset!==this._anchorOffset||a.focusOffset!==this._focusOffset){for(var b=
+a.anchorNode;b;){if(b.lineIndex!==void 0)break;b=b.parentNode}if(b){var e=this._model,c=b.lineIndex,l=e.getLine(c),f=l,d=0,e=e.getLineStart(c);if(a.rangeCount>0)a.getRangeAt(0).deleteContents(),c=b.ownerDocument.createTextNode(j.data),a.getRangeAt(0).insertNode(c),d=this._getDOMText(b,c),f=d.text,d=d.offset,c.parentNode.removeChild(c);b.lineRemoved=!0;for(b=0;l.charCodeAt(b)===f.charCodeAt(b)&&b<d;)b++;a=l.length-1;for(c=f.length-l.length;l.charCodeAt(a)===f.charCodeAt(a+c)&&a+c>=d+j.data.length;)a--;
+a++;l=f.substring(b,a+c);b+=e;a+=e;this._modifyContent({text:l,start:b,end:a,_ignoreDOMSelection:!0},!0)}}else this._doContent(j.data);j.preventDefault()}},_handleTouchStart:function(j){this._commitIME();var a=this._getWindow();if(this._touchScrollTimer)this._vScrollDiv.style.display="none",this._hScrollDiv.style.display="none",a.clearInterval(this._touchScrollTimer),this._touchScrollTimer=null;var b=j.touches;if(b.length===1){var b=b[0],e=b.clientX,c=b.clientY;this._touchStartX=e;this._touchStartY=
+c;if(f.isAndroid&&(c<b.pageY-a.pageYOffset||e<b.pageX-a.pageXOffset))e=b.pageX-a.pageXOffset,c=b.pageY-a.pageYOffset;a=this.convert({x:e,y:c},"page","document");this._lastTouchOffset=this.getOffsetAtLocation(a.x,a.y);this._touchStartTime=j.timeStamp;this._touching=!0}},_handleTouchMove:function(j){var a=j.touches;if(a.length===1){a=a[0];this._touchCurrentX=a.clientX;this._touchCurrentY=a.clientY;if(!this._touchScrollTimer&&j.timeStamp-this._touchStartTime<200){this._vScrollDiv.style.display="block";
+if(!this._wrapMode)this._hScrollDiv.style.display="block";var b=this,e=this._getWindow();this._touchScrollTimer=e.setInterval(function(){var j=0,a=0;if(b._touching)j=b._touchStartX-b._touchCurrentX,a=b._touchStartY-b._touchCurrentY,b._touchSpeedX=j/10,b._touchSpeedY=a/10,b._touchStartX=b._touchCurrentX,b._touchStartY=b._touchCurrentY;else if(Math.abs(b._touchSpeedX)<0.1&&Math.abs(b._touchSpeedY)<0.1){b._vScrollDiv.style.display="none";b._hScrollDiv.style.display="none";e.clearInterval(b._touchScrollTimer);
+b._touchScrollTimer=null;return}else j=b._touchSpeedX*10,a=b._touchSpeedY*10,b._touchSpeedX*=0.95,b._touchSpeedY*=0.95;b._scrollView(j,a)},10)}this._touchScrollTimer&&j.preventDefault()}},_handleTouchEnd:function(j){if(j.touches.length===0)this._touching=!1},_doAction:function(j){var a,b,e=this._keyModes;for(b=e.length-1;b>=0;b--)if(a=e[b],typeof a.match==="function"&&(a=a.match(j),a!==void 0))return this.invokeAction(a);return!1},_doMove:function(j,a){var b=this._model,e=a.getCaret(),c=b.getLineAtOffset(e);
+if(!j.count)j.count=1;for(;j.count!==0;){var l=b.getLineStart(c);if(j.count<0&&e===l)if(c>0)j.unit==="character"&&j.count++,c--,a.extend(b.getLineEnd(c));else break;else if(j.count>0&&e===b.getLineEnd(c))if(c+1<b.getLineCount())j.unit==="character"&&j.count--,c++,a.extend(b.getLineStart(c));else break;else{var f=!1;j.expandTab&&j.unit==="character"&&(e-l)%this._tabSize===0&&(f=!/[^ ]/.test(b.getText(l,e)));f?(a.extend(e-this._tabSize),j.count+=j.count<0?1:-1):(l=this._getLine(c),a.extend(l.getNextOffset(e,
+j)),l.destroy())}e=a.getCaret()}return a},_doBackspace:function(j){var a=this._getSelection();if(a.isEmpty()){if(!j.count)j.count=1;j.count*=-1;j.expandTab=this._expandTab;this._doMove(j,a)}this._modifyContent({text:"",start:a.start,end:a.end},!0);return!0},_doCase:function(j){var a=this._getSelection();this._doMove(j,a);var b=this.getText(a.start,a.end);this._setSelection(a,!0);switch(j.type){case "lower":b=b.toLowerCase();break;case "capitalize":b=b.replace(/(?:^|\s)\S/g,function(j){return j.toUpperCase()});
+break;case "reverse":j="";for(a=0;a<b.length;a++){var e=b[a],c=e.toLowerCase(),e=c!==e?c:e.toUpperCase();j+=e}b=j;break;default:b=b.toUpperCase()}this._doContent(b);return!0},_doContent:function(j){var a=this._getSelection();if(this._overwriteMode&&a.isEmpty()){var b=this._model,e=b.getLineAtOffset(a.end);a.end<b.getLineEnd(e)&&(b=this._getLine(e),a.extend(b.getNextOffset(a.getCaret(),{unit:"character",count:1})),b.destroy())}this._modifyContent({text:j,start:a.start,end:a.end,_ignoreDOMSelection:!0},
+!0)},_doCopy:function(j){var a=this._getSelection();return!a.isEmpty()?this._setClipboardText(this._getBaseText(a.start,a.end),j):!0},_doCursorNext:function(j){var a=this._getSelection();!a.isEmpty()&&!j.select?a.start=a.end:this._doMove(j,a);j.select||a.collapse();this._setSelection(a,!0);return!0},_doCursorPrevious:function(j){var a=this._getSelection();if(!a.isEmpty()&&!j.select)a.end=a.start;else{if(!j.count)j.count=1;j.count*=-1;this._doMove(j,a)}j.select||a.collapse();this._setSelection(a,!0);
+return!0},_doCut:function(j){var a=this._getSelection();return!a.isEmpty()?(a=this._getBaseText(a.start,a.end),this._doContent(""),this._setClipboardText(a,j)):!0},_doDelete:function(j){var a=this._getSelection();a.isEmpty()&&this._doMove(j,a);this._modifyContent({text:"",start:a.start,end:a.end},!0);return!0},_doEnd:function(j){var a=this._getSelection(),b=this._model,e;if(j.ctrl)a.extend(b.getCharCount()),e=function(){};else{var c=a.getCaret(),l=b.getLineAtOffset(c);if(this._wrapMode){var f=this._getLine(l),
+c=f.getLineIndex(c),c=c===f.getLineCount()-1?b.getLineEnd(l):f.getLineStart(c+1)-1;f.destroy()}else j.count&&j.count>0&&(l=Math.min(l+j.count-1,b.getLineCount()-1)),c=b.getLineEnd(l);a.extend(c)}j.select||a.collapse();this._setSelection(a,!0,!0,e);return!0},_doEnter:function(j){var a=this._model,b=this._getSelection();this._doContent(a.getLineDelimiter());if(j&&j.noCursor)b.end=b.start,this._setSelection(b,!0);return!0},_doHome:function(j){var a=this._getSelection(),b=this._model,e;if(j.ctrl)a.extend(0),
+e=function(){};else{var c=a.getCaret(),l=b.getLineAtOffset(c);this._wrapMode?(b=this._getLine(l),c=b.getLineIndex(c),c=b.getLineStart(c),b.destroy()):c=b.getLineStart(l);a.extend(c)}j.select||a.collapse();this._setSelection(a,!0,!0,e);return!0},_doLineDown:function(j){var a=this._model,b=this._getSelection(),e=b.getCaret(),c=a.getLineAtOffset(e),l=this._getLine(c),d=this._columnX,o=1,g=!1;if(d===-1||j.wholeLine||j.select&&f.isIE)d=j.wholeLine?a.getLineEnd(c+1):e,d=l.getBoundingClientRect(d).left;
+(e=l.getLineIndex(e))<l.getLineCount()-1?o=l.getClientRects(e+1).top+1:(e=a.getLineCount()-1,g=c===e,j.count&&j.count>0?c=Math.min(c+j.count,e):c++);e=!1;if(g){if(j.select||f.isMac||f.isLinux)b.extend(a.getCharCount()),e=!0}else l.lineIndex!==c&&(l.destroy(),l=this._getLine(c)),b.extend(l.getOffset(d,o)),e=!0;e&&(j.select||b.collapse(),this._setSelection(b,!0,!0));this._columnX=d;l.destroy();return!0},_doLineUp:function(a){var b=this._model,e=this._getSelection(),c=e.getCaret(),l=b.getLineAtOffset(c),
+d=this._getLine(l),o=this._columnX,g=!1,h;if(o===-1||a.wholeLine||a.select&&f.isIE)o=a.wholeLine?b.getLineStart(l-1):c,o=d.getBoundingClientRect(o).left;(c=d.getLineIndex(c))>0?h=d.getClientRects(c-1).top+1:(g=l===0,g||(a.count&&a.count>0?l=Math.max(l-a.count,0):l--,h=this._getLineHeight(l)-1));c=!1;if(g){if(a.select||f.isMac||f.isLinux)e.extend(0),c=!0}else d.lineIndex!==l&&(d.destroy(),d=this._getLine(l)),e.extend(d.getOffset(o,h)),c=!0;c&&(a.select||e.collapse(),this._setSelection(e,!0,!0));this._columnX=
+o;d.destroy();return!0},_doNoop:function(){return!0},_doPageDown:function(a){var b=this,e=this._model,c=this._getSelection(),l=c.getCaret(),d=e.getLineAtOffset(l),o=e.getLineCount(),g=this._getScroll(),e=this._getClientHeight(),h,p;if(this._lineHeight){h=this._columnX;g=this._getBoundsAtOffset(l);if(h===-1||a.select&&f.isIE)h=g.left;l=this._getLineIndex(g.top+e);p=this._getLine(l);d=this._getLinePixel(l);l=p.getOffset(h,g.top+e-d);e=p.getBoundingClientRect(l);p.destroy();c.extend(l);a.select||c.collapse();
+this._setSelection(c,!0,!0,function(){b._columnX=h},e.top+d-g.top);return!0}if(d<o-1){var i=this._getLineHeight(),q=Math.min(o-d-1,Math.floor(e/i)),q=Math.max(1,q);h=this._columnX;if(h===-1||a.select&&f.isIE)p=this._getLine(d),h=p.getBoundingClientRect(l).left,p.destroy();p=this._getLine(d+q);c.extend(p.getOffset(h,0));p.destroy();a.select||c.collapse();a=o*i;l=g.y+q*i;l+e>a&&(l=a-e);this._setSelection(c,!0,!0,function(){b._columnX=h},l-g.y)}return!0},_doPageUp:function(a){var b=this,e=this._model,
+c=this._getSelection(),l=c.getCaret(),d=e.getLineAtOffset(l),o=this._getScroll(),g=this._getClientHeight(),h;if(this._lineHeight){h=this._columnX;o=this._getBoundsAtOffset(l);if(h===-1||a.select&&f.isIE)h=o.left;l=this._getLineIndex(o.bottom-g);e=this._getLine(l);d=this._getLinePixel(l);l=e.getOffset(h,o.bottom-g-d);g=e.getBoundingClientRect(l);e.destroy();c.extend(l);a.select||c.collapse();this._setSelection(c,!0,!0,function(){b._columnX=h},g.top+d-o.top);return!0}if(d>0){var p=this._getLineHeight(),
+g=Math.max(1,Math.min(d,Math.floor(g/p)));h=this._columnX;if(h===-1||a.select&&f.isIE)e=this._getLine(d),h=e.getBoundingClientRect(l).left,e.destroy();e=this._getLine(d-g);c.extend(e.getOffset(h,this._getLineHeight(d-g)-1));e.destroy();a.select||c.collapse();a=Math.max(0,o.y-g*p);this._setSelection(c,!0,!0,function(){b._columnX=h},a-o.y)}return!0},_doPaste:function(a){var b=this;return this._getClipboardText(a,function(a){a&&(f.isLinux&&b._lastMouseButton===2&&(new Date).getTime()-b._lastMouseTime<=
+b._clickTime&&b._setSelectionTo(b._lastMouseX,b._lastMouseY),b._doContent(a))})!==null},_doScroll:function(a){var b=a.type,e=this._model,c=e.getLineCount(),a=this._getClientHeight(),l=this._getLineHeight();c*=l;var f=this._getScroll().y,d;switch(b){case "textStart":d=0;break;case "textEnd":d=c-a;break;case "pageDown":d=f+a;break;case "pageUp":d=f-a;break;case "lineDown":d=f+l;break;case "lineUp":d=f-l;break;case "centerLine":b=this._getSelection(),d=e.getLineAtOffset(b.start),e=(e.getLineAtOffset(b.end)-
+d+1)*l,d=d*l-a/2+e/2}d!==void 0&&(d=Math.min(Math.max(0,d),c-a),this._scrollViewAnimated(0,d-f,function(){}));return!0},_doSelectAll:function(){var a=this._model,b=this._getSelection();b.setCaret(0);b.extend(a.getCharCount());this._setSelection(b,!1);return!0},_doTab:function(){if(this._tabMode&&!this._readonly){var a="\t";if(this._expandTab)var b=this._model,a=this._getSelection().getCaret(),e=b.getLineAtOffset(a),b=b.getLineStart(e),a=Array(this._tabSize-(a-b)%this._tabSize+1).join(" ");this._doContent(a);
+return!0}},_doShiftTab:function(){return!this._tabMode||this._readonly?void 0:!0},_doOverwriteMode:function(){if(!this._readonly)return this.setOptions({overwriteMode:!this.getOptions("overwriteMode")}),!0},_doTabMode:function(){this._tabMode=!this._tabMode;return!0},_doWrapMode:function(){this.setOptions({wrapMode:!this.getOptions("wrapMode")});return!0},_autoScroll:function(){var a=this._model,b=this._getSelection(),e=this.convert({x:this._autoScrollX,y:this._autoScrollY},"page","document"),c=b.getCaret(),
+l=a.getLineCount(),d=a.getLineAtOffset(c),o;if(this._autoScrollDir==="up"||this._autoScrollDir==="down")c=this._autoScrollY/this._getLineHeight(),c=c<0?Math.floor(c):Math.ceil(c),o=Math.max(0,Math.min(l-1,d+c));else if(this._autoScrollDir==="left"||this._autoScrollDir==="right")o=this._getLineIndex(e.y),d=this._getLine(d),e.x+=d.getBoundingClientRect(c,!1).left,d.destroy();o===0&&(f.isMac||f.isLinux)?b.extend(0):o===l-1&&(f.isMac||f.isLinux)?b.extend(a.getCharCount()):(d=this._getLine(o),b.extend(d.getOffset(e.x,
+e.y-this._getLinePixel(o))),d.destroy());this._setSelection(b,!0)},_autoScrollTimer:function(){this._autoScroll();var a=this;this._autoScrollTimerID=this._getWindow().setTimeout(function(){a._autoScrollTimer()},this._AUTO_SCROLL_RATE)},_calculateLineHeightTimer:function(a){if(this._lineHeight&&!this._calculateLHTimer){var b=this._model.getLineCount(),e=0;if(a){for(var a=0,c=(new Date).getTime(),l=0;e<b;)if(this._lineHeight[e]||(a++,l||(l=e),this._lineHeight[e]=this._calculateLineHeight(e)),e++,(new Date).getTime()-
+c>100)break;this.redrawRulers(0,b);this._queueUpdate()}a=this._getWindow();if(e!==b){var f=this;this._calculateLHTimer=a.setTimeout(function(){f._calculateLHTimer=null;f._calculateLineHeightTimer(!0)},0)}else if(this._calculateLHTimer)a.clearTimeout(this._calculateLHTimer),this._calculateLHTimer=void 0}},_calculateLineHeight:function(a){var a=this._getLine(a),b=a.getBoundingClientRect();a.destroy();return Math.max(1,b.bottom-b.top)},_calculateMetrics:function(){var a=this._clientDiv,b=a.ownerDocument,
+e=f.createElement(b,"div");e.style.lineHeight="normal";var c={type:"LineStyle",textView:this,0:0,lineText:this._model.getLine(0),lineStart:0};this.onLineStyle(c);g(c.style,e);e.style.position="fixed";e.style.left="-1000px";var d=f.createElement(b,"span");d.appendChild(b.createTextNode(" "));e.appendChild(d);var h=f.createElement(b,"span");h.style.fontStyle="italic";h.appendChild(b.createTextNode(" "));e.appendChild(h);var p=f.createElement(b,"span");p.style.fontWeight="bold";p.appendChild(b.createTextNode(" "));
+e.appendChild(p);c=f.createElement(b,"span");c.style.fontWeight="bold";c.style.fontStyle="italic";c.appendChild(b.createTextNode(" "));e.appendChild(c);a.appendChild(e);var i=e.getBoundingClientRect(),d=d.getBoundingClientRect(),h=h.getBoundingClientRect(),p=p.getBoundingClientRect(),c=c.getBoundingClientRect(),d=d.bottom-d.top,h=h.bottom-h.top,p=p.bottom-p.top,q=c.bottom-c.top,r=0,c=i.bottom-i.top<=0,i=Math.max(1,i.bottom-i.top);h>d&&(r=1);p>h&&(r=2);q>p&&(r=3);var s;if(r!==0){s={style:{}};if((r&
+1)!==0)s.style.fontStyle="italic";if((r&2)!==0)s.style.fontWeight="bold"}d=o(e);a.removeChild(e);q=l(this._viewDiv);e=f.createElement(b,"div");e.style.position="fixed";e.style.left="-1000px";e.style.paddingLeft=q.left+"px";e.style.paddingTop=q.top+"px";e.style.paddingRight=q.right+"px";e.style.paddingBottom=q.bottom+"px";e.style.width="100px";e.style.height="100px";q=f.createElement(b,"div");q.style.width="100%";q.style.height="100%";e.appendChild(q);a.appendChild(e);r=e.getBoundingClientRect();h=
+q.getBoundingClientRect();p=0;if(!this._singleMode)e.style.overflow="hidden",q.style.height="200px",p=e.clientWidth,e.style.overflow="scroll",p-=e.clientWidth;a.removeChild(e);q={left:h.left-r.left,top:h.top-r.top,right:r.right-h.right,bottom:r.bottom-h.bottom};h=r=0;if(!c&&(this._wrapOffset||this._marginOffset))e=f.createElement(b,"div"),e.style.position="fixed",e.style.left="-1000px",e.innerHTML=Array(this._wrapOffset+1).join(" "),a.appendChild(e),r=e.getBoundingClientRect(),r=Math.ceil(r.right-
+r.left),e.innerHTML=Array(this._marginOffset+1).join(" "),h=e.getBoundingClientRect(),h=Math.ceil(h.right-h.left),a.removeChild(e);return{lineHeight:i,largestFontStyle:s,lineTrim:d,viewPadding:q,scrollWidth:p,wrapWidth:r,marginWidth:h,invalid:c}},_cancelAnimation:function(){if(this._animation)this._animation.stop(),this._animation=null},_clearSelection:function(a){var b=this._getSelection();if(b.isEmpty())return!1;a==="next"?b.start=b.end:b.end=b.start;this._setSelection(b,!0);return!0},_commitIME:function(){if(this._imeOffset!==
+-1){this._scrollDiv.focus();this._clientDiv.focus();var a=this._model,b=a.getLineAtOffset(this._imeOffset),e=a.getLineStart(b),c=this._getDOMText(this._getLineNode(b)).text,a=a.getLine(b),e=this._imeOffset-e,a=e+c.length-a.length;e!==a&&this._doContent(c.substring(e,a));this._imeOffset=-1}},_createActions:function(){this.addKeyMode(new n.DefaultKeyMode(this));var a=this;this._actions={noop:{defaultHandler:function(){return a._doNoop()}},lineUp:{defaultHandler:function(e){return a._doLineUp(b(e,{select:!1}))},
+actionDescription:{name:k.lineUp}},lineDown:{defaultHandler:function(e){return a._doLineDown(b(e,{select:!1}))},actionDescription:{name:k.lineDown}},lineStart:{defaultHandler:function(e){return a._doHome(b(e,{select:!1,ctrl:!1}))},actionDescription:{name:k.lineStart}},lineEnd:{defaultHandler:function(e){return a._doEnd(b(e,{select:!1,ctrl:!1}))},actionDescription:{name:k.lineEnd}},charPrevious:{defaultHandler:function(e){return a._doCursorPrevious(b(e,{select:!1,unit:"character"}))},actionDescription:{name:k.charPrevious}},
+charNext:{defaultHandler:function(e){return a._doCursorNext(b(e,{select:!1,unit:"character"}))},actionDescription:{name:k.charNext}},pageUp:{defaultHandler:function(e){return a._doPageUp(b(e,{select:!1}))},actionDescription:{name:k.pageUp}},pageDown:{defaultHandler:function(e){return a._doPageDown(b(e,{select:!1}))},actionDescription:{name:k.pageDown}},scrollPageUp:{defaultHandler:function(e){return a._doScroll(b(e,{type:"pageUp"}))},actionDescription:{name:k.scrollPageUp}},scrollPageDown:{defaultHandler:function(e){return a._doScroll(b(e,
+{type:"pageDown"}))},actionDescription:{name:k.scrollPageDown}},scrollLineUp:{defaultHandler:function(e){return a._doScroll(b(e,{type:"lineUp"}))},actionDescription:{name:k.scrollLineUp}},scrollLineDown:{defaultHandler:function(e){return a._doScroll(b(e,{type:"lineDown"}))},actionDescription:{name:k.scrollLineDown}},wordPrevious:{defaultHandler:function(e){return a._doCursorPrevious(b(e,{select:!1,unit:"word"}))},actionDescription:{name:k.wordPrevious}},wordNext:{defaultHandler:function(e){return a._doCursorNext(b(e,
+{select:!1,unit:"word"}))},actionDescription:{name:k.wordNext}},textStart:{defaultHandler:function(e){return a._doHome(b(e,{select:!1,ctrl:!0}))},actionDescription:{name:k.textStart}},textEnd:{defaultHandler:function(e){return a._doEnd(b(e,{select:!1,ctrl:!0}))},actionDescription:{name:k.textEnd}},scrollTextStart:{defaultHandler:function(e){return a._doScroll(b(e,{type:"textStart"}))},actionDescription:{name:k.scrollTextStart}},scrollTextEnd:{defaultHandler:function(e){return a._doScroll(b(e,{type:"textEnd"}))},
+actionDescription:{name:k.scrollTextEnd}},centerLine:{defaultHandler:function(e){return a._doScroll(b(e,{type:"centerLine"}))},actionDescription:{name:k.centerLine}},selectLineUp:{defaultHandler:function(e){return a._doLineUp(b(e,{select:!0}))},actionDescription:{name:k.selectLineUp}},selectLineDown:{defaultHandler:function(e){return a._doLineDown(b(e,{select:!0}))},actionDescription:{name:k.selectLineDown}},selectWholeLineUp:{defaultHandler:function(e){return a._doLineUp(b(e,{select:!0,wholeLine:!0}))},
+actionDescription:{name:k.selectWholeLineUp}},selectWholeLineDown:{defaultHandler:function(e){return a._doLineDown(b(e,{select:!0,wholeLine:!0}))},actionDescription:{name:k.selectWholeLineDown}},selectLineStart:{defaultHandler:function(e){return a._doHome(b(e,{select:!0,ctrl:!1}))},actionDescription:{name:k.selectLineStart}},selectLineEnd:{defaultHandler:function(e){return a._doEnd(b(e,{select:!0,ctrl:!1}))},actionDescription:{name:k.selectLineEnd}},selectCharPrevious:{defaultHandler:function(e){return a._doCursorPrevious(b(e,
+{select:!0,unit:"character"}))},actionDescription:{name:k.selectCharPrevious}},selectCharNext:{defaultHandler:function(e){return a._doCursorNext(b(e,{select:!0,unit:"character"}))},actionDescription:{name:k.selectCharNext}},selectPageUp:{defaultHandler:function(e){return a._doPageUp(b(e,{select:!0}))},actionDescription:{name:k.selectPageUp}},selectPageDown:{defaultHandler:function(e){return a._doPageDown(b(e,{select:!0}))},actionDescription:{name:k.selectPageDown}},selectWordPrevious:{defaultHandler:function(e){return a._doCursorPrevious(b(e,
+{select:!0,unit:"word"}))},actionDescription:{name:k.selectWordPrevious}},selectWordNext:{defaultHandler:function(e){return a._doCursorNext(b(e,{select:!0,unit:"word"}))},actionDescription:{name:k.selectWordNext}},selectTextStart:{defaultHandler:function(e){return a._doHome(b(e,{select:!0,ctrl:!0}))},actionDescription:{name:k.selectTextStart}},selectTextEnd:{defaultHandler:function(e){return a._doEnd(b(e,{select:!0,ctrl:!0}))},actionDescription:{name:k.selectTextEnd}},deletePrevious:{defaultHandler:function(e){return a._doBackspace(b(e,
+{unit:"character"}))},actionDescription:{name:k.deletePrevious}},deleteNext:{defaultHandler:function(e){return a._doDelete(b(e,{unit:"character"}))},actionDescription:{name:k.deleteNext}},deleteWordPrevious:{defaultHandler:function(e){return a._doBackspace(b(e,{unit:"word"}))},actionDescription:{name:k.deleteWordPrevious}},deleteWordNext:{defaultHandler:function(e){return a._doDelete(b(e,{unit:"word"}))},actionDescription:{name:k.deleteWordNext}},deleteLineStart:{defaultHandler:function(e){return a._doBackspace(b(e,
+{unit:"line"}))},actionDescription:{name:k.deleteLineStart}},deleteLineEnd:{defaultHandler:function(e){return a._doDelete(b(e,{unit:"line"}))},actionDescription:{name:k.deleteLineEnd}},tab:{defaultHandler:function(){return a._doTab()},actionDescription:{name:k.tab}},shiftTab:{defaultHandler:function(){return a._doShiftTab()},actionDescription:{name:k.shiftTab}},enter:{defaultHandler:function(){return a._doEnter()},actionDescription:{name:k.enter}},enterNoCursor:{defaultHandler:function(e){return a._doEnter(b(e,
+{noCursor:!0}))},actionDescription:{name:k.enterNoCursor}},selectAll:{defaultHandler:function(){return a._doSelectAll()},actionDescription:{name:k.selectAll}},copy:{defaultHandler:function(){return a._doCopy()},actionDescription:{name:k.copy}},cut:{defaultHandler:function(){return a._doCut()},actionDescription:{name:k.cut}},paste:{defaultHandler:function(){return a._doPaste()},actionDescription:{name:k.paste}},uppercase:{defaultHandler:function(e){return a._doCase(b(e,{type:"upper"}))},actionDescription:{name:k.uppercase}},
+lowercase:{defaultHandler:function(e){return a._doCase(b(e,{type:"lower"}))},actionDescription:{name:k.lowercase}},capitalize:{defaultHandler:function(e){return a._doCase(b(e,{unit:"word",type:"capitalize"}))},actionDescription:{name:k.capitalize}},reversecase:{defaultHandler:function(e){return a._doCase(b(e,{type:"reverse"}))},actionDescription:{name:k.reversecase}},toggleOverwriteMode:{defaultHandler:function(){return a._doOverwriteMode()},actionDescription:{name:k.toggleOverwriteMode}},toggleTabMode:{defaultHandler:function(){return a._doTabMode()},
+actionDescription:{name:k.toggleTabMode}},toggleWrapMode:{defaultHandler:function(){return a._doWrapMode()},actionDescription:{name:k.toggleWrapMode}}}},_createRulerParent:function(a){var b=f.createElement(document,"div");b.className=a;b.tabIndex=-1;b.style.overflow="hidden";b.style.MozUserSelect="none";b.style.WebkitUserSelect="none";b.style.position="absolute";b.style.top="0px";b.style.bottom="0px";b.style.cursor="default";b.style.display="none";b.setAttribute("aria-hidden","true");this._rootDiv.appendChild(b);
+return b},_createRuler:function(a,b){if(this._clientDiv){var e=this._getRulerParent(a);if(e){if(e!==this._marginDiv||this._marginOffset)e.style.display="block";var c=f.createElement(e.ownerDocument,"div");c._ruler=a;c.rulerChanged=!0;c.style.position="relative";c.style.cssFloat="left";c.style.styleFloat="left";c.style.outline="none";if(b===void 0||b<0||b>=e.children.length)e.appendChild(c);else{for(var l=e.firstChild;l&&b-- >0;)l=l.nextSibling;e.insertBefore(c,l)}}}},_createView:function(){if(!this._clientDiv){for(var a=
+this._parent;a.hasChildNodes();)a.removeChild(a.lastChild);var b=a.ownerDocument,e=f.createElement(b,"div");this._rootDiv=e;e.tabIndex=-1;e.style.position="relative";e.style.overflow="hidden";e.style.width="100%";e.style.height="100%";e.style.overflow="hidden";e.style.WebkitTextSizeAdjust="100%";e.setAttribute("role","application");a.appendChild(e);this._leftDiv=this._createRulerParent("textviewLeftRuler");a=f.createElement(b,"div");a.className="textviewScroll";this._viewDiv=a;a.tabIndex=-1;a.style.position=
+"absolute";a.style.top="0px";a.style.bottom="0px";a.style.borderWidth="0px";a.style.margin="0px";a.style.outline="none";a.style.background="transparent";if(f.isMac&&f.isWebkit)a.style.pointerEvents="none",a.style.zIndex="2";e.appendChild(a);var c=this._createRulerParent("textviewRightRuler");this._rightDiv=c;c.style.right="0px";this._scrollDiv=c=f.createElement(b,"div");c.style.margin="0px";c.style.borderWidth="0px";c.style.padding="0px";a.appendChild(c);(this._marginDiv=this._createRulerParent("textviewMarginRuler")).style.zIndex=
+"4";if(!f.isIE&&!f.isIOS)this._clipDiv=a=f.createElement(b,"div"),a.style.position="absolute",a.style.overflow="hidden",a.style.margin="0px",a.style.borderWidth="0px",a.style.padding="0px",a.style.background="transparent",e.appendChild(a),this._clipScrollDiv=c=f.createElement(b,"div"),c.style.position="absolute",c.style.height="1px",c.style.top="-1000px",c.style.background="transparent",a.appendChild(c);this._setFullSelection(this._fullSelection,!0);a=f.createElement(b,"div");a.className="textviewContent";
+this._clientDiv=a;a.tabIndex=0;a.style.position="absolute";a.style.borderWidth="0px";a.style.margin="0px";a.style.padding="0px";a.style.outline="none";a.style.zIndex="1";a.style.WebkitUserSelect="text";a.setAttribute("spellcheck","false");if(f.isIOS||f.isAndroid)a.style.WebkitTapHighlightColor="transparent";(this._clipDiv||e).appendChild(a);if(f.isIOS||f.isAndroid)this._vScrollDiv=c=f.createElement(b,"div"),c.style.position="absolute",c.style.borderWidth="1px",c.style.borderColor="white",c.style.borderStyle=
+"solid",c.style.borderRadius="4px",c.style.backgroundColor="black",c.style.opacity="0.5",c.style.margin="0px",c.style.padding="0px",c.style.outline="none",c.style.zIndex="3",c.style.width="8px",c.style.display="none",e.appendChild(c),this._hScrollDiv=c=f.createElement(b,"div"),c.style.position="absolute",c.style.borderWidth="1px",c.style.borderColor="white",c.style.borderStyle="solid",c.style.borderRadius="4px",c.style.backgroundColor="black",c.style.opacity="0.5",c.style.margin="0px",c.style.padding=
+"0px",c.style.outline="none",c.style.zIndex="3",c.style.height="8px",c.style.display="none",e.appendChild(c);if(f.isFirefox&&!a.setCapture)this._overlayDiv=b=f.createElement(b,"div"),b.style.position=a.style.position,b.style.borderWidth=a.style.borderWidth,b.style.margin=a.style.margin,b.style.padding=a.style.padding,b.style.cursor="text",b.style.zIndex="2",(this._clipDiv||e).appendChild(b);a.contentEditable="true";a.setAttribute("role","textbox");a.setAttribute("aria-multiline","true");this._setWrapMode(this._wrapMode,
+!0);this._setReadOnly(this._readonly);this._setThemeClass(this._themeClass,!0);this._setTabSize(this._tabSize,!0);this._setMarginOffset(this._marginOffset,!0);this._hookEvents();e=this._rulers;for(b=0;b<e.length;b++)this._createRuler(e[b]);this._update()}},_defaultOptions:function(){return{parent:{value:void 0,update:null},model:{value:void 0,update:this.setModel},scrollAnimation:{value:0,update:null},readonly:{value:!1,update:this._setReadOnly},fullSelection:{value:!0,update:this._setFullSelection},
+tabMode:{value:!0,update:null},tabSize:{value:8,update:this._setTabSize},expandTab:{value:!1,update:null},singleMode:{value:!1,update:this._setSingleMode},overwriteMode:{value:!1,update:this._setOverwriteMode},blockCursorVisible:{value:!1,update:this._setBlockCursor},marginOffset:{value:0,update:this._setMarginOffset},wrapOffset:{value:0,update:this._setWrapOffset},wrapMode:{value:!1,update:this._setWrapMode},wrappable:{value:!1,update:null},theme:{value:c.TextTheme.getTheme(),update:this._setTheme},
+themeClass:{value:void 0,update:this._setThemeClass}}},_destroyRuler:function(a){var b=this._getRulerParent(a);if(b)for(var e=b.firstChild;e;){if(e._ruler===a){e._ruler=void 0;b.removeChild(e);if(b.children.length===0&&(b!==this._marginDiv||!this._marginOffset))b.style.display="none";break}e=e.nextSibling}},_destroyView:function(){if(this._clientDiv){this._setGrab(null);this._unhookEvents();var a=this._getWindow();if(this._autoScrollTimerID)a.clearTimeout(this._autoScrollTimerID),this._autoScrollTimerID=
+null;if(this._updateTimer)a.clearTimeout(this._updateTimer),this._updateTimer=null;a=this._rootDiv;a.parentNode.removeChild(a);this._hScrollDiv=this._vScrollDiv=this._cursorDiv=this._marginDiv=this._rightDiv=this._leftDiv=this._overlayDiv=this._clientDiv=this._clipScrollDiv=this._clipDiv=this._viewDiv=this._scrollDiv=this._rootDiv=this._clipboardDiv=this._selDiv3=this._selDiv2=this._selDiv1=null}},_doAutoScroll:function(a,b,e){this._autoScrollDir=a;this._autoScrollX=b;this._autoScrollY=e;this._autoScrollTimerID||
+this._autoScrollTimer()},_endAutoScroll:function(){this._autoScrollTimerID&&this._getWindow().clearTimeout(this._autoScrollTimerID);this._autoScrollTimerID=this._autoScrollDir=void 0},_fixCaret:function(){var a=this._clientDiv;if(a){var b=this._hasFocus;this._ignoreFocus=!0;b&&a.blur();a.contentEditable=!1;a.contentEditable=!0;b&&a.focus();this._ignoreFocus=!1}},_getBaseText:function(a,b){var e=this._model;e.getBaseModel&&(a=e.mapOffset(a),b=e.mapOffset(b),e=e.getBaseModel());return e.getText(a,b)},
+_getBottomIndex:function(a){var b=this._bottomChild;if(a&&this._getClientHeight()>this._getLineHeight()){var a=b.getBoundingClientRect(),e=this._clientDiv.getBoundingClientRect();a.bottom>e.bottom&&(b=this._getLinePrevious(b)||b)}return b.lineIndex},_getBoundsAtOffset:function(a){var b=this._getLine(this._model.getLineAtOffset(a)),a=b.getBoundingClientRect(a),e=this._getLinePixel(b.lineIndex);a.top+=e;a.bottom+=e;b.destroy();return a},_getClientHeight:function(){var a=this._getViewPadding();return Math.max(0,
+this._viewDiv.clientHeight-a.top-a.bottom)},_getClientWidth:function(){var a=this._getViewPadding();return Math.max(0,this._viewDiv.clientWidth-a.left-a.right)},_getClipboardText:function(a,b){var c=this._model.getLineDelimiter(),l,d,o=this._getWindow(),g=o.clipboardData;if(!g&&a)g=a.clipboardData;if(g)return l=[],d=g.getData(f.isIE?"Text":"text/plain"),e(d,function(a){l.push(a)},function(){l.push(c)}),d=l.join(""),b&&b(d),d;if(f.isFirefox){this._ignoreFocus=!0;var h=this._clipboardDiv,g=this._rootDiv.ownerDocument;
+if(!h)this._clipboardDiv=h=f.createElement(g,"div"),h.style.position="fixed",h.style.whiteSpace="pre",h.style.left="-1000px",this._rootDiv.appendChild(h);h.innerHTML="<pre contenteditable=''></pre>";h.firstChild.focus();var p=this,i=function(){var a=p._getTextFromElement(h);h.innerHTML="";l=[];e(a,function(a){l.push(a)},function(){l.push(c)});return l.join("")},q=!1;this._ignorePaste=!0;if(!f.isLinux||this._lastMouseButton!==2)try{q=g.execCommand("paste",!1,null)}catch(r){q=h.childNodes.length>1||
+h.firstChild&&h.firstChild.childNodes.length>0}this._ignorePaste=!1;if(!q)return a?(o.setTimeout(function(){p.focus();(d=i())&&b&&b(d);p._ignoreFocus=!1},0),null):(this.focus(),this._ignoreFocus=!1,"");this.focus();this._ignoreFocus=!1;(d=i())&&b&&b(d);return d}return""},_getDOMText:function(a,b){for(var e=a.firstChild,c="",l=0;e;){var f;if(!e.ignore)if(e.ignoreChars){f=e.lastChild;for(var d=0,o=[],g=-1;f;){var h=f.data;if(h)for(var p=h.length-1;p>=0;p--){var i=h.substring(p,p+1);d<e.ignoreChars&&
+(i===" "||i==="\u200b"||i==="\ufeff")?d++:o.push(i==="\u00a0"?"\t":i)}if(b===f)g=o.length;f=f.previousSibling}o=o.reverse().join("");g!==-1&&(l=c.length+o.length-g);c+=o}else for(f=e.firstChild;f;){if(b===f)l=c.length;c+=f.data;f=f.nextSibling}e=e.nextSibling}return{text:c,offset:l}},_getTextFromElement:function(a){var b=a.ownerDocument,e=b.defaultView;if(!e.getSelection)return a.innerText||a.textContent;b=b.createRange();b.selectNode(a);var a=e.getSelection(),e=[],c;for(c=0;c<a.rangeCount;c++)e.push(a.getRangeAt(c));
+this._ignoreSelect=!0;a.removeAllRanges();a.addRange(b);b=a.toString();a.removeAllRanges();for(c=0;c<e.length;c++)a.addRange(e[c]);this._ignoreSelect=!1;return b},_getViewPadding:function(){return this._metrics.viewPadding},_getLine:function(a){var b=this._getLineNode(a);return b&&!b.lineChanged&&!b.lineRemoved?b._line:new p(this,a)},_getLineHeight:function(a,b){if(a!==void 0&&this._lineHeight){var e=this._lineHeight[a];if(e)return e;if(b||b===void 0)return this._lineHeight[a]=this._calculateLineHeight(a)}return this._metrics.lineHeight},
+_getLineNode:function(a){for(var b=this._clientDiv.firstChild;b;){if(a===b.lineIndex)return b;b=b.nextSibling}},_getLineNext:function(a){for(a=a?a.nextSibling:this._clientDiv.firstChild;a&&a.lineIndex===-1;)a=a.nextSibling;return a},_getLinePrevious:function(a){for(a=a?a.previousSibling:this._clientDiv.lastChild;a&&a.lineIndex===-1;)a=a.previousSibling;return a},_getLinePixel:function(a){a=Math.min(Math.max(0,a),this._model.getLineCount());if(this._lineHeight){var b=this._getTopIndex(),e=-this._topIndexY+
+this._getScroll().y;if(a>b)for(;b<a;b++)e+=this._getLineHeight(b);else for(b-=1;b>=a;b--)e-=this._getLineHeight(b);return e}return this._getLineHeight()*a},_getLineIndex:function(a){var b,e=0,c=this._model.getLineCount();if(this._lineHeight){var e=this._getTopIndex(),l=-this._topIndexY+this._getScroll().y;if(a!==l)if(a<l)for(;a<l&&e>0;)a+=this._getLineHeight(--e);else for(b=this._getLineHeight(e);a-b>=l&&e<c-1;)a-=b,b=this._getLineHeight(++e)}else b=this._getLineHeight(),e=Math.floor(a/b);return Math.max(0,
+Math.min(c-1,e))},_getRulerParent:function(a){switch(a.getLocation()){case "left":return this._leftDiv;case "right":return this._rightDiv;case "margin":return this._marginDiv}return null},_getScroll:function(a){(a===void 0||a)&&this._cancelAnimation();a=this._viewDiv;return{x:a.scrollLeft,y:a.scrollTop}},_getSelection:function(){return this._selection.clone()},_getTopIndex:function(a){var b=this._topChild;if(a&&this._getClientHeight()>this._getLineHeight()){var a=b.getBoundingClientRect(),e=this._getViewPadding(),
+c=this._viewDiv.getBoundingClientRect();a.top<c.top+e.top&&(b=this._getLineNext(b)||b)}return b.lineIndex},_hookEvents:function(){var a=this;this._modelListener={onChanging:function(b){a._onModelChanging(b)},onChanged:function(b){a._onModelChanged(b)}};this._model.addEventListener("preChanging",this._modelListener.onChanging);this._model.addEventListener("postChanged",this._modelListener.onChanged);this._themeListener={onChanged:function(){a._setThemeClass(a._themeClass)}};this._theme.addEventListener("ThemeChanged",
+this._themeListener.onChanged);var b=this._handlers=[],e=this._clientDiv,c=this._viewDiv,l=this._rootDiv,d=this._overlayDiv||e,o=e.ownerDocument,g=this._getWindow(),h=f.isIE?o:g;b.push({target:g,type:"resize",handler:function(b){return a._handleResize(b?b:g.event)}});b.push({target:e,type:"blur",handler:function(b){return a._handleBlur(b?b:g.event)}});b.push({target:e,type:"focus",handler:function(b){return a._handleFocus(b?b:g.event)}});b.push({target:c,type:"focus",handler:function(){e.focus()}});
+b.push({target:c,type:"scroll",handler:function(b){return a._handleScroll(b?b:g.event)}});b.push({target:e,type:"textInput",handler:function(b){return a._handleTextInput(b?b:g.event)}});b.push({target:e,type:"keydown",handler:function(b){return a._handleKeyDown(b?b:g.event)}});b.push({target:e,type:"keypress",handler:function(b){return a._handleKeyPress(b?b:g.event)}});b.push({target:e,type:"keyup",handler:function(b){return a._handleKeyUp(b?b:g.event)}});f.isIE&&b.push({target:o,type:"keyup",handler:function(b){return a._handleDocKeyUp(b?
+b:g.event)}});b.push({target:e,type:"contextmenu",handler:function(b){return a._handleContextMenu(b?b:g.event)}});b.push({target:e,type:"copy",handler:function(b){return a._handleCopy(b?b:g.event)}});b.push({target:e,type:"cut",handler:function(b){return a._handleCut(b?b:g.event)}});b.push({target:e,type:"paste",handler:function(b){return a._handlePaste(b?b:g.event)}});if(f.isIOS||f.isAndroid)b.push({target:o,type:"selectionchange",handler:function(b){return a._handleSelectionChange(b?b:g.event)}}),
+b.push({target:e,type:"touchstart",handler:function(b){return a._handleTouchStart(b?b:g.event)}}),b.push({target:e,type:"touchmove",handler:function(b){return a._handleTouchMove(b?b:g.event)}}),b.push({target:e,type:"touchend",handler:function(b){return a._handleTouchEnd(b?b:g.event)}});else{b.push({target:e,type:"selectstart",handler:function(b){return a._handleSelectStart(b?b:g.event)}});b.push({target:e,type:"mousedown",handler:function(b){return a._handleMouseDown(b?b:g.event)}});b.push({target:e,
+type:"mouseover",handler:function(b){return a._handleMouseOver(b?b:g.event)}});b.push({target:e,type:"mouseout",handler:function(b){return a._handleMouseOut(b?b:g.event)}});b.push({target:h,type:"mouseup",handler:function(b){return a._handleMouseUp(b?b:g.event)}});b.push({target:h,type:"mousemove",handler:function(b){return a._handleMouseMove(b?b:g.event)}});b.push({target:l,type:"mousedown",handler:function(b){return a._handleRootMouseDown(b?b:g.event)}});b.push({target:l,type:"mouseup",handler:function(b){return a._handleRootMouseUp(b?
+b:g.event)}});b.push({target:d,type:"dragstart",handler:function(b){return a._handleDragStart(b?b:g.event)}});b.push({target:d,type:"drag",handler:function(b){return a._handleDrag(b?b:g.event)}});b.push({target:d,type:"dragend",handler:function(b){return a._handleDragEnd(b?b:g.event)}});b.push({target:d,type:"dragenter",handler:function(b){return a._handleDragEnter(b?b:g.event)}});b.push({target:d,type:"dragover",handler:function(b){return a._handleDragOver(b?b:g.event)}});b.push({target:d,type:"dragleave",
+handler:function(b){return a._handleDragLeave(b?b:g.event)}});b.push({target:d,type:"drop",handler:function(b){return a._handleDrop(b?b:g.event)}});b.push({target:this._clientDiv,type:f.isFirefox?"DOMMouseScroll":"mousewheel",handler:function(b){return a._handleMouseWheel(b?b:g.event)}});this._clipDiv&&b.push({target:this._clipDiv,type:f.isFirefox?"DOMMouseScroll":"mousewheel",handler:function(b){return a._handleMouseWheel(b?b:g.event)}});if(f.isFirefox&&(!f.isWindows||f.isFirefox>=15))(c=g.MutationObserver||
+g.MozMutationObserver)?(this._mutationObserver=new c(function(b){a._handleDataModified(b)}),this._mutationObserver.observe(e,{subtree:!0,characterData:!0})):b.push({target:this._clientDiv,type:"DOMCharacterDataModified",handler:function(b){return a._handleDataModified(b?b:g.event)}});this._overlayDiv&&(b.push({target:this._overlayDiv,type:"mousedown",handler:function(b){return a._handleMouseDown(b?b:g.event)}}),b.push({target:this._overlayDiv,type:"mouseover",handler:function(b){return a._handleMouseOver(b?
+b:g.event)}}),b.push({target:this._overlayDiv,type:"mouseout",handler:function(b){return a._handleMouseOut(b?b:g.event)}}),b.push({target:this._overlayDiv,type:"contextmenu",handler:function(b){return a._handleContextMenu(b?b:g.event)}}));this._isW3CEvents||b.push({target:this._clientDiv,type:"dblclick",handler:function(b){return a._handleDblclick(b?b:g.event)}})}this._hookRulerEvents(this._leftDiv,b);this._hookRulerEvents(this._rightDiv,b);this._hookRulerEvents(this._marginDiv,b);for(c=0;c<b.length;c++)l=
+b[c],v(l.target,l.type,l.handler,l.capture)},_hookRulerEvents:function(a,b){if(a){var e=this,c=this._getWindow();f.isIE&&b.push({target:a,type:"selectstart",handler:function(){return!1}});b.push({target:a,type:f.isFirefox?"DOMMouseScroll":"mousewheel",handler:function(a){return e._handleMouseWheel(a?a:c.event)}});b.push({target:a,type:"click",handler:function(a){e._handleRulerEvent(a?a:c.event)}});b.push({target:a,type:"dblclick",handler:function(a){e._handleRulerEvent(a?a:c.event)}});b.push({target:a,
+type:"mousemove",handler:function(a){e._handleRulerEvent(a?a:c.event)}});b.push({target:a,type:"mouseover",handler:function(a){e._handleRulerEvent(a?a:c.event)}});b.push({target:a,type:"mouseout",handler:function(a){e._handleRulerEvent(a?a:c.event)}})}},_getWindow:function(){return this._parent.ownerDocument.defaultView||this._parent.ownerDocument.parentWindow},_ignoreEvent:function(a){for(a=a.target;a&&a!==this._clientDiv;){if(a.ignore)return!0;a=a.parentNode}return!1},_init:function(a){var b=a.parent;
+typeof b==="string"&&(b=(a.document||document).getElementById(b));if(!b)throw"no parent";a.parent=b;a.model=a.model||new m.TextModel;var e=this._defaultOptions(),c;for(c in e)e.hasOwnProperty(c)&&(this["_"+c]=a[c]!==void 0?a[c]:e[c].value);this._keyModes=[];this._rulers=[];this._selection=new q(0,0,!1);this._linksVisible=!1;this._maxLineWidth=this._redrawCount=0;this._maxLineIndex=-1;this._ignoreSelect=!0;this._hasFocus=this._ignoreFocus=!1;this._dragOffset=this._columnX=-1;this._isRangeRects=(!f.isIE||
+f.isIE>=9)&&typeof b.ownerDocument.createRange().getBoundingClientRect==="function";this._isW3CEvents=b.addEventListener;this._autoScrollTimerID=this._autoScrollY=this._autoScrollX=null;this._AUTO_SCROLL_RATE=50;this._mouseUpClosure=this._moseMoveClosure=this._grabControl=null;this._clickCount=this._lastMouseTime=this._lastMouseY=this._lastMouseX=0;this._clickTime=250;this._clickDist=5;this._isMouseDown=!1;this._doubleClickSelection=null;this._vScroll=this._hScroll=0;this._imeOffset=-1;this._createActions();
+this._createView()},_modifyContent:function(a,b){if(!this._readonly||a._code)if(a.type="Verify",this.onVerify(a),!(a.text===null||a.text===void 0)){var e=this._model;try{if(a._ignoreDOMSelection)this._ignoreDOMSelection=!0;e.setText(a.text,a.start,a.end)}finally{if(a._ignoreDOMSelection)this._ignoreDOMSelection=!1}b&&(e=this._getSelection(),e.setCaret(a.start+a.text.length),this._setSelection(e,!0));this.onModify({type:"Modify"})}},_onModelChanged:function(a){a.type="ModelChanged";this.onModelChanged(a);
+a.type="Changed";var b=a.start,e=a.addedCharCount,c=a.removedCharCount,l=a.addedLineCount,f=a.removedLineCount,d=this._getSelection();d.end>b&&(d.end>b&&d.start<b+c?d.setCaret(b+e):(d.start+=e-c,d.end+=e-c),this._setSelection(d,!1,!1));b=this._model.getLineAtOffset(b);for(e=this._getLineNext();e;){c=e.lineIndex;if(b<=c&&c<=b+f)b===c&&!e.modelChangedEvent&&!e.lineRemoved?(e.modelChangedEvent=a,e.lineChanged=!0):(e.lineRemoved=!0,e.lineChanged=!1,e.modelChangedEvent=null);if(c>b+f)e.lineIndex=c+l-f,
+e._line.lineIndex=e.lineIndex;e=this._getLineNext(e)}this._lineHeight&&(a=[b,f].concat(Array(l)),Array.prototype.splice.apply(this._lineHeight,a));if(!this._wrapMode&&b<=this._maxLineIndex&&this._maxLineIndex<=b+f)this._checkMaxLineIndex=this._maxLineIndex,this._maxLineIndex=-1,this._maxLineWidth=0;this._update()},_onModelChanging:function(a){a.type="ModelChanging";this.onModelChanging(a);a.type="Changing"},_queueUpdate:function(){if(!this._updateTimer&&!this._ignoreQueueUpdate){var a=this;this._updateTimer=
+this._getWindow().setTimeout(function(){a._updateTimer=null;a._update()},0)}},_resetLineHeight:function(a,b){if(this._wrapMode||this._variableLineHeight){if(a!==void 0&&b!==void 0)for(var e=a;e<b;e++)this._lineHeight[e]=void 0;else this._lineHeight=Array(this._model.getLineCount());this._calculateLineHeightTimer()}else this._lineHeight=null},_resetLineWidth:function(){var a=this._clientDiv;if(a)for(a=a.firstChild;a;)a.lineWidth=void 0,a=a.nextSibling},_reset:function(){this._maxLineIndex=-1;this._maxLineWidth=
+0;this._columnX=-1;this._bottomChild=this._topChild=null;this._topIndexY=0;this._variableLineHeight=!1;this._resetLineHeight();this._setSelection(new q(0,0,!1),!1,!1);if(this._viewDiv)this._viewDiv.scrollLeft=0,this._viewDiv.scrollTop=0;var a=this._clientDiv;if(a){for(var b=a.firstChild;b;)b.lineRemoved=!0,b=b.nextSibling;if(f.isFirefox)this._ignoreFocus=!1,(b=this._hasFocus)&&a.blur(),a.contentEditable=!1,a.contentEditable=!0,b&&a.focus(),this._ignoreFocus=!1}},_scrollViewAnimated:function(a,b,e){var c=
+this._getWindow();if(e&&this._scrollAnimation){var l=this;this._animation=new u({window:c,duration:this._scrollAnimation,curve:[b,0],onAnimate:function(a){a=b-Math.floor(a);l._scrollView(0,a);b-=a},onEnd:function(){l._animation=null;l._scrollView(a,b);e&&c.setTimeout(e,0)}});this._animation.play()}else this._scrollView(a,b),e&&c.setTimeout(e,0)},_scrollView:function(a,b){this._ensureCaretVisible=!1;var e=this._viewDiv;a&&(e.scrollLeft+=a);b&&(e.scrollTop+=b)},_setClipboardText:function(a,b){var c,
+l=this._getWindow(),d=l.clipboardData;if(!d&&b)d=b.clipboardData;if(d&&(c=[],e(a,function(a){c.push(a)},function(){c.push(f.platformDelimiter)}),d.setData(f.isIE?"Text":"text/plain",c.join(""))))return!0;var o=this._parent.ownerDocument,g=f.createElement(o,"pre");g.style.position="fixed";g.style.left="-1000px";e(a,function(a){g.appendChild(o.createTextNode(a))},function(){g.appendChild(f.createElement(o,"br"))});g.appendChild(o.createTextNode(" "));this._clientDiv.appendChild(g);d=o.createRange();
+d.setStart(g.firstChild,0);d.setEndBefore(g.lastChild);var h=l.getSelection();h.rangeCount>0&&h.removeAllRanges();h.addRange(d);var p=this,d=function(){g&&g.parentNode===p._clientDiv&&p._clientDiv.removeChild(g);p._updateDOMSelection()},h=!1;this._ignoreCopy=!0;try{h=o.execCommand("copy",!1,null)}catch(i){}this._ignoreCopy=!1;if(!h&&b)return l.setTimeout(d,0),!1;d();return!0},_setDOMSelection:function(a,b,e,c,l){for(var d,o,g,h,p=0,i=a.firstChild,q,r,s=this._model.getLine(a.lineIndex).length;i;){if(!i.ignore){q=
+i.firstChild;r=q.length;i.ignoreChars&&(r-=i.ignoreChars);if(p+r>b||p+r>=s){d=q;o=b-p;i.ignoreChars&&r>0&&o===r&&(o+=i.ignoreChars);break}p+=r}i=i.nextSibling}for(var p=0,i=e.firstChild,t=this._model.getLine(e.lineIndex).length;i;){if(!i.ignore){q=i.firstChild;r=q.length;i.ignoreChars&&(r-=i.ignoreChars);if(r+p>c||p+r>=t){g=q;h=c-p;i.ignoreChars&&r>0&&h===r&&(h+=i.ignoreChars);break}p+=r}i=i.nextSibling}this._setDOMFullSelection(a,b,s,e,c,t);a=this._getWindow();b=this._parent.ownerDocument;if(a.getSelection){e=
+a.getSelection();a=b.createRange();a.setStart(d,o);a.setEnd(g,h);if(this._hasFocus&&(e.anchorNode!==d||e.anchorOffset!==o||e.focusNode!==g||e.focusOffset!==h||e.anchorNode!==g||e.anchorOffset!==h||e.focusNode!==d||e.focusOffset!==o))this._anchorNode=d,this._anchorOffset=o,this._focusNode=g,this._focusOffset=h,this._ignoreSelect=!1,e.rangeCount>0&&e.removeAllRanges(),e.addRange(a),this._ignoreSelect=!0;if(this._cursorDiv&&(a=b.createRange(),l?(a.setStart(d,o),a.setEnd(d,o)):(a.setStart(g,h),a.setEnd(g,
+h)),g=a.getClientRects()[0],h=this._cursorDiv.parentNode,d=h.getBoundingClientRect(),g&&d))this._cursorDiv.style.top=g.top-d.top+h.scrollTop+"px",this._cursorDiv.style.left=g.left-d.left+h.scrollLeft+"px"}else if(b.selection&&this._hasFocus)l=b.body,a=f.createElement(b,"div"),l.appendChild(a),l.removeChild(a),a=l.createTextRange(),a.moveToElementText(d.parentNode),a.moveStart("character",o),d=l.createTextRange(),d.moveToElementText(g.parentNode),d.moveStart("character",h),a.setEndPoint("EndToStart",
+d),this._ignoreSelect=!1,a.select(),this._ignoreSelect=!0},_setDOMFullSelection:function(a,b,e,c,l){if(this._selDiv1&&(e=this._selDiv1,e.style.width="0px",e.style.height="0px",e=this._selDiv2,e.style.width="0px",e.style.height="0px",e=this._selDiv3,e.style.width="0px",e.style.height="0px",!(a===c&&b===l))){var f=this._model,d=this._getViewPadding(),o=this._clientDiv.getBoundingClientRect(),g=this._viewDiv.getBoundingClientRect(),e=g.left+d.left,h=o.right,d=g.top+d.top,i=o.bottom,g=o=0;this._clipDiv?
+(g=this._clipDiv.getBoundingClientRect(),o=g.left-this._clipDiv.scrollLeft):(g=this._rootDiv.getBoundingClientRect(),o=g.left);g=g.top;this._ignoreDOMSelection=!0;var q=(new p(this,a.lineIndex,a)).getBoundingClientRect(f.getLineStart(a.lineIndex)+b,!1),r=q.left,b=(new p(this,c.lineIndex,c)).getBoundingClientRect(f.getLineStart(c.lineIndex)+l,!1),f=b.left;this._ignoreDOMSelection=!1;var s=this._selDiv1,r=Math.min(h,Math.max(e,r)),t=Math.min(i,Math.max(d,q.top)),u=h,l=Math.min(i,Math.max(d,q.bottom));
+s.style.left=r-o+"px";s.style.top=t-g+"px";s.style.width=Math.max(0,u-r)+"px";s.style.height=Math.max(0,l-t)+"px";if(a.lineIndex===c.lineIndex)u=Math.min(f,h),s.style.width=Math.max(0,u-r)+"px";else if(q=Math.min(i,Math.max(d,b.top)),f=Math.min(h,Math.max(e,f)),d=Math.min(i,Math.max(d,b.bottom)),i=this._selDiv3,i.style.left=e-o+"px",i.style.top=q-g+"px",i.style.width=Math.max(0,f-e)+"px",i.style.height=Math.max(0,d-q)+"px",Math.abs(a.lineIndex-c.lineIndex)>1)a=this._selDiv2,a.style.left=e-o+"px",
+a.style.top=l-g+"px",a.style.width=Math.max(0,h-e)+"px",a.style.height=Math.max(0,q-l)+"px"}},_setGrab:function(a){if(a!==this._grabControl)a?(a.setCapture&&a.setCapture(),this._grabControl=a):(this._grabControl.releaseCapture&&this._grabControl.releaseCapture(),this._grabControl=null)},_setLinksVisible:function(a){if(this._linksVisible!==a){this._linksVisible=a;if(f.isIE&&a)this._hadFocus=this._hasFocus;var b=this._clientDiv;b.contentEditable=!a;this._hadFocus&&!a&&b.focus();if(this._overlayDiv)this._overlayDiv.style.zIndex=
+a?"-1":"1";for(a=this._getLineNext();a;){if(a.hasLink)for(b=a.firstChild;b;)if(b.ignore)b=b.nextSibling;else{var e=b.nextSibling,c=b.viewStyle;c&&c.tagName&&c.tagName.toLowerCase()==="a"&&a.replaceChild(a._line._createSpan(a,b.firstChild.data,c),b);b=e}a=this._getLineNext(a)}this._updateDOMSelection()}},_setSelection:function(a,b,e,c,l){if(a){this._columnX=-1;e===void 0&&(e=!0);var f=this._selection;this._selection=a;b!==!1&&this._showCaret(!1,c,b,l);e&&this._updateDOMSelection();if(!f.equals(a))this.onSelection({type:"Selection",
+oldValue:{start:f.start,end:f.end},newValue:{start:a.start,end:a.end}})}},_setSelectionTo:function(a,b,e,c){var l=this._model,f=this._getSelection(),b=this.convert({x:a,y:b},"page","document"),a=this._getLineIndex(b.y);if(this._clickCount===1){l=this._getLine(a);a=l.getOffset(b.x,b.y-this._getLinePixel(a));l.destroy();if(c&&!e&&f.start<=a&&a<f.end)return this._dragOffset=a,!1;f.extend(a);e||f.collapse()}else(this._clickCount&1)===0?(l=this._getLine(a),a=l.getOffset(b.x,b.y-this._getLinePixel(a)),
+this._doubleClickSelection?a>=this._doubleClickSelection.start?(e=this._doubleClickSelection.start,c=l.getNextOffset(a,{unit:"wordend",count:1})):(e=l.getNextOffset(a,{unit:"word",count:-1}),c=this._doubleClickSelection.end):(e=l.getNextOffset(a,{unit:"word",count:-1}),c=l.getNextOffset(e,{unit:"wordend",count:1})),l.destroy()):this._doubleClickSelection?(c=l.getLineAtOffset(this._doubleClickSelection.start),a>=c?(e=l.getLineStart(c),c=l.getLineEnd(a)):(e=l.getLineStart(a),c=l.getLineEnd(c))):(e=
+l.getLineStart(a),c=l.getLineEnd(a)),f.setCaret(e),f.extend(c);this._setSelection(f,!0,!0);return!0},_setFullSelection:function(a,b){this._fullSelection=a;if(f.isWebkit)this._fullSelection=!0;var e=this._clipDiv||this._rootDiv;if(e)if(this._fullSelection){if(!this._selDiv1&&this._fullSelection&&!f.isIOS){var c=e.ownerDocument;this._highlightRGB=f.isWebkit?"transparent":"Highlight";var l=f.createElement(c,"div");this._selDiv1=l;l.style.position="absolute";l.style.borderWidth="0px";l.style.margin="0px";
+l.style.padding="0px";l.style.outline="none";l.style.background=this._highlightRGB;l.style.width="0px";l.style.height="0px";l.style.zIndex="0";e.appendChild(l);var d=f.createElement(c,"div");this._selDiv2=d;d.style.position="absolute";d.style.borderWidth="0px";d.style.margin="0px";d.style.padding="0px";d.style.outline="none";d.style.background=this._highlightRGB;d.style.width="0px";d.style.height="0px";d.style.zIndex="0";e.appendChild(d);this._selDiv3=c=f.createElement(c,"div");c.style.position="absolute";
+c.style.borderWidth="0px";c.style.margin="0px";c.style.padding="0px";c.style.outline="none";c.style.background=this._highlightRGB;c.style.width="0px";c.style.height="0px";c.style.zIndex="0";e.appendChild(c);if(f.isFirefox&&f.isMac){e=this._getWindow().getComputedStyle(c,null).getPropertyValue("background-color");switch(e){case "rgb(119, 141, 168)":e="rgb(199, 208, 218)";break;case "rgb(127, 127, 127)":e="rgb(198, 198, 198)";break;case "rgb(255, 193, 31)":e="rgb(250, 236, 115)";break;case "rgb(243, 70, 72)":e=
+"rgb(255, 176, 139)";break;case "rgb(255, 138, 34)":e="rgb(255, 209, 129)";break;case "rgb(102, 197, 71)":e="rgb(194, 249, 144)";break;case "rgb(140, 78, 184)":e="rgb(232, 184, 255)";break;default:e="rgb(180, 213, 255)"}this._highlightRGB=e;l.style.background=e;d.style.background=e;c.style.background=e}b||this._updateDOMSelection()}}else{if(this._selDiv1)e.removeChild(this._selDiv1),this._selDiv1=null;if(this._selDiv2)e.removeChild(this._selDiv2),this._selDiv2=null;if(this._selDiv3)e.removeChild(this._selDiv3),
+this._selDiv3=null}},_setBlockCursor:function(a){this._blockCursorVisible=a;this._updateBlockCursorVisible()},_setOverwriteMode:function(a){this._overwriteMode=a;this._updateBlockCursorVisible()},_updateBlockCursorVisible:function(){if(this._blockCursorVisible||this._overwriteMode){if(!this._cursorDiv){var a=f.createElement(document,"div");a.className="textviewBlockCursor";this._cursorDiv=a;a.tabIndex=-1;a.style.zIndex="2";a.style.color="transparent";a.style.position="absolute";a.style.pointerEvents=
+"none";a.innerHTML="&nbsp;";this._viewDiv.appendChild(a);this._updateDOMSelection()}}else if(this._cursorDiv)this._cursorDiv.parentNode.removeChild(this._cursorDiv),this._cursorDiv=null},_setMarginOffset:function(a,b){this._marginOffset=a;this._marginDiv.style.display=a?"block":"none";if(!b)this._metrics=this._calculateMetrics(),this._queueUpdate()},_setWrapOffset:function(a,b){this._wrapOffset=a;if(!b)this._metrics=this._calculateMetrics(),this._queueUpdate()},_setReadOnly:function(a){this._readonly=
+a;this._clientDiv.setAttribute("aria-readonly",a?"true":"false")},_setSingleMode:function(a,b){this._singleMode=a;this._updateOverflow();this._updateStyle(b)},_setTabSize:function(a,b){this._tabSize=a;this._customTabSize=void 0;var e=this._clientDiv;if(f.isOpera){if(e)e.style.OTabSize=this._tabSize+""}else if(f.isWebkit>=537.1){if(e)e.style.tabSize=this._tabSize+""}else if(f.isFirefox>=4){if(e)e.style.MozTabSize=this._tabSize+""}else if(this._tabSize!==8)this._customTabSize=this._tabSize;b||(this.redrawLines(),
+this._resetLineWidth())},_setTheme:function(a){this._theme&&this._theme.removeEventListener("ThemeChanged",this._themeListener.onChanged);(this._theme=a)&&this._theme.addEventListener("ThemeChanged",this._themeListener.onChanged);this._setThemeClass(this._themeClass)},_setThemeClass:function(a,b){this._themeClass=a;var e="textview",c=this._theme.getThemeClass();c&&(e+=" "+c);this._themeClass&&c!==this._themeClass&&(e+=" "+this._themeClass);this._rootDiv.className=e;this._updateStyle(b)},_setWrapMode:function(a,
+b){this._wrapMode=a&&this._wrappable;var e=this._clientDiv;this._wrapMode?(e.style.whiteSpace="pre-wrap",e.style.wordWrap="break-word"):(e.style.whiteSpace="pre",e.style.wordWrap="normal");this._updateOverflow();b||(this.redraw(),this._resetLineWidth());this._resetLineHeight()},_showCaret:function(a,b,e,c){if(this._clientDiv){var l=this._model,f=this._getSelection(),d=this._getScroll(),o=f.getCaret(),g=f.start,h=f.end,p=l.getLineAtOffset(h),i=Math.max(Math.max(g,l.getLineStart(p)),h-1),l=this._getClientWidth(),
+p=this._getClientHeight(),q=l/4,r=this._getBoundsAtOffset(o===g?g:i),s=r.left,t=r.right,u=r.top,v=r.bottom;a&&!f.isEmpty()&&(r=this._getBoundsAtOffset(o===h?g:i),r.top===u?o===g?t=s+Math.min(r.right-s,l):s=t-Math.min(t-r.left,l):o===g?v=u+Math.min(r.bottom-u,p):u=v-Math.min(v-r.top,p));a=0;s<d.x&&(a=Math.min(s-d.x,-q));t>d.x+l&&(a=Math.max(t-d.x-l,q));f=0;u<d.y?f=u-d.y:v>d.y+p&&(f=v-d.y-p);c&&(c>0?f>0&&(f=Math.max(f,c)):f<0&&(f=Math.min(f,c)));if(a!==0||f!==0)return f!==0&&typeof e==="number"&&(e<
+0&&(e=0),e>1&&(e=1),f+=Math.floor(f>0?e*p:-e*p)),this._scrollViewAnimated(a,f,b),p!==this._getClientHeight()||l!==this._getClientWidth()?this._showCaret():this._ensureCaretVisible=!0,!0;else b&&b();return!1}},_startIME:function(){if(this._imeOffset===-1){var a=this._getSelection();a.isEmpty()||this._modifyContent({text:"",start:a.start,end:a.end},!0);this._imeOffset=a.start}},_unhookEvents:function(){this._model.removeEventListener("preChanging",this._modelListener.onChanging);this._model.removeEventListener("postChanged",
+this._modelListener.onChanged);this._theme.removeEventListener("ThemeChanged",this._themeListener.onChanged);this._modelListener=null;for(var a=0;a<this._handlers.length;a++){var b=this._handlers[a];s(b.target,b.type,b.handler)}this._handlers=null;if(this._mutationObserver)this._mutationObserver.disconnect(),this._mutationObserver=null},_updateDOMSelection:function(){if(!(this._redrawCount>0)&&!this._ignoreDOMSelection&&this._clientDiv){var a=this._getSelection(),b=this._model,e=b.getLineAtOffset(a.start),
+c=b.getLineAtOffset(a.end),l=this._getLineNext();if(l){var f=this._getLinePrevious(),d;e<l.lineIndex?(d=l,e=0):e>f.lineIndex?(d=f,e=0):(d=this._getLineNode(e),e=a.start-b.getLineStart(e));c<l.lineIndex?b=0:c>f.lineIndex?(l=f,b=0):(l=this._getLineNode(c),b=a.end-b.getLineStart(c));this._setDOMSelection(d,e,l,b,a.caret)}}},_update:function(a){if(!(this._redrawCount>0)){if(this._updateTimer)this._getWindow().clearTimeout(this._updateTimer),this._updateTimer=null,a=!1;var b=this._clientDiv,e=this._viewDiv;
+if(b){if(this._metrics.invalid)this._ignoreQueueUpdate=!0,this._updateStyle(),this._ignoreQueueUpdate=!1;var c=this._model,l=this._getScroll(!1),d=this._getViewPadding(),o=c.getLineCount(),g=this._getLineHeight(),h=!1,i=!1,q=!1,r=this._metrics.scrollWidth;if(this._wrapMode)b.style.width=(this._metrics.wrapWidth||this._getClientWidth())+"px";var s,t,u,v,k=0,n=0,m;if(this._lineHeight){for(;n<o;){m=this._getLineHeight(n);if(k+m>l.y)break;k+=m;n++}s=n;t=Math.max(0,s-1);u=c=l.y-k;s>0&&(c+=this._getLineHeight(s-
+1))}else v=Math.max(0,l.y)/g,s=Math.floor(v),t=Math.max(0,s-1),c=Math.round((v-t)*g),u=Math.round((v-s)*g);this._topIndexY=u;v=this._rootDiv;var I=v.clientWidth,F=v.clientHeight;if(a){g=0;this._leftDiv&&(s=this._leftDiv.getBoundingClientRect(),g=s.right-s.left);s=this._getClientWidth();v=this._getClientHeight();i=s;if(this._wrapMode){if(this._metrics.wrapWidth)i=this._metrics.wrapWidth}else i=Math.max(this._maxLineWidth,i);for(;n<o;)m=this._getLineHeight(n,!1),k+=m,n++;o=k}else{v=this._getClientHeight();
+u=Math.min(s+Math.floor((v+u)/g),o-1);var l=Math.min(u+1,o-1),A;for(m=b.firstChild;m;){A=m.lineIndex;var z=m.nextSibling;if(!(t<=A&&A<=l)||m.lineRemoved||m.lineIndex===-1)this._mouseWheelLine===m?(m.style.display="none",m.lineIndex=-1):b.removeChild(m);m=z}m=this._getLineNext();var z=e.ownerDocument,C=z.createDocumentFragment();for(A=t;A<=l;A++)if(!m||m.lineIndex>A)(new p(this,A)).create(C,null);else{C.firstChild&&(b.insertBefore(C,m),C=z.createDocumentFragment());if(m&&m.lineChanged)m=(new p(this,
+A)).create(C,m),m.lineChanged=!1;m=this._getLineNext(m)}C.firstChild&&b.insertBefore(C,m);if(f.isWebkit&&!this._wrapMode)b.style.width="0x7fffffffpx";m=this._getLineNext();A=v+c;for(C=!1;m;){t=m.lineWidth;if(t===void 0)if(z=m._line.getBoundingClientRect(),t=m.lineWidth=Math.ceil(z.right-z.left),z=z.bottom-z.top,this._lineHeight)this._lineHeight[m.lineIndex]=z;else if(g!==0&&z!==0&&Math.ceil(g)!==Math.ceil(z))this._variableLineHeight=!0,this._lineHeight=[],this._lineHeight[m.lineIndex]=z;if(this._lineHeight&&
+!C&&(A-=this._lineHeight[m.lineIndex],A<0))u=m.lineIndex,C=!0;if(!this._wrapMode){if(t>=this._maxLineWidth)this._maxLineWidth=t,this._maxLineIndex=m.lineIndex;if(this._checkMaxLineIndex===m.lineIndex)this._checkMaxLineIndex=-1}if(m.lineIndex===s)this._topChild=m;if(m.lineIndex===u)this._bottomChild=m;m=this._getLineNext(m)}if(this._checkMaxLineIndex!==-1&&(A=this._checkMaxLineIndex,this._checkMaxLineIndex=-1,0<=A&&A<o)){g=new p(this,A);z=g.getBoundingClientRect();t=z.right-z.left;if(t>=this._maxLineWidth)this._maxLineWidth=
+t,this._maxLineIndex=A;g.destroy()}for(;n<o;)m=this._getLineHeight(n,n<=u),k+=m,n++;o=k;this._updateRuler(this._leftDiv,s,l,F);this._updateRuler(this._rightDiv,s,l,F);this._updateRuler(this._marginDiv,s,l,F);g=0;this._leftDiv&&(s=this._leftDiv.getBoundingClientRect(),g=s.right-s.left);l=0;this._rightDiv&&(l=this._rightDiv.getBoundingClientRect(),l=l.right-l.left);e.style.left=g+"px";e.style.right=l+"px";l=this._scrollDiv;l.style.height=o+"px";s=this._getClientWidth();if(!this._singleMode&&!this._wrapMode){k=
+h=v;(n=e.style.overflowX==="scroll")?h+=r:k-=r;m=u=s;(t=e.style.overflowY==="scroll")?u+=r:m-=r;v=h;s=u;o>v&&(q=!0,s=m);this._maxLineWidth>s&&(i=!0,v=k,o>v&&(q=!0,s=m));if(n!==i)e.style.overflowX=i?"scroll":"hidden";if(t!==q)e.style.overflowY=q?"scroll":"hidden";h=n!==i||t!==q}q=s;if(this._wrapMode){if(this._metrics.wrapWidth)q=this._metrics.wrapWidth}else q=Math.max(this._maxLineWidth,q);i=q;if((!f.isIE||f.isIE>=9)&&this._maxLineWidth>s)q+=d.right+d.left;l.style.width=q+"px";if(this._clipScrollDiv)this._clipScrollDiv.style.width=
+q+"px";l=this._getScroll(!1)}if(this._vScrollDiv)q=v-8,k=Math.max(15,Math.ceil(Math.min(1,q/(o+d.top+d.bottom))*q)),this._vScrollDiv.style.left=g+s-8+"px",this._vScrollDiv.style.top=Math.floor(Math.max(0,l.y*q/o))+"px",this._vScrollDiv.style.height=k+"px";if(!this._wrapMode&&this._hScrollDiv)q=s-8,k=Math.max(15,Math.ceil(Math.min(1,q/(this._maxLineWidth+d.left+d.right))*q)),this._hScrollDiv.style.left=g+Math.floor(Math.max(0,Math.floor(l.x*q/this._maxLineWidth)))+"px",this._hScrollDiv.style.top=v-
+9+"px",this._hScrollDiv.style.width=k+"px";n=l.x;k=this._clipDiv;q=this._overlayDiv;if(u=this._marginDiv)u.style.left=-n+g+this._metrics.marginWidth+d.left+"px",u.style.bottom=(e.style.overflowX==="scroll"?r:0)+"px";if(k){k.scrollLeft=n;k.scrollTop=0;e=g+d.left;r=d.top;a=s;g=v;n=0;u=-c;if(l.x===0)e-=d.left,a+=d.left,n=d.left;l.x+s===i&&(a+=d.right);l.y===0&&(r-=d.top,g+=d.top,u+=d.top);l.y+v===o&&(g+=d.bottom);k.style.left=e+"px";k.style.top=r+"px";k.style.right=I-a-e+"px";k.style.bottom=F-g-r+"px";
+b.style.left=n+"px";b.style.top=u+"px";b.style.width=i+"px";b.style.height=v+c+"px";if(q)q.style.left=b.style.left,q.style.top=b.style.top,q.style.width=b.style.width,q.style.height=b.style.height}else{e=n;r=c;I=n+s;F=c+v;e===0&&(e-=d.left);r===0&&(r-=d.top);I===i&&(I+=d.right);l.y+v===o&&(F+=d.bottom);b.style.clip="rect("+r+"px,"+I+"px,"+F+"px,"+e+"px)";b.style.left=-n+g+d.left+"px";b.style.width=(this._wrapMode||f.isWebkit?i:s+n)+"px";if(!a)b.style.top=-c+d.top+"px",b.style.height=v+c+"px";if(q&&
+(q.style.clip=b.style.clip,q.style.left=b.style.left,q.style.width=b.style.width,!a))q.style.top=b.style.top,q.style.height=b.style.height}this._updateDOMSelection();if(h)b=this._ensureCaretVisible,this._ensureCaretVisible=!1,b&&this._showCaret(),this._queueUpdate()}}},_updateOverflow:function(){var a=this._viewDiv;this._wrapMode?(a.style.overflowX="hidden",a.style.overflowY="scroll"):a.style.overflow="hidden"},_updateRuler:function(a,b,e,c){if(a)for(var l=this._parent.ownerDocument,d=this._getLineHeight(),
+o=this._getViewPadding(),a=a.firstChild;a;){var h=a._ruler,p=d,i=h.getOverview();i==="page"&&(p+=this._topIndexY);a.style.top=-p+"px";a.style.height=c+p+"px";a.rulerChanged&&g(h.getRulerStyle(),a);var q,r=a.firstChild;r?(q=r,r=r.nextSibling):(q=f.createElement(l,"div"),q.style.visibility="hidden",a.appendChild(q));var s;if(a.rulerChanged&&q){p=-1;if(s=h.getWidestAnnotation())if(g(s.style,q),s.html)q.innerHTML=s.html;q.lineIndex=p;q.style.height=d+o.top+"px"}var t;if(i==="page"){for(h=h.getAnnotations(b,
+e+1);r;)p=r.lineIndex,s=r.nextSibling,(!(b<=p&&p<=e)||r.lineChanged)&&a.removeChild(r),r=s;r=a.firstChild.nextSibling;t=l.createDocumentFragment();for(p=b;p<=e;p++)if(!r||r.lineIndex>p){q=f.createElement(l,"div");if(s=h[p]){g(s.style,q);if(s.html)q.innerHTML=s.html;q.annotation=s}q.lineIndex=p;q.style.height=this._getLineHeight(p)+"px";t.appendChild(q)}else if(t.firstChild&&(a.insertBefore(t,r),t=l.createDocumentFragment()),r)r=r.nextSibling;t.firstChild&&a.insertBefore(t,r)}else{s=this._getClientHeight();
+p=this._model.getLineCount();r=s+o.top+o.bottom-2*this._metrics.scrollWidth;i=d*p<r?d:r/p;if(a.rulerChanged){for(s=a.childNodes.length;s>1;)a.removeChild(a.lastChild),s--;h=h.getAnnotations(0,p);t=l.createDocumentFragment();for(var u in h)if(p=u>>>0,!(p<0)){q=f.createElement(l,"div");s=h[u];g(s.style,q);q.style.position="absolute";q.style.top=this._metrics.scrollWidth+d+Math.floor(p*i)+"px";if(s.html)q.innerHTML=s.html;q.annotation=s;q.lineIndex=p;t.appendChild(q)}a.appendChild(t)}else if(a._oldTrackHeight!==
+r)for(q=a.firstChild?a.firstChild.nextSibling:null;q;)q.style.top=this._metrics.scrollWidth+d+Math.floor(q.lineIndex*i)+"px",q=q.nextSibling;a._oldTrackHeight=r}a.rulerChanged=!1;a=a.nextSibling}},_updateStyleSheet:function(){var a="";f.isWebkit&&this._metrics.scrollWidth>0&&(a+="\n.textview ::-webkit-scrollbar-corner {background: #eeeeee;}");f.isFirefox&&f.isMac&&this._highlightRGB&&this._highlightRGB!=="Highlight"&&(a+="\n.textview ::-moz-selection {background: "+this._highlightRGB+";}");if(a){var b=
+document.getElementById("_textviewStyle");if(b)b.removeChild(b.firstChild),b.appendChild(document.createTextNode(a));else{b=f.createElement(document,"style");b.id="_textviewStyle";var e=document.getElementsByTagName("head")[0]||document.documentElement;b.appendChild(document.createTextNode(a));e.insertBefore(b,e.firstChild)}}},_updateStyle:function(a){if(!a&&f.isIE)this._rootDiv.style.lineHeight="normal";var b=this._metrics=this._calculateMetrics();this._rootDiv.style.lineHeight=f.isIE?b.lineHeight-
+(b.lineTrim.top+b.lineTrim.bottom)+"px":"normal";this._updateStyleSheet();a||(this.redraw(),this._resetLineWidth())}};i.EventTarget.addMixin(t.prototype);return{TextView:t}});
+define("orion/editor/projectionTextModel",["orion/editor/textModel","orion/editor/eventTarget"],function(k,m){function n(i){this._model=i;this._projections=[];var c=this;this._listener={onChanged:function(d){c._onChanged(d)},onChanging:function(d){c._onChanging(d)}};i.addEventListener("postChanged",this._listener.onChanged);i.addEventListener("preChanging",this._listener.onChanging)}n.prototype={destroy:function(){if(this._model)this._model.removeEventListener("postChanged",this._listener.onChanged),
+this._model.removeEventListener("preChanging",this._listener.onChanging),this._model=null},addProjection:function(i){if(i){var c=this._model,d=this._projections;i._lineIndex=c.getLineAtOffset(i.start);i._lineCount=c.getLineAtOffset(i.end)-i._lineIndex;var f=i.text;f||(f="");i._model=typeof f==="string"?new k.TextModel(f,c.getLineDelimiter()):f;var c=this.mapOffset(i.start,!0),f=i.end-i.start,g=i._lineCount,h=i._model.getCharCount(),b=i._model.getLineCount()-1;this.onChanging({type:"Changing",text:i._model.getText(),
+start:c,removedCharCount:f,addedCharCount:h,removedLineCount:g,addedLineCount:b});var a=this._binarySearch(d,i.start);d.splice(a,0,i);this.onChanged({type:"Changed",start:c,removedCharCount:f,addedCharCount:h,removedLineCount:g,addedLineCount:b})}},getProjections:function(){return this._projections.slice(0)},getBaseModel:function(){return this._model},mapOffset:function(i,c){var d=this._projections,f=0,g,h;if(c){for(g=0;g<d.length;g++){h=d[g];if(h.start>i)break;if(h.end>i)return-1;f+=h._model.getCharCount()-
+(h.end-h.start)}return i+f}for(g=0;g<d.length;g++){h=d[g];if(h.start>i-f)break;var b=h._model.getCharCount();if(h.start+b>i-f)return-1;f+=b-(h.end-h.start)}return i-f},removeProjection:function(i){var c,d=0;for(c=0;c<this._projections.length;c++){var f=this._projections[c];if(f===i){i=f;break}d+=f._model.getCharCount()-(f.end-f.start)}if(c<this._projections.length){var f=this._model,d=i.start+d,g=i.end-i.start,h=i._lineCount,b=i._model.getCharCount(),a=i._model.getLineCount()-1;this.onChanging({type:"Changing",
+text:f.getText(i.start,i.end),start:d,removedCharCount:b,addedCharCount:g,removedLineCount:a,addedLineCount:h});this._projections.splice(c,1);this.onChanged({type:"Changed",start:d,removedCharCount:b,addedCharCount:g,removedLineCount:a,addedLineCount:h})}},_binarySearch:function(i,c){for(var d=i.length,f=-1,g;d-f>1;)g=Math.floor((d+f)/2),c<=i[g].start?d=g:f=g;return d},getCharCount:function(){for(var i=this._model.getCharCount(),c=this._projections,d=0;d<c.length;d++){var f=c[d];i+=f._model.getCharCount()-
+(f.end-f.start)}return i},getLine:function(i,c){if(i<0)return null;var d=this._model,f=this._projections,g=0,h=[],b=0,a,e,l;for(a=0;a<f.length;a++){l=f[a];if(l._lineIndex>=i-g)break;e=l._model.getLineCount()-1;if(l._lineIndex+e>=i-g)if(b=i-(l._lineIndex+g),b<e)return l._model.getLine(b,c);else h.push(l._model.getLine(e));b=l.end;g+=e-l._lineCount}for(b=Math.max(b,d.getLineStart(i-g));a<f.length;a++){l=f[a];if(l._lineIndex>i-g)break;h.push(d.getText(b,l.start));e=l._model.getLineCount()-1;if(l._lineIndex+
+e>i-g)return h.push(l._model.getLine(0,c)),h.join("");h.push(l._model.getText());b=l.end;g+=e-l._lineCount}f=d.getLineEnd(i-g,c);b<f&&h.push(d.getText(b,f));return h.join("")},getLineAtOffset:function(i){for(var c=this._model,d=this._projections,f=0,g=0,h=0;h<d.length;h++){var b=d[h];if(b.start>i-f)break;var a=b._model.getCharCount();if(b.start+a>i-f){d=i-(b.start+f);g+=b._model.getLineAtOffset(d);f+=d;break}g+=b._model.getLineCount()-1-b._lineCount;f+=a-(b.end-b.start)}return c.getLineAtOffset(i-
+f)+g},getLineCount:function(){for(var i=this._projections,c=this._model.getLineCount(),d=0;d<i.length;d++){var f=i[d];c+=f._model.getLineCount()-1-f._lineCount}return c},getLineDelimiter:function(){return this._model.getLineDelimiter()},getLineEnd:function(i,c){if(i<0)return-1;for(var d=this._model,f=this._projections,g=0,h=0,b=0;b<f.length;b++){var a=f[b];if(a._lineIndex>i-g)break;var e=a._model.getLineCount()-1;if(a._lineIndex+e>i-g)return a._model.getLineEnd(i-(a._lineIndex+g),c)+a.start+h;h+=
+a._model.getCharCount()-(a.end-a.start);g+=e-a._lineCount}return d.getLineEnd(i-g,c)+h},getLineStart:function(i){if(i<0)return-1;for(var c=this._model,d=this._projections,f=0,g=0,h=0;h<d.length;h++){var b=d[h];if(b._lineIndex>=i-f)break;var a=b._model.getLineCount()-1;if(b._lineIndex+a>=i-f)return b._model.getLineStart(i-(b._lineIndex+f))+b.start+g;g+=b._model.getCharCount()-(b.end-b.start);f+=a-b._lineCount}return c.getLineStart(i-f)+g},getText:function(i,c){i===void 0&&(i=0);var d=this._model,f=
+this._projections,g=0,h=[],b,a,e;for(b=0;b<f.length;b++){a=f[b];if(a.start>i-g)break;e=a._model.getCharCount();if(a.start+e>i-g)if(c!==void 0&&a.start+e>c-g)return a._model.getText(i-(a.start+g),c-(a.start+g));else h.push(a._model.getText(i-(a.start+g))),i=a.end+g+e-(a.end-a.start);g+=e-(a.end-a.start)}var l=i-g;if(c!==void 0){for(;b<f.length;b++){a=f[b];if(a.start>c-g)break;h.push(d.getText(l,a.start));e=a._model.getCharCount();if(a.start+e>c-g)return h.push(a._model.getText(0,c-(a.start+g))),h.join("");
+h.push(a._model.getText());l=a.end;g+=e-(a.end-a.start)}h.push(d.getText(l,c-g))}else{for(;b<f.length;b++)a=f[b],h.push(d.getText(l,a.start)),h.push(a._model.getText()),l=a.end;h.push(d.getText(l))}return h.join("")},_onChanged:function(){var i=this._change,c=i.baseStart,d=i.baseEnd,f,g,h=this._projections;for(f=0;f<h.length;f++)if(g=h[f],g.end>c)break;var b=f;for(f=0;f<h.length;f++)if(g=h[f],g.start>=d)break;var a=f,e=this._model,c=i.baseText.length-(d-c);for(f=a;f<h.length;f++)g=h[f],g.start+=c,
+g.end+=c,g._lineIndex=e.getLineAtOffset(g.start);g=h.splice(b,a-b);for(f=0;f<g.length;f++)g[f].annotation&&g[f].annotation._expand();this.onChanged({type:"Changed",start:i.start,removedCharCount:i.removedCharCount,addedCharCount:i.addedCharCount,removedLineCount:i.removedLineCount,addedLineCount:i.addedLineCount});this._change=void 0},_onChanging:function(i){var c=!!this._change,d=this._change||{},f=i.start,g=f+i.removedCharCount;d.baseStart=f;d.baseEnd=g;d.baseText=i.text;d.addedLineCount=i.addedLineCount;
+if(!c){this._change=d;d.text=i.text;var h=this._projections,b,a,e,i=function(c){for(a=0,b=0;a<h.length;a++){e=h[a];if(e.start>c)break;if(e.end>c)return-1;b+=e._model.getCharCount()-(e.end-e.start)}return c+b};d.start=i(f);if(d.start===-1)d.text=this._model.getText(e.start,f)+d.text,d.addedLineCount+=this._model.getLineAtOffset(f)-this._model.getLineAtOffset(e.start),d.start=e.start+b;d.end=i(g);if(d.end===-1)d.text+=this._model.getText(g,e.end),d.addedLineCount+=this._model.getLineAtOffset(e.end)-
+this._model.getLineAtOffset(g),d.end=e.start+b}d.addedCharCount=d.text.length;d.removedCharCount=d.end-d.start;d.removedLineCount=this.getLineAtOffset(d.end)-this.getLineAtOffset(d.start);this.onChanging({type:"Changing",text:d.text,start:d.start,removedCharCount:d.removedCharCount,addedCharCount:d.addedCharCount,removedLineCount:d.removedLineCount,addedLineCount:d.addedLineCount})},onChanging:function(i){return this.dispatchEvent(i)},onChanged:function(i){return this.dispatchEvent(i)},setLineDelimiter:function(i){this._model.setLineDelimiter(i)},
+setText:function(i,c,d){function f(e){for(b=0,h=0;b<g.length;b++){a=g[b];if(a.start>e-h)break;var c=a._model.getCharCount();if(a.start+c>e-h)return-1;h+=c-(a.end-a.start)}return e-h}this._change={text:i||"",start:c||0,end:d===void 0?this.getCharCount():d};var g=this._projections,h,b,a,e,l,i=f(this._change.start);if(i===-1)e={projection:a,start:this._change.start-(a.start+h)},i=a.end;c=f(this._change.end);if(c===-1)l={projection:a,end:this._change.end-(a.start+h)},c=a.start;if(e&&l&&e.projection===
+l.projection)a._model.setText(this._change.text,e.start,l.end);else{this._model.setText(this._change.text,i,c);if(e)a=e.projection,a._model.setText("",e.start);if(l)a=l.projection,a._model.setText("",0,l.end),a.start=a.end,a._lineCount=0}this._change=void 0}};m.EventTarget.addMixin(n.prototype);return{ProjectionTextModel:n}});
+define("orion/editor/annotations",["i18n!orion/editor/nls/messages","orion/editor/eventTarget"],function(k,m){function n(b,a,e){this.start=b;this.end=a;this._projectionModel=e;this.html=this._expandedHTML;this.style=this._expandedStyle;this.expanded=!0}function i(){}function c(b,a){var e=b.lastIndexOf("."),e=b.substring(e+1),c={title:k[e],style:{styleClass:"annotation "+e},html:"<div class='annotationHTML "+e+"'></div>",overviewStyle:{styleClass:"annotationOverview "+e}};a?c.lineStyle={styleClass:"annotationLine "+
+e}:c.rangeStyle={styleClass:"annotationRange "+e};i.registerType(b,c)}function d(){}function f(b){this._annotations=[];var a=this;this._listener={onChanged:function(b){a._onChanged(b)}};this.setTextModel(b)}function g(b,a){this._view=b;this._annotationModel=a;var e=this;this._listener={onDestroy:function(a){e._onDestroy(a)},onLineStyle:function(a){e._onLineStyle(a)},onChanged:function(a){e._onAnnotationModelChanged(a)}};b.addEventListener("Destroy",this._listener.onDestroy);b.addEventListener("postLineStyle",
+this._listener.onLineStyle);a.addEventListener("Changed",this._listener.onChanged)}n.prototype={_expandedHTML:"<div class='annotationHTML expanded'></div>",_expandedStyle:{styleClass:"annotation expanded"},_collapsedHTML:"<div class='annotationHTML collapsed'></div>",_collapsedStyle:{styleClass:"annotation collapsed"},_collapse:function(){if(!this.expanded)return!1;this.expanded=!1;this.html=this._collapsedHTML;this.style=this._collapsedStyle;this._annotationModel&&this._annotationModel.modifyAnnotation(this);
+return!0},_expand:function(){if(this.expanded)return!1;this.expanded=!0;this.html=this._expandedHTML;this.style=this._expandedStyle;this._annotationModel&&this._annotationModel.modifyAnnotation(this);return!0},collapse:function(){if(this._collapse()){var b=this._projectionModel,a=b.getBaseModel();this._projection={annotation:this,start:a.getLineStart(a.getLineAtOffset(this.start)+1),end:a.getLineEnd(a.getLineAtOffset(this.end),!0)};b.addProjection(this._projection)}},expand:function(){this._expand()&&
+this._projectionModel.removeProjection(this._projection)}};i.ANNOTATION_ERROR="orion.annotation.error";i.ANNOTATION_WARNING="orion.annotation.warning";i.ANNOTATION_TASK="orion.annotation.task";i.ANNOTATION_BREAKPOINT="orion.annotation.breakpoint";i.ANNOTATION_BOOKMARK="orion.annotation.bookmark";i.ANNOTATION_FOLDING="orion.annotation.folding";i.ANNOTATION_CURRENT_BRACKET="orion.annotation.currentBracket";i.ANNOTATION_MATCHING_BRACKET="orion.annotation.matchingBracket";i.ANNOTATION_CURRENT_LINE="orion.annotation.currentLine";
+i.ANNOTATION_CURRENT_SEARCH="orion.annotation.currentSearch";i.ANNOTATION_MATCHING_SEARCH="orion.annotation.matchingSearch";i.ANNOTATION_READ_OCCURRENCE="orion.annotation.readOccurrence";i.ANNOTATION_WRITE_OCCURRENCE="orion.annotation.writeOccurrence";i.ANNOTATION_SELECTED_LINKED_GROUP="orion.annotation.selectedLinkedGroup";i.ANNOTATION_CURRENT_LINKED_GROUP="orion.annotation.currentLinkedGroup";i.ANNOTATION_LINKED_GROUP="orion.annotation.linkedGroup";i.ANNOTATION_BLAME="orion.annotation.blame";i.ANNOTATION_CURRENT_BLAME=
+"orion.annotation.currentBlame";var h={};i.registerType=function(b,a){var e=a;if(typeof e!=="function")e=function(a,b,e){this.start=a;this.end=b;if(e!==void 0)this.title=e},e.prototype=a;e.prototype.type=b;h[b]=e;return b};i.createAnnotation=function(b,a,e,c){return new (this.getType(b))(a,e,c)};i.getType=function(b){return h[b]};c(i.ANNOTATION_ERROR);c(i.ANNOTATION_WARNING);c(i.ANNOTATION_TASK);c(i.ANNOTATION_BREAKPOINT);c(i.ANNOTATION_BOOKMARK);c(i.ANNOTATION_CURRENT_BRACKET);c(i.ANNOTATION_MATCHING_BRACKET);
+c(i.ANNOTATION_CURRENT_SEARCH);c(i.ANNOTATION_MATCHING_SEARCH);c(i.ANNOTATION_READ_OCCURRENCE);c(i.ANNOTATION_WRITE_OCCURRENCE);c(i.ANNOTATION_SELECTED_LINKED_GROUP);c(i.ANNOTATION_CURRENT_LINKED_GROUP);c(i.ANNOTATION_LINKED_GROUP);c(i.ANNOTATION_CURRENT_LINE,!0);c(i.ANNOTATION_BLAME,!0);c(i.ANNOTATION_CURRENT_BLAME,!0);i.registerType(i.ANNOTATION_FOLDING,n);d.addMixin=function(b){var a=d.prototype,e;for(e in a)a.hasOwnProperty(e)&&(b[e]=a[e])};d.prototype={addAnnotationType:function(b){if(!this._annotationTypes)this._annotationTypes=
+[];this._annotationTypes.push(b)},getAnnotationTypePriority:function(b){if(this._annotationTypes)for(var a=0;a<this._annotationTypes.length;a++)if(this._annotationTypes[a]===b)return a+1;return 0},getAnnotationsByType:function(b,a,e){b=b.getAnnotations(a,e);for(e=[];b.hasNext();)a=b.next(),this.getAnnotationTypePriority(a.type)!==0&&e.push(a);var c=this;e.sort(function(a,b){return c.getAnnotationTypePriority(a.type)-c.getAnnotationTypePriority(b.type)});return e},isAnnotationTypeVisible:function(b){return this.getAnnotationTypePriority(b)!==
+0},removeAnnotationType:function(b){if(this._annotationTypes)for(var a=0;a<this._annotationTypes.length;a++)if(this._annotationTypes[a]===b){this._annotationTypes.splice(a,1);break}}};f.prototype={addAnnotation:function(b){if(b){var a=this._annotations,e=this._binarySearch(a,b.start);a.splice(e,0,b);b._annotationModel=this;this.onChanged({type:"Changed",added:[b],removed:[],changed:[]})}},getTextModel:function(){return this._model},getAnnotations:function(b,a){var e=this._annotations,c,d=0,f;f=b===
+void 0&&a===void 0?function(){return d<e.length?e[d++]:null}:function(){for(;d<e.length;){var c=e[d++];if(b===c.start||(b>c.start?b<c.end:c.start<a))return c;if(c.start>=a)break}return null};c=f();return{next:function(){var a=c;a&&(c=f());return a},hasNext:function(){return c!==null}}},modifyAnnotation:function(b){if(b&&!(this._getAnnotationIndex(b)<0))this.onChanged({type:"Changed",added:[],removed:[],changed:[b]})},onChanged:function(b){return this.dispatchEvent(b)},removeAnnotations:function(b){var a=
+this._annotations,e,c;if(b){e=[];for(c=a.length-1;c>=0;c--){var d=a[c];if(d.type===b)a.splice(c,1),e.splice(0,0,d),d._annotationModel=null}}else e=a;this.onChanged({type:"Changed",removed:e,added:[],changed:[]})},removeAnnotation:function(b){if(b){var a=this._getAnnotationIndex(b);if(!(a<0))b._annotationModel=null,this.onChanged({type:"Changed",removed:this._annotations.splice(a,1),added:[],changed:[]})}},replaceAnnotations:function(b,a){var e=this._annotations,c,d,f,g=[];if(b)for(c=b.length-1;c>=
+0;c--)if(f=b[c],d=this._getAnnotationIndex(f),!(d<0))f._annotationModel=null,e.splice(d,1),g.splice(0,0,f);a||(a=[]);for(c=0;c<a.length;c++)f=a[c],d=this._binarySearch(e,f.start),f._annotationModel=this,e.splice(d,0,f);this.onChanged({type:"Changed",removed:g,added:a,changed:[]})},setTextModel:function(b){this._model&&this._model.removeEventListener("Changed",this._listener.onChanged);(this._model=b)&&this._model.addEventListener("Changed",this._listener.onChanged)},_binarySearch:function(b,a){for(var e=
+b.length,c=-1,d;e-c>1;)d=Math.floor((e+c)/2),a<=b[d].start?e=d:c=d;return e},_getAnnotationIndex:function(b){for(var a=this._annotations,e=this._binarySearch(a,b.start);e<a.length&&a[e].start===b.start;){if(a[e]===b)return e;e++}return-1},_onChanged:function(b){var a=b.start,e=b.removedCharCount,c=this._annotations,d=a+e;if(0<c.length){for(var f={type:"Changed",added:[],removed:[],changed:[],textModelChangedEvent:b},b=b.addedCharCount-e,e=0;e<c.length;e++){var g=c[e];if(g.start>=d)g._oldStart=g.start,
+g._oldEnd=g.end,g.start+=b,g.end+=b,f.changed.push(g);else if(!(g.end<=a))g.start<a&&d<g.end?(g._oldStart=g.start,g._oldEnd=g.end,g.end+=b,f.changed.push(g)):(c.splice(e,1),f.removed.push(g),g._annotationModel=null,g.expand&&g.expand(),e--)}if(f.added.length>0||f.removed.length>0||f.changed.length>0)this.onChanged(f)}}};m.EventTarget.addMixin(f.prototype);g.prototype={destroy:function(){var b=this._view;if(b)b.removeEventListener("Destroy",this._listener.onDestroy),b.removeEventListener("LineStyle",
+this._listener.onLineStyle),this.view=null;(b=this._annotationModel)&&b.removeEventListener("Changed",this._listener.onChanged)},_mergeStyle:function(b,a){if(a){b||(b={});b.styleClass&&a.styleClass&&b.styleClass!==a.styleClass?b.styleClass+=" "+a.styleClass:b.styleClass=a.styleClass;var e;if(a.tagName&&!b.tagName)b.tagName=a.tagName;if(a.style){if(!b.style)b.style={};for(e in a.style)b.style[e]||(b.style[e]=a.style[e])}if(a.attributes){if(!b.attributes)b.attributes={};for(e in a.attributes)b.attributes[e]||
+(b.attributes[e]=a.attributes[e])}}return b},_mergeStyleRanges:function(b,a){b||(b=[]);var e,c;for(c=0;c<b.length&&a;c++){var d=b[c];if(a.end<=d.start)break;if(!(a.start>=d.end)){e=this._mergeStyle({},d.style);e=this._mergeStyle(e,a.style);var f=[];f.push(c,1);a.start<d.start&&f.push({start:a.start,end:d.start,style:a.style});a.start>d.start&&f.push({start:d.start,end:a.start,style:d.style});f.push({start:Math.max(d.start,a.start),end:Math.min(d.end,a.end),style:e});a.end<d.end&&f.push({start:a.end,
+end:d.end,style:d.style});a=a.end>d.end?{start:d.end,end:a.end,style:a.style}:null;Array.prototype.splice.apply(b,f)}}a&&(e=this._mergeStyle({},a.style),b.splice(c,0,{start:a.start,end:a.end,style:e}));return b},_onAnnotationModelChanged:function(b){function a(a,b){f.getBaseModel&&(a=f.mapOffset(a,!0),b=f.mapOffset(b,!0));a!==-1&&b!==-1&&c.redrawRange(a,b)}function e(b,e){for(var c=0;c<b.length;c++)if(d.isAnnotationTypeVisible(b[c].type)){var l=b[c];a(l.start,l.end);e&&l._oldStart!==void 0&&l._oldEnd&&
+a(l._oldStart,l._oldEnd)}}var c=this._view;if(c){var d=this,f=c.getModel();e(b.added);e(b.removed);e(b.changed,!0)}},_onDestroy:function(){this.destroy()},_onLineStyle:function(b){var a=this._annotationModel,e=b.textView.getModel(),c=a.getTextModel(),d=b.lineStart,f=b.lineStart+b.lineText.length;c!==e&&(d=e.mapOffset(d),f=e.mapOffset(f));for(a=a.getAnnotations(d,f);a.hasNext();)if(d=a.next(),this.isAnnotationTypeVisible(d.type)){if(d.rangeStyle){var f=d.start,g=d.end;c!==e&&(f=e.mapOffset(f,!0),g=
+e.mapOffset(g,!0));b.ranges=this._mergeStyleRanges(b.ranges,{start:f,end:g,style:d.rangeStyle})}if(d.lineStyle)b.style=this._mergeStyle({},b.style),b.style=this._mergeStyle(b.style,d.lineStyle)}}};d.addMixin(g.prototype);return{FoldingAnnotation:n,AnnotationType:i,AnnotationTypeList:d,AnnotationModel:f,AnnotationStyler:g}});
+define("orion/editor/tooltip","i18n!orion/editor/nls/messages,orion/editor/textView,orion/editor/textModel,orion/editor/projectionTextModel,orion/editor/util,orion/util".split(","),function(k,m,n,i,c,d){function f(c){this._view=c;this._fadeDelay=500;this._hideDelay=200;this._showDelay=500;this._autoHideDelay=5E3;this._create(c.getOptions("parent").ownerDocument)}f.getTooltip=function(c){if(!c._tooltip)c._tooltip=new f(c);return c._tooltip};f.prototype={_create:function(f){if(!this._tooltipDiv){var h=
+this._tooltipDiv=d.createElement(f,"div");h.tabIndex=0;h.className="textviewTooltip";h.setAttribute("aria-live","assertive");h.setAttribute("aria-atomic","true");var b=this._tooltipContents=d.createElement(f,"div");h.appendChild(b);f.body.appendChild(h);var a=this;c.addEventListener(h,"mouseover",function(){if(a._hideDelay){var b=a._getWindow();if(a._delayedHideTimeout)b.clearTimeout(a._delayedHideTimeout),a._delayedHideTimeout=null;if(a._hideTimeout)b.clearTimeout(a._hideTimeout),a._hideTimeout=
+null;a._nextTarget=null}},!1);c.addEventListener(h,"mouseout",function(b){b=b.relatedTarget||b.toElement;b===h||a._hasFocus()||(!b||!c.contains(h,b))&&a._hide()},!1);c.addEventListener(h,"keydown",function(b){b.keyCode===27&&a._hide()},!1);c.addEventListener(f,"mousedown",this._mouseDownHandler=function(b){a.isVisible()&&(c.contains(h,b.target||b.srcElement)||a._hide())},!0);this._view.addEventListener("Destroy",function(){a.destroy()});this._hide()}},_getWindow:function(){var c=this._tooltipDiv.ownerDocument;
+return c.defaultView||c.parentWindow},destroy:function(){if(this._tooltipDiv){this._hide();var d=this._tooltipDiv.parentNode;d&&d.removeChild(this._tooltipDiv);c.removeEventListener(this._tooltipDiv.ownerDocument,"mousedown",this._mouseDownHandler,!0);this._tooltipDiv=null}},_hasFocus:function(){var d=this._tooltipDiv;return!d?!1:c.contains(d,d.ownerDocument.activeElement)},hide:function(c){if(c===void 0)c=this._hideDelay;var d=this._getWindow();if(this._delayedHideTimeout)d.clearTimeout(this._delayedHideTimeout),
+this._delayedHideTimeout=null;var b=this;c?b._delayedHideTimeout=d.setTimeout(function(){b._delayedHideTimeout=null;b._hide();b.setTarget(b._nextTarget,0)},c):(b._hide(),b.setTarget(b._nextTarget,0))},_hide:function(){var c=this._tooltipDiv;if(c){this._hasFocus()&&this._view.focus();if(this._contentsView)this._contentsView.destroy(),this._contentsView=null;if(this._tooltipContents)this._tooltipContents.innerHTML="";c.style.visibility="hidden";c=this._getWindow();if(this._showTimeout)c.clearTimeout(this._showTimeout),
+this._showTimeout=null;if(this._delayedHideTimeout)c.clearTimeout(this._delayedHideTimeout),this._delayedHideTimeout=null;if(this._hideTimeout)c.clearTimeout(this._hideTimeout),this._hideTimeout=null;if(this._fadeTimeout)c.clearInterval(this._fadeTimeout),this._fadeTimeout=null}},isVisible:function(){return this._tooltipDiv&&this._tooltipDiv.style.visibility==="visible"},setTarget:function(c,d,b){if(this.isVisible()){if(!this._hasFocus())this._nextTarget=c,this.hide(b)}else if(this._target=c){var a=
+this,c=a._getWindow();if(a._showTimeout)c.clearTimeout(a._showTimeout),a._showTimeout=null;d===0?a.show(!0):a._showTimeout=c.setTimeout(function(){a._showTimeout=null;a.show(!0)},d?d:a._showDelay)}},show:function(c){if(this._target){var d=this._target.getTooltipInfo();if(d){var b=this._tooltipDiv,a=this._tooltipContents;b.style.left=b.style.right=b.style.width=b.style.height=a.style.width=a.style.height="auto";var e=d.contents;e instanceof Array&&(e=this._getAnnotationContents(e));if(typeof e==="string")a.innerHTML=
+e;else if(this._isNode(e))a.appendChild(e);else if(e instanceof i.ProjectionTextModel){var l=this._view,f=l.getOptions();f.wrapMode=!1;f.parent=a;var q=f.themeClass;q?((q=q.replace("tooltipTheme",""))&&(q=" "+q),q="tooltipTheme"+q):q="tooltipTheme";f.themeClass=q;f=this._contentsView=new m.TextView(f);f.addEventListener("LineStyle",function(a){l.onLineStyle(a)});f.setModel(e);e=f.computeSize();a.style.width=e.width+"px";a.style.height=e.height+"px";f.resize()}else return;a=b.ownerDocument.documentElement;
+d.anchor==="right"?(e=a.clientWidth-d.x,b.style.right=e+"px"):(e=parseInt(this._getNodeStyle(b,"padding-left","0"),10),e+=parseInt(this._getNodeStyle(b,"border-left-width","0"),10),e=d.x-e,b.style.left=e+"px");b.style.maxWidth=a.clientWidth-e-10+"px";e=parseInt(this._getNodeStyle(b,"padding-top","0"),10);e+=parseInt(this._getNodeStyle(b,"border-top-width","0"),10);e=d.y-e;b.style.top=e+"px";b.style.maxHeight=a.clientHeight-e-10+"px";b.style.opacity="1";b.style.visibility="visible";if(c){var r=this,
+p=this._getWindow();r._hideTimeout=p.setTimeout(function(){r._hideTimeout=null;var a=parseFloat(r._getNodeStyle(b,"opacity","1"));r._fadeTimeout=p.setInterval(function(){b.style.visibility==="visible"&&a>0?(a-=0.1,b.style.opacity=a):r._hide()},r._fadeDelay/10)},r._autoHideDelay)}}}},_getAnnotationContents:function(f){function h(a,b){var e=t.getLineStart(t.getLineAtOffset(a)),c=t.getLineEnd(t.getLineAtOffset(b),!0);return t.getText(e,c)}function b(a){var b=a.title,e=d.createElement(q,"div");e.className=
+"tooltipRow";if(a.html)e.innerHTML=a.html,e.lastChild&&c.addEventListener(e.lastChild,"click",function(){var b=a.start,e=a.end;p.getBaseModel&&(b=p.mapOffset(b,!0),e=p.mapOffset(e,!0));r.setSelection(b,e,1/3,function(){o._hide()})},!1),e.appendChild(q.createTextNode("\u00a0"));b||(b=h(a.start,a.end));typeof b==="function"&&(b=a.title());if(typeof b==="string"){var j=d.createElement(q,"span");j.appendChild(q.createTextNode(b));b=j}e.appendChild(b);return e}for(var a,e=[],l=0;l<f.length;l++)a=f[l],
+a.title!==""&&!a.groupAnnotation&&e.push(a);f=e;if(f.length===0)return null;var o=this,q=this._tooltipDiv.ownerDocument,r=this._view,p=r.getModel(),t=p.getBaseModel?p.getBaseModel():p;if(f.length===1)if(a=f[0],a.title!==void 0){a=b(a);if(a.firstChild)(f=a.firstChild.className)&&(f+=" "),f+="single",a.firstChild.className=f;return a}else return f=new i.ProjectionTextModel(t),e=t.getLineStart(t.getLineAtOffset(a.start)),l=t.getCharCount(),a.end!==l&&f.addProjection({start:a.end,end:l}),e>0&&f.addProjection({start:0,
+end:e}),f;else{e=d.createElement(q,"div");a=d.createElement(q,"em");a.appendChild(q.createTextNode(k.multipleAnnotations));e.appendChild(a);for(l=0;l<f.length;l++)a=f[l],(a=b(a))&&e.appendChild(a);return e}},_getNodeStyle:function(c,d,b){var a;if(c&&(a=c.style[d],!a))if(c.currentStyle){for(a=0;(a=d.indexOf("-",a))!==-1;)d=d.substring(0,a)+d.substring(a+1,a+2).toUpperCase()+d.substring(a+2);a=c.currentStyle[d]}else a=(c=c.ownerDocument.defaultView.getComputedStyle(c,null))?c.getPropertyValue(d):null;
+return a||b},_isNode:function(c){return typeof Node==="object"?c instanceof Node:c&&typeof c==="object"&&typeof c.nodeType==="number"&&typeof c.nodeName==="string"}};return{Tooltip:f}});
+define("orion/editor/rulers",["i18n!orion/editor/nls/messages","orion/editor/annotations","orion/editor/tooltip","orion/util"],function(k,m,n,i){function c(b,a,e,c){this._location=a||"left";this._overview=e||"page";this._rulerStyle=c;this._view=null;var d=this;this._listener={onTextModelChanged:function(a){d._onTextModelChanged(a)},onAnnotationModelChanged:function(a){d._onAnnotationModelChanged(a)}};this.setAnnotationModel(b)}function d(b,a,e,l,d){c.call(this,b,a,"page",e);this._oddStyle=l||{style:{backgroundColor:"white"}};
+this._evenStyle=d||{style:{backgroundColor:"white"}};this._numOfDigits=0;this._firstLine=1}function f(b,a,e){c.call(this,b,a,"page",e)}function g(b,a,e){c.call(this,b,a,"document",e)}function h(b,a,e){f.call(this,b,a,e)}c.prototype={getAnnotations:function(b,a){var e=this._annotationModel;if(!e)return[];var c=this._view.getModel(),d=c.getLineStart(b),f=c.getLineEnd(a-1),g=c;c.getBaseModel&&(g=c.getBaseModel(),d=c.mapOffset(d),f=c.mapOffset(f));for(var h=[],e=this.getAnnotationsByType(e,d,f),d=0;d<
+e.length;d++)for(var f=e[d],i=g.getLineAtOffset(f.start),v=g.getLineAtOffset(Math.max(f.start,f.end-1)),s=i;s<=v;s++){var u=s;if(c!==g){u=g.getLineStart(s);u=c.mapOffset(u,!0);if(u===-1)continue;u=c.getLineAtOffset(u)}if(b<=u&&u<a){var j=this._mergeAnnotation(h[u],f,s-i,v-i+1);j&&(h[u]=j)}}if(!this._multiAnnotation&&this._multiAnnotationOverlay)for(var k in h)h[k]._multiple&&(h[k].html+=this._multiAnnotationOverlay.html);return h},getAnnotationModel:function(){return this._annotationModel},getLocation:function(){return this._location},
+getOverview:function(){return this._overview},getRulerStyle:function(){return this._rulerStyle},getView:function(){return this._view},getWidestAnnotation:function(){return null},setAnnotationModel:function(b){this._annotationModel&&this._annotationModel.removEventListener("Changed",this._listener.onAnnotationModelChanged);(this._annotationModel=b)&&this._annotationModel.addEventListener("Changed",this._listener.onAnnotationModelChanged)},setMultiAnnotation:function(b){this._multiAnnotation=b},setMultiAnnotationOverlay:function(b){this._multiAnnotationOverlay=
+b},setView:function(b){this._onTextModelChanged&&this._view&&this._view.removeEventListener("ModelChanged",this._listener.onTextModelChanged);this._view=b;this._onTextModelChanged&&this._view&&this._view.addEventListener("ModelChanged",this._listener.onTextModelChanged)},onClick:function(b){if(b!==void 0){var a=this._view,e=a.getModel(),c=e,d=e.getLineStart(b),f=d,g=d,h=this._annotationModel;if(h){a=a.getSelection();g=e.getLineEnd(b,!0);if(d<=a.start&&a.start<g)d=a.start;e.getBaseModel&&(d=e.mapOffset(d),
+g=e.mapOffset(g),c=e.getBaseModel());for(var i,g=h.getAnnotations(d,g),h=null;!i&&g.hasNext();)a=g.next(),this.isAnnotationTypeVisible(a.type)&&(h=a,a.start<=d||(i=a));if(h&&h.groupId!==void 0)this._currentClickGroup=this._currentClickGroup===h.groupId?null:h.groupId,this._setCurrentGroup(b);i&&c.getLineAtOffset(i.start)===c.getLineAtOffset(d)?(d=i.start,g=i.end):g=d=f;e.getBaseModel&&(d=e.mapOffset(d,!0),g=e.mapOffset(g,!0))}(b=n.Tooltip.getTooltip(this._view))&&b.setTarget(null);this._view.setSelection(g,
+d,1/3,function(){})}},onDblClick:function(){},onMouseMove:function(b,a){var e=n.Tooltip.getTooltip(this._view);if(e&&!(e.isVisible()&&this._tooltipLineIndex===b)){this._tooltipLineIndex=b;var c=this;e.setTarget({y:a.clientY,getTooltipInfo:function(){return c._getTooltipInfo(c._tooltipLineIndex,this.y)}})}},onMouseOver:function(b,a){this.onMouseMove(b,a);this._currentClickGroup||this._setCurrentGroup(b)},onMouseOut:function(){this._currentClickGroup||this._setCurrentGroup(-1);var b=n.Tooltip.getTooltip(this._view);
+b&&b.setTarget(null)},_getTooltipInfo:function(b,a){if(b!==void 0){var e=this._view,c=e.getModel(),d=this._annotationModel,f=[];if(d){var f=c.getLineStart(b),g=c.getLineEnd(b);c.getBaseModel&&(f=c.mapOffset(f),g=c.mapOffset(g));f=this.getAnnotationsByType(d,f,g)}d=this._getTooltipContents(b,f);if(!d)return null;d={contents:d,anchor:this.getLocation()};f=e.getClientArea();f.y=this.getOverview()==="document"?e.convert({y:a},"view","document").y:e.getLocationAtOffset(c.getLineStart(b)).y;e.convert(f,
+"document","page");d.x=f.x;d.y=f.y;d.anchor==="right"&&(d.x+=f.width);return d}},_getTooltipContents:function(b,a){return a},_onAnnotationModelChanged:function(b){function a(a){for(var b=0;b<a.length;b++)if(d.isAnnotationTypeVisible(a[b].type)){var f=a[b].start,g=a[b].end;c.getBaseModel&&(f=c.mapOffset(f,!0),g=c.mapOffset(g,!0));f!==-1&&g!==-1&&e.redrawLines(c.getLineAtOffset(f),c.getLineAtOffset(Math.max(f,g-1))+1,d)}}var e=this._view;if(e){var c=e.getModel(),d=this,f=c.getLineCount();b.textModelChangedEvent?
+(b=b.textModelChangedEvent.start,c.getBaseModel&&(b=c.mapOffset(b,!0)),b=c.getLineAtOffset(b),e.redrawLines(b,f,d)):(a(b.added),a(b.removed),a(b.changed))}},_mergeAnnotation:function(b,a,e){b||(b={});if(e===0)if(b.html&&a.html){if(a.html!==b.html&&!b._multiple&&this._multiAnnotation)b.html=this._multiAnnotation.html;b._multiple=!0}else b.html=a.html;b.style=this._mergeStyle(b.style,a.style);return b},_mergeStyle:function(b,a){if(a){b||(b={});b.styleClass&&a.styleClass&&b.styleClass!==a.styleClass?
+b.styleClass+=" "+a.styleClass:b.styleClass=a.styleClass;var e;if(a.style){if(!b.style)b.style={};for(e in a.style)b.style[e]===void 0&&(b.style[e]=a.style[e])}if(a.attributes){if(!b.attributes)b.attributes={};for(e in a.attributes)b.attributes[e]===void 0&&(b.attributes[e]=a.attributes[e])}}return b},_setCurrentGroup:function(b){var a=this._annotationModel,e=null,c=a.getTextModel(),d,f=this._currentGroupAnnotation;if(b!==-1){var g=c.getLineStart(b),h=c.getLineEnd(b);c.getBaseModel&&(g=c.mapOffset(g),
+h=c.mapOffset(h));for(d=a.getAnnotations(g,h);d.hasNext();)if(c=d.next(),this.isAnnotationTypeVisible(c.type)&&c.start<=g&&c.end>=h&&c.groupId!==void 0){e=c;break}if(f&&e&&f.groupId===e.groupId)return}this._currentGroupAnnotation=null;f&&a.removeAnnotations(f.groupType);if(e&&b!==-1){this._currentGroupAnnotation=e;d=a.getAnnotations();for(b=[];d.hasNext();)c=d.next(),delete c.groupAnnotation,c.groupId===e.groupId&&(c=c.createGroupAnnotation(),b.push(c));a.replaceAnnotations(null,b)}}};m.AnnotationTypeList.addMixin(c.prototype);
+d.prototype=new c;d.prototype.getAnnotations=function(b,a){for(var e=c.prototype.getAnnotations.call(this,b,a),d=this._view.getModel(),f=b;f<a;f++){var g=f&1?this._oddStyle:this._evenStyle,h=f;d.getBaseModel&&(h=d.getLineStart(h),h=d.getBaseModel().getLineAtOffset(d.mapOffset(h)));e[f]||(e[f]={});e[f].html=this._firstLine+h+"";if(!e[f].style)e[f].style=g}return e};d.prototype.getWidestAnnotation=function(){var b=this._view.getModel().getLineCount();return this.getAnnotations(b-1,b)[b-1]};d.prototype.setFirstLine=
+function(b){this._firstLine=b!==void 0?b:1};d.prototype._onTextModelChanged=function(b){var b=b.start,a=this._view.getModel(),e=(this._firstLine+(a.getBaseModel?a.getBaseModel().getLineCount():a.getLineCount())-1+"").length;if(this._numOfDigits!==e)this._numOfDigits=e,this._view.redrawLines(a.getLineAtOffset(b),a.getLineCount(),this)};f.prototype=new c;g.prototype=new c;g.prototype.getRulerStyle=function(){var b={style:{lineHeight:"1px",fontSize:"1px"}};return b=this._mergeStyle(b,this._rulerStyle)};
+g.prototype._getTooltipContents=function(b,a){if(a.length===0){var e=this._view.getModel(),d=b;e.getBaseModel&&(d=e.getLineStart(d),d=e.getBaseModel().getLineAtOffset(e.mapOffset(d)));return i.formatMessage(k.line,d+1)}return c.prototype._getTooltipContents.call(this,b,a)};g.prototype._mergeAnnotation=function(b,a,e,c){if(e===0){if(!b)b={html:"&nbsp;",style:{style:{height:3*c+"px"}}},b.style=this._mergeStyle(b.style,a.overviewStyle);return b}};h.prototype=new f;h.prototype.onClick=function(b){if(b!==
+void 0){var a=this._annotationModel;if(a){var e=this._view.getModel(),c=e.getLineStart(b),b=e.getLineEnd(b,!0);e.getBaseModel&&(c=e.mapOffset(c),b=e.mapOffset(b),e=e.getBaseModel());for(var d,a=a.getAnnotations(c,b);!d&&a.hasNext();)b=a.next(),this.isAnnotationTypeVisible(b.type)&&(d=b);d&&e.getLineAtOffset(d.start)===e.getLineAtOffset(c)&&((e=n.Tooltip.getTooltip(this._view))&&e.setTarget(null),d.expanded?d.collapse():d.expand())}}};h.prototype._getTooltipContents=function(b,a){return a.length===
+1&&a[0].expanded?null:f.prototype._getTooltipContents.call(this,b,a)};h.prototype._onAnnotationModelChanged=function(b){function a(a){for(g=0;g<a.length;g++)if(d.isAnnotationTypeVisible(a[g].type)){var b=a[g].start;c.getBaseModel&&(b=c.mapOffset(b,!0));b!==-1&&(p=Math.min(p,c.getLineAtOffset(b)))}}if(b.textModelChangedEvent)f.prototype._onAnnotationModelChanged.call(this,b);else{var e=this._view;if(e){var c=e.getModel(),d=this,g,h=c.getLineCount(),p=h;a(b.added);a(b.removed);a(b.changed);b=e.getRulers();
+for(g=0;g<b.length;g++)e.redrawLines(p,h,b[g])}}};return{Ruler:c,AnnotationRuler:f,LineNumberRuler:d,OverviewRuler:g,FoldingRuler:h}});
+define("orion/editor/undoStack",[],function(){function k(i,c,d,f,g){this.model=i;this.offset=c;this.text=d;this.previousText=f;this.type=g}function m(i){this.owner=i;this.changes=[]}function n(i,c){this.size=c!==void 0?c:100;this.reset();var d=this;this._listener={onChanging:function(c){d._onChanging(c)},onDestroy:function(c){d._onDestroy(c)}};if(i.getModel){var f=i.getModel();f.getBaseModel&&(f=f.getBaseModel());this.model=f;this.setView(i)}else this.shared=!0,this.model=i;this.model.addEventListener("Changing",
+this._listener.onChanging)}k.prototype={getRedoChanges:function(){return[{start:this.offset,end:this.offset+this.previousText.length,text:this.text}]},getUndoChanges:function(){return[{start:this.offset,end:this.offset+this.text.length,text:this.previousText}]},undo:function(i,c){this._doUndoRedo(this.offset,this.previousText,this.text,i,c);return!0},redo:function(i,c){this._doUndoRedo(this.offset,this.text,this.previousText,i,c);return!0},merge:function(i,c,d,f,g){if(f===this.type)if(f===1&&i===
+this.offset+this.text.length)return this.text+=c,!0;else if(f===-1&&g===this.offset)return this.offset=i,this.previousText=d+this.previousText,!0;else if(f===-1&&i===this.offset)return this.previousText+=d,!0;return!1},_doUndoRedo:function(i,c,d,f,g){this.model.setText(c,i,i+d.length);g&&f&&(d=f.getModel(),d!==this.model&&(i=d.mapOffset(i,!0)),f.setSelection(i,i+c.length))}};m.prototype={getRedoChanges:function(){for(var i=[],c=0;c<this.changes.length;c++)i=i.concat(this.changes[c].getRedoChanges());
+return i},getUndoChanges:function(){for(var i=[],c=this.changes.length-1;c>=0;c--)i=i.concat(this.changes[c].getUndoChanges());return i},add:function(i){this.changes.push(i)},end:function(i){if(i)this.endSelection=i.getSelection(),this.endCaret=i.getCaretOffset();(i=this.owner)&&i.end&&i.end()},undo:function(i,c){this.changes.length>1&&i&&i.setRedraw(!1);for(var d=this.changes.length-1;d>=0;d--)this.changes[d].undo(i,!1);this.changes.length>1&&i&&i.setRedraw(!0);if(c&&i){var d=this.startSelection.start,
+f=this.startSelection.end;i.setSelection(this.startCaret?d:f,this.startCaret?f:d)}(d=this.owner)&&d.undo&&d.undo();return this.changes.length>0},redo:function(i,c){this.changes.length>1&&i&&i.setRedraw(!1);for(var d=0;d<this.changes.length;d++)this.changes[d].redo(i,!1);i&&i.setRedraw(!0);if(c&&i){var d=this.endSelection.start,f=this.endSelection.end;i.setSelection(this.endCaret?d:f,this.endCaret?f:d)}(d=this.owner)&&d.redo&&d.redo();return this.changes.length>0},merge:function(i,c,d,f,g){var h=this.changes.length;
+return h>0?this.changes[h-1].merge(i,c,d,f,g):!1},start:function(i){if(i)this.startSelection=i.getSelection(),this.startCaret=i.getCaretOffset();(i=this.owner)&&i.start&&i.start()}};n.prototype={destroy:function(){this._onDestroy()},add:function(i){this.compoundChange?this.compoundChange.add(i):(this.stack.splice(this.index,this.stack.length-this.index,i),this.index++,this.stack.length>this.size&&(this.stack.shift(),this.index--))},markClean:function(){this._commitUndo();if(this.cleanChange=this.stack[this.index-
+1])this.cleanChange.type=2},isClean:function(){return this.cleanChange===this.stack[this.index-1]},canUndo:function(){return this.index>0},canRedo:function(){return this.stack.length-this.index>0},endCompoundChange:function(){this.compoundChange&&this.compoundChange.end(this.view);this.compoundChange=void 0},getSize:function(){return{undo:this.index,redo:this.stack.length-this.index}},getRedoChanges:function(){this._commitUndo();for(var i=[],c=this.index;c<this.stack.length;c++)i=i.concat(this.stack[c].getRedoChanges());
+return i},getUndoChanges:function(){this._commitUndo();for(var i=[],c=this.index;c>=0;c--)i=i.concat(this.stack[c].getUndoChanges());return i},undo:function(){this._commitUndo();var i;i=!1;this._ignoreUndo=!0;do{if(this.index<=0)break;i=this.stack[--this.index]}while(!(i=i.undo(this.view,!0)));this._ignoreUndo=!1;return i},redo:function(){this._commitUndo();var i;this._ignoreUndo=!0;do{if(this.index>=this.stack.length)break;i=this.stack[this.index++]}while(!i.redo(this.view,!0));this._ignoreUndo=
+!1;return!0},reset:function(){this.index=0;this.cleanChange=void 0;this.stack=[];this._ignoreUndo=!1;this._compoundChange=void 0},setView:function(i){if(this.view!==i)this.view&&i.removeEventListener("Destroy",this._listener.onDestroy),(this.view=i)&&i.addEventListener("Destroy",this._listener.onDestroy)},startCompoundChange:function(i){this._commitUndo();i=new m(i);this.add(i);this.compoundChange=i;this.compoundChange.start(this.view);return this.compoundChange},_commitUndo:function(){this.endCompoundChange()},
+_onDestroy:function(i){(!i||!this.shared)&&this.model.removeEventListener("Changing",this._listener.onChanging);if(this.view)this.view.removeEventListener("Destroy",this._listener.onDestroy),this.view=null},_onChanging:function(i){if(!this._ignoreUndo){var c=i.text,d=i.start,f=i.addedCharCount,g=i.removedCharCount,i=d+g,h=0;f===0&&g===1?h=-1:f===1&&g===0&&(h=1);f=this.stack.length;g=this.model.getText(d,i);(!(f>0&&this.index===f)||!this.stack[f-1].merge(d,c,g,h,i))&&this.add(new k(this.model,d,c,
+g,h))}}};return{UndoStack:n}});
+define("orion/editor/textDND",["orion/util"],function(k){function m(k,i){this._view=k;this._undoStack=i;this._dragSelection=null;this._dropOffset=-1;this._dropText=null;var c=this;this._listener={onDragStart:function(d){c._onDragStart(d)},onDragEnd:function(d){c._onDragEnd(d)},onDragEnter:function(d){c._onDragEnter(d)},onDragOver:function(d){c._onDragOver(d)},onDrop:function(d){c._onDrop(d)},onDestroy:function(d){c._onDestroy(d)}};k.addEventListener("DragStart",this._listener.onDragStart);k.addEventListener("DragEnd",
+this._listener.onDragEnd);k.addEventListener("DragEnter",this._listener.onDragEnter);k.addEventListener("DragOver",this._listener.onDragOver);k.addEventListener("Drop",this._listener.onDrop);k.addEventListener("Destroy",this._listener.onDestroy)}m.prototype={destroy:function(){var k=this._view;if(k)k.removeEventListener("DragStart",this._listener.onDragStart),k.removeEventListener("DragEnd",this._listener.onDragEnd),k.removeEventListener("DragEnter",this._listener.onDragEnter),k.removeEventListener("DragOver",
+this._listener.onDragOver),k.removeEventListener("Drop",this._listener.onDrop),k.removeEventListener("Destroy",this._listener.onDestroy),this._view=null},_onDestroy:function(){this.destroy()},_onDragStart:function(k){var i=this._view,c=i.getSelection(),i=i.getModel();if(i.getBaseModel)c.start=i.mapOffset(c.start),c.end=i.mapOffset(c.end),i=i.getBaseModel();if(i=i.getText(c.start,c.end))this._dragSelection=c,k.event.dataTransfer.effectAllowed="copyMove",k.event.dataTransfer.setData("Text",i)},_onDragEnd:function(m){if(this._dragSelection){var i=
+this._view,c=m.event.dataTransfer.dropEffect;if(!k.isFirefox&&(c!=="none"||this._dropText))c=m.event.dataTransfer.dropEffect=this._dropEffect;this._undoStack&&this._undoStack.startCompoundChange();(m=c==="move")&&i.setText("",this._dragSelection.start,this._dragSelection.end);if(this._dropText){var c=this._dropText,d=this._dropOffset;if(m)if(d>=this._dragSelection.end)d-=this._dragSelection.end-this._dragSelection.start;else if(d>=this._dragSelection.start)d=this._dragSelection.start;i.setText(c,
+d,d);i.setSelection(d,d+c.length);this._dropText=null;this._dropOffset=-1}this._undoStack&&this._undoStack.endCompoundChange()}this._dragSelection=null},_onDragEnter:function(k){this._onDragOver(k)},_onDragOver:function(m){var i=m.event.dataTransfer.types,c=!this._view.getOptions("readonly");c&&i&&(c=i.contains?i.contains("text/plain")||i.contains("Text"):i.indexOf("text/plain")!==-1||i.indexOf("Text")!==-1);if(c){if(!k.isFirefox)this._dropEffect=m.event.dataTransfer.dropEffect=(k.isMac?m.event.altKey:
+m.event.ctrlKey)?"copy":"move"}else m.event.dataTransfer.dropEffect="none"},_onDrop:function(m){var i=this._view,c=m.event.dataTransfer.getData("Text");if(c){if(!k.isFirefox)m.event.dataTransfer.dropEffect=this._dropEffect;m=i.getOffsetAtLocation(m.x,m.y);this._dragSelection?(this._dropOffset=m,this._dropText=c):(i.setText(c,m,m),i.setSelection(m,m+c.length))}}};return{TextDND:m}});
+define("orion/objects",[],function(){function k(k){for(var n=1;n<arguments.length;n++){var i=arguments[n],c;for(c in i)Object.prototype.hasOwnProperty.call(i,c)&&(k[c]=i[c])}return k}return{clone:function(m){if(Array.isArray(m))return Array.prototype.slice.call(m);var n=Object.create(Object.getPrototypeOf(m));k(n,m);return n},mixin:k,toArray:function(k){return Array.isArray(k)?k:[k]}}});
+define("orion/editor/editor","i18n!orion/editor/nls/messages,orion/editor/eventTarget,orion/editor/tooltip,orion/editor/annotations,orion/objects,orion/util".split(","),function(k,m,n,i,c,d){function f(b){b=b||{};this._domNode=b.domNode;this._model=b.model;this._undoStack=b.undoStack;this._statusReporter=b.statusReporter;this._title=null;var a=this;this._listener={onChanged:function(b){a.onChanged(b)}};this._model&&this._model.addEventListener("Changed",this._listener.onChanged);this.checkDirty()}
+function g(b){b=b||{};f.call(this,b);this._textViewFactory=b.textViewFactory;this._undoStackFactory=b.undoStackFactory;this._textDNDFactory=b.textDNDFactory;this._annotationFactory=b.annotationFactory;this._foldingRulerFactory=b.foldingRulerFactory;this._lineNumberRulerFactory=b.lineNumberRulerFactory;this._contentAssistFactory=b.contentAssistFactory;this._keyBindingFactory=b.keyBindingFactory;this._contentAssist=this._foldingRuler=this._overviewRuler=this._lineNumberRuler=this._annotationRuler=this._annotationModel=
+this._annotationStyler=null}var h=i.AnnotationType;f.prototype={destroy:function(){this.uninstall();this._statusReporter=this._domNode=null;this._model&&this._model.removeEventListener("Changed",this._listener.onChanged)},checkDirty:function(){this.setDirty(this._undoStack&&!this._undoStack.isClean())},focus:function(){},getModel:function(){return this._model},getText:function(b,a){return this.getModel().getText(b,a)},getTitle:function(){return this._title},getUndoStack:function(){return this._undoStack},
+install:function(){this.installed=!0},isDirty:function(){return this._dirty},markClean:function(){this.getUndoStack().markClean();this.setDirty(!1)},onDirtyChanged:function(b){return this.dispatchEvent(b)},onInputChanged:function(b){return this.dispatchEvent(b)},onChanged:function(){this.checkDirty()},reportStatus:function(b,a,e){this._statusReporter&&this._statusReporter(b,a,e)},resize:function(){},setDirty:function(b){if(this._dirty!==b)this._dirty=b,this.onDirtyChanged({type:"DirtyChanged"})},
+_setModelText:function(b){this._model&&this._model.setText(b)},setInput:function(b,a,e,c){this._title=b;c||(a?this.reportStatus(a,"error"):e!==null&&e!==void 0&&typeof e==="string"&&this._setModelText(e),this._undoStack&&this._undoStack.reset());this.checkDirty();this.onInputChanged({type:"InputChanged",title:b,message:a,contents:e,contentsSaved:c})},setText:function(b,a,e){this.getModel().setText(b,a,e)},uninstall:function(){this.installed=!1}};m.EventTarget.addMixin(f.prototype);g.prototype=new f;
+c.mixin(g.prototype,{destroy:function(){f.prototype.destroy.call(this);this._textViewFactory=this._undoStackFactory=this._textDNDFactory=this._annotationFactory=this._foldingRulerFactory=this._lineNumberRulerFactory=this._contentAssistFactory=this._keyBindingFactory=null},getAnnotationModel:function(){return this._annotationModel},getAnnotationRuler:function(){return this._annotationRuler},getAnnotationStyler:function(){return this._annotationStyler},getContentAssist:function(){return this._contentAssist},
+getFoldingRuler:function(){return this._foldingRuler},getLineNumberRuler:function(){return this._lineNumberRuler},getModel:function(){if(!this._textView)return null;var b=this._textView.getModel();b.getBaseModel&&(b=b.getBaseModel());return b},getOverviewRuler:function(){return this._overviewRuler},getTextView:function(){return this._textView},getKeyModes:function(){return this._textView.getKeyModes()},getSourceCodeActions:function(){return this._sourceCodeActions},getLinkedMode:function(){return this._linkedMode},
+getTextActions:function(){return this._textActions},focus:function(){this._textView&&this._textView.focus()},resize:function(){this._textView&&this._textView.resize()},setAnnotationRulerVisible:function(b,a){if(this._annotationRulerVisible!==b||a)if(this._annotationRulerVisible=b,this._annotationRuler){var e=this._textView;b?e.addRuler(this._annotationRuler,0):e.removeRuler(this._annotationRuler)}},setFoldingRulerVisible:function(b,a){if(this._foldingRulerVisible!==b||a)if(this._foldingRulerVisible=
+b,this._foldingRuler){var e=this._textView;e.getModel().getBaseModel&&(b?e.addRuler(this._foldingRuler):e.removeRuler(this._foldingRuler))}},setLineNumberRulerVisible:function(b,a){if(this._lineNumberRulerVisible!==b||a)if(this._lineNumberRulerVisible=b,this._lineNumberRuler){var e=this._textView;b?e.addRuler(this._lineNumberRuler,!this._annotationRulerVisible?0:1):e.removeRuler(this._lineNumberRuler)}},setOverviewRulerVisible:function(b,a){if(this._overviewRulerVisible!==b||a)if(this._overviewRulerVisible=
+b,this._overviewRuler){var e=this._textView;b?e.addRuler(this._overviewRuler):e.removeRuler(this._overviewRuler)}},mapOffset:function(b,a){var e=this._textView.getModel();e.getBaseModel&&(b=e.mapOffset(b,a));return b},getLineAtOffset:function(b){return this.getModel().getLineAtOffset(this.mapOffset(b))},getLineStart:function(b){return this.getModel().getLineStart(b)},getCaretOffset:function(){return this.mapOffset(this._textView.getCaretOffset())},getSelection:function(){var b=this._textView,a=b.getSelection(),
+b=b.getModel();if(b.getBaseModel)a.start=b.mapOffset(a.start),a.end=b.mapOffset(a.end);return a},_expandOffset:function(b){var a=this._textView.getModel(),e=this._annotationModel;if(e&&a.getBaseModel)for(b=e.getAnnotations(b,b+1);b.hasNext();)a=b.next(),a.type===h.ANNOTATION_FOLDING&&a.expand&&a.expand()},setCaretOffset:function(b,a,e){var c=this._textView,d=c.getModel();d.getBaseModel&&(this._expandOffset(b),b=d.mapOffset(b,!0));c.setCaretOffset(b,a,e)},setText:function(b,a,e){var c=this._textView,
+d=c.getModel();d.getBaseModel&&(a!==void 0&&(this._expandOffset(a),a=d.mapOffset(a,!0)),e!==void 0&&(this._expandOffset(e),e=d.mapOffset(e,!0)));c.setText(b,a,e)},setSelection:function(b,a,e,c){var d=this._textView,f=d.getModel();f.getBaseModel&&(this._expandOffset(b),this._expandOffset(a),b=f.mapOffset(b,!0),a=f.mapOffset(a,!0));d.setSelection(b,a,e,c)},moveSelection:function(b,a,e,c){var d=this._textView;this.setSelection(b,a||b,1/3,function(){(c===void 0||c)&&d.focus();e&&e()})},_getTooltipInfo:function(b,
+a){var e=this._textView,c=this.getAnnotationModel();if(!c)return null;var d=this._annotationStyler;if(!d)return null;var f=e.getOffsetAtLocation(b,a);if(f===-1)return null;f=this.mapOffset(f);d=d.getAnnotationsByType(c,f,f+1);c=[];for(f=0;f<d.length;f++)d[f].rangeStyle&&c.push(d[f]);if(c.length===0)return null;e=e.convert({x:b,y:a},"document","page");return{contents:c,anchor:"left",x:e.x+10,y:e.y+20}},_highlightCurrentLine:function(b,a){var e=this._annotationModel;if(e){var c=this._textView;if(!c.getOptions("singleMode")){var d=
+c.getModel(),f=a?d.getLineAtOffset(a.start):-1,g=d.getLineAtOffset(b.start),c=b.start===b.end,p=!a||a.start===a.end,i=d.getLineStart(g),k=d.getLineEnd(g);d.getBaseModel&&(i=d.mapOffset(i),k=d.mapOffset(k));d=this._currentLineAnnotation;if(!(f===g&&p&&c&&d&&d.start===i&&d.end===k)){var f=d?[d]:null,s;c&&(d=h.createAnnotation(h.ANNOTATION_CURRENT_LINE,i,k),s=[d]);this._currentLineAnnotation=d;e.replaceAnnotations(f,s)}}}},installTextView:function(){this.install()},install:function(){if(!this._textView){this._textView=
+this._textViewFactory();if(this._undoStackFactory)this._undoStack=this._undoStackFactory.createUndoStack(this),this.checkDirty();if(this._textDNDFactory)this._textDND=this._textDNDFactory.createTextDND(this,this._undoStack);if(this._contentAssistFactory)this._contentAssist=this._contentAssistFactory.createContentAssistMode(this).getContentAssist();var b=this,a=this._textView,e=this;this._listener={onModelChanged:function(){e.checkDirty()},onMouseOver:function(a){e._listener.onMouseMove(a)},onMouseMove:function(b){var c=
+n.Tooltip.getTooltip(a);if(c&&!(e._listener.lastMouseX===b.event.clientX&&e._listener.lastMouseY===b.event.clientY))e._listener.lastMouseX=b.event.clientX,e._listener.lastMouseY=b.event.clientY,c.setTarget({x:b.x,y:b.y,getTooltipInfo:function(){return e._getTooltipInfo(this.x,this.y)}})},onMouseOut:function(b){var c=n.Tooltip.getTooltip(a);if(c&&!(e._listener.lastMouseX===b.event.clientX&&e._listener.lastMouseY===b.event.clientY))e._listener.lastMouseX=b.event.clientX,e._listener.lastMouseY=b.event.clientY,
+c.setTarget(null)},onScroll:function(){var b=n.Tooltip.getTooltip(a);b&&b.setTarget(null,0,0)},onSelection:function(a){e._updateCursorStatus();e._highlightCurrentLine(a.newValue,a.oldValue)}};a.addEventListener("ModelChanged",this._listener.onModelChanged);a.addEventListener("Selection",this._listener.onSelection);a.addEventListener("MouseOver",this._listener.onMouseOver);a.addEventListener("MouseOut",this._listener.onMouseOut);a.addEventListener("MouseMove",this._listener.onMouseMove);a.addEventListener("Scroll",
+this._listener.onScroll);if(this._keyBindingFactory){var c;if(c=typeof this._keyBindingFactory==="function"?this._keyBindingFactory(this,this.getKeyModes(),this._undoStack,this._contentAssist):this._keyBindingFactory.createKeyBindings(b,this._undoStack,this._contentAssist))this._textActions=c.textActions,this._linkedMode=c.linkedMode,this._sourceCodeActions=c.sourceCodeActions}c=function(a){if(a!==void 0&&a!==-1){for(var e=this.getView().getModel(),c=this.getAnnotationModel(),d=b.mapOffset(e.getLineStart(a)),
+a=b.mapOffset(e.getLineEnd(a)),e=c.getAnnotations(d,a),f=null;e.hasNext();){var l=e.next();if(l.type===h.ANNOTATION_BOOKMARK){f=l;break}}f?c.removeAnnotation(f):(f=h.createAnnotation(h.ANNOTATION_BOOKMARK,d,a),f.title=void 0,c.addAnnotation(f))}};if(this._annotationFactory){var d=a.getModel();d.getBaseModel&&(d=d.getBaseModel());if(this._annotationModel=this._annotationFactory.createAnnotationModel(d))if(d=this._annotationStyler=this._annotationFactory.createAnnotationStyler(a,this._annotationModel))d.addAnnotationType(h.ANNOTATION_CURRENT_SEARCH),
+d.addAnnotationType(h.ANNOTATION_MATCHING_SEARCH),d.addAnnotationType(h.ANNOTATION_ERROR),d.addAnnotationType(h.ANNOTATION_WARNING),d.addAnnotationType(h.ANNOTATION_MATCHING_BRACKET),d.addAnnotationType(h.ANNOTATION_CURRENT_BRACKET),d.addAnnotationType(h.ANNOTATION_CURRENT_LINE),d.addAnnotationType(h.ANNOTATION_READ_OCCURRENCE),d.addAnnotationType(h.ANNOTATION_WRITE_OCCURRENCE),d.addAnnotationType(h.ANNOTATION_SELECTED_LINKED_GROUP),d.addAnnotationType(h.ANNOTATION_CURRENT_LINKED_GROUP),d.addAnnotationType(h.ANNOTATION_LINKED_GROUP),
+d.addAnnotationType("orion.annotation.highlightError");var d=this._annotationFactory.createAnnotationRulers(this._annotationModel),g=this._annotationRuler=d.annotationRuler;if(g)g.onDblClick=c,g.setMultiAnnotationOverlay({html:"<div class='annotationHTML overlay'></div>"}),g.addAnnotationType(h.ANNOTATION_ERROR),g.addAnnotationType(h.ANNOTATION_WARNING),g.addAnnotationType(h.ANNOTATION_TASK),g.addAnnotationType(h.ANNOTATION_BOOKMARK);this.setAnnotationRulerVisible(this._annotationRulerVisible||this._annotationRulerVisible===
+void 0,!0);if(g=this._overviewRuler=d.overviewRuler)g.addAnnotationType(h.ANNOTATION_CURRENT_SEARCH),g.addAnnotationType(h.ANNOTATION_MATCHING_SEARCH),g.addAnnotationType(h.ANNOTATION_READ_OCCURRENCE),g.addAnnotationType(h.ANNOTATION_WRITE_OCCURRENCE),g.addAnnotationType(h.ANNOTATION_CURRENT_BLAME),g.addAnnotationType(h.ANNOTATION_ERROR),g.addAnnotationType(h.ANNOTATION_WARNING),g.addAnnotationType(h.ANNOTATION_TASK),g.addAnnotationType(h.ANNOTATION_BOOKMARK),g.addAnnotationType(h.ANNOTATION_MATCHING_BRACKET),
+g.addAnnotationType(h.ANNOTATION_CURRENT_BRACKET),g.addAnnotationType(h.ANNOTATION_CURRENT_LINE);this.setOverviewRulerVisible(this._overviewRulerVisible||this._overviewRulerVisible===void 0,!0)}if(this._lineNumberRulerFactory)this._lineNumberRuler=this._lineNumberRulerFactory.createLineNumberRuler(this._annotationModel),this._lineNumberRuler.addAnnotationType(h.ANNOTATION_CURRENT_BLAME),this._lineNumberRuler.addAnnotationType(h.ANNOTATION_BLAME),this._lineNumberRuler.onDblClick=c,this.setLineNumberRulerVisible(this._lineNumberRulerVisible||
+this._lineNumberRulerVisible===void 0,!0);if(this._foldingRulerFactory)this._foldingRuler=this._foldingRulerFactory.createFoldingRuler(this._annotationModel),this._foldingRuler.addAnnotationType(h.ANNOTATION_FOLDING),this.setFoldingRulerVisible(this._foldingRulerVisible||this._foldingRulerVisible===void 0,!0);this.dispatchEvent({type:"TextViewInstalled",textView:a});f.prototype.install.call(this)}},uninstallTextView:function(){this.uninstall()},uninstall:function(){var b=this._textView;if(b)b.destroy(),
+this._textView=this._undoStack=this._textDND=this._contentAssist=this._listener=this._annotationModel=this._annotationStyler=this._annotationRuler=this._overviewRuler=this._lineNumberRuler=this._foldingRuler=this._currentLineAnnotation=this._title=null,this._dirty=!1,this._foldingRulerVisible=this._overviewRulerVisible=this._lineNumberRulerVisible=this._annotationRulerVisible=void 0,this.dispatchEvent({type:"TextViewUninstalled",textView:b}),f.prototype.uninstall.call(this)},_updateCursorStatus:function(){var b=
+this.getModel(),a=this.getCaretOffset(),e=b.getLineAtOffset(a),b=b.getLineStart(e);a-=b;for(var b=this.getKeyModes(),c=0;c<b.length;c++){var f=b[c];if(f.isActive()&&f.isStatusActive&&f.isStatusActive())return}this.reportStatus(d.formatMessage(k.lineColumn,e+1,a+1))},showAnnotations:function(b,a,e,c){var d=this._annotationModel;if(d){for(var f=[],g=[],i=d.getTextModel(),t=d.getAnnotations(),k;t.hasNext();)k=t.next(),a.indexOf(k.type)!==-1&&k.creatorID===this&&f.push(k);if(b)for(a=0;a<b.length;a++)if(k=
+b[a]){if(e)k=e(k);else{var s;typeof k.line==="number"?(s=i.getLineStart(k.line-1),t=s+k.start-1,s=s+k.end-1):(t=k.start,s=k.end);var u=c(k);if(!u)continue;k=h.createAnnotation(u,t,s,k.description)}k.creatorID=this;g.push(k)}d.replaceAnnotations(f,g)}},showProblems:function(b){this.showAnnotations(b,[h.ANNOTATION_ERROR,h.ANNOTATION_WARNING,h.ANNOTATION_TASK],null,function(a){switch(a.severity){case "error":return h.ANNOTATION_ERROR;case "warning":return h.ANNOTATION_WARNING;case "task":return h.ANNOTATION_TASK}return null})},
+showOccurrences:function(b){this.showAnnotations(b,[h.ANNOTATION_READ_OCCURRENCE,h.ANNOTATION_WRITE_OCCURRENCE],null,function(a){return a.readAccess?h.ANNOTATION_READ_OCCURRENCE:h.ANNOTATION_WRITE_OCCURRENCE})},showBlame:function(b){var a=this._blameRGB,e=this.getTextView().getOptions("parent").ownerDocument;if(!a){var f=d.createElement(e,"div");f.className="annotation blame";e.body.appendChild(f);var g=(e.defaultView||e.parentWindow).getComputedStyle(f).getPropertyValue("background-color");f.parentNode.removeChild(f);
+var f=g.indexOf("("),q=g.indexOf(")"),g=g.substring(f+1,q);this._blameRGB=a=g.split(",").slice(0,3)}var r=function(){var a=i.AnnotationType.createAnnotation(this.groupType,this.start,this.end,this.title);a.style=c.mixin({},a.style);a.style.style=c.mixin({},a.style.style);a.style.style.backgroundColor="";this.groupAnnotation=a;a.blame=this.blame;a.html=this.html;a.creatorID=this.creatorID;return a},p=function(){var a=d.createElement(e,"div");a.className="tooltipTitle";var b=this.blame.Message.indexOf("\n");
+if(b===-1)b=this.blame.Message.length;var c=d.createElement(e,"a");c.href=this.blame.CommitLink;c.appendChild(e.createTextNode(this.blame.Message.substring(0,b)));a.appendChild(c);a.appendChild(d.createElement(e,"br"));a.appendChild(e.createTextNode(d.formatMessage(k.committerOnTime,this.blame.AuthorName,this.blame.Time)));return a},t=this.getModel();this.showAnnotations(b,[h.ANNOTATION_BLAME,h.ANNOTATION_CURRENT_BLAME],function(b){var e=t.getLineStart(b.Start-1),d=t.getLineEnd(b.End-1,!0),e=i.AnnotationType.createAnnotation(h.ANNOTATION_BLAME,
+e,d,p),d=a.slice(0);d.push(b.Shade);e.style=c.mixin({},e.style);e.style.style=c.mixin({},e.style.style);e.style.style.backgroundColor="rgba("+d.join()+")";e.groupId=b.Name;e.groupType=h.ANNOTATION_CURRENT_BLAME;e.createGroupAnnotation=r;e.html='<img class="annotationHTML blame" src="'+b.AuthorImage+'"/>';e.blame=b;return e})},showSelection:function(b,a,e,c,d){typeof b==="number"?(typeof a!=="number"&&(a=b),this.moveSelection(b,a)):typeof e==="number"&&(b=this.getModel().getLineStart(e-1),typeof c===
+"number"&&(b+=c),typeof d!=="number"&&(d=0),this.moveSelection(b,b+d))},_setModelText:function(b){this._textView&&(this._textView.setText(b),this._textView.getModel().setLineDelimiter("auto"),this._highlightCurrentLine(this._textView.getSelection()))},setInput:function(b,a,e,c,d){f.prototype.setInput.call(this,b,a,e,c);this._textView&&!c&&!d&&this._textView.focus()},onGotoLine:function(b,a,e,c){if(this._textView){var d=this.getModel(),b=Math.max(0,Math.min(b,d.getLineCount()-1)),f=d.getLineStart(b),
+g=0;e===void 0&&(e=0);typeof a==="string"?(b=d.getLine(b).indexOf(a),b!==-1&&(g=b,e=g+a.length)):(g=a,a=d.getLineEnd(b)-f,g=Math.min(g,a),e=Math.min(e,a));this.moveSelection(f+g,f+e,c)}}});return{BaseEditor:f,Editor:g}});
+define("orion/editor/find","i18n!orion/editor/nls/messages,orion/keyBinding,orion/editor/keyModes,orion/editor/annotations,orion/regex,orion/objects,orion/util".split(","),function(k,m,n,i,c,d,f){function g(a){var b=a.getTextView();n.KeyMode.call(this,b);this.editor=a;this._active=!1;this._success=!0;this._ignoreSelection=!1;this._prefix="";b.setAction("incrementalFindCancel",function(){this.setActive(!1);return!0}.bind(this));b.setAction("incrementalFindBackspace",function(){return this._backspace()}.bind(this));
+var d=this;this._listener={onVerify:function(a){var b=d.editor,e=b.getModel(),f=b.mapOffset(a.start),b=b.mapOffset(a.end),e=e.getText(f,b);if((e=d._prefix.match(RegExp("^"+c.escape(e),"i")))&&e.length>0)d._prefix+=a.text,d._success=!0,d._status(),d.find(d._forward,!0),a.text=null},onSelection:function(){d._ignoreSelection||d.setActive(!1)}}}function h(a,b,c){if(a){this._editor=a;this._undoStack=b;this._showAll=!0;this._visible=!1;this._wrap=this._caseInsensitive=!0;this._wholeWord=!1;this._incremental=
+!0;this._regex=!1;this._findAfterReplace=!0;this._reverse=this._hideAfterFind=!1;this._timer=this._end=this._start=void 0;this._lastString="";var d=this;this._listeners={onEditorFocus:function(a){d._removeCurrentAnnotation(a)}};this.setOptions(c)}}var b={};g.prototype=new n.KeyMode;d.mixin(g.prototype,{createKeyBindings:function(){var a=m.KeyBinding,b=[];b.push({actionID:"incrementalFindBackspace",keyBinding:new a(8)});b.push({actionID:"incrementalFindCancel",keyBinding:new a(13)});b.push({actionID:"incrementalFindCancel",
+keyBinding:new a(27)});b.push({actionID:"incrementalFindReverse",keyBinding:new a(38)});b.push({actionID:"incrementalFind",keyBinding:new a(40)});b.push({actionID:"incrementalFindReverse",keyBinding:new a("k",!0,!0)});b.push({actionID:"incrementalFind",keyBinding:new a("k",!0)});return b},find:function(a,b){this._forward=a;if(!this.isActive())return this.setActive(!0),!1;var c=this._prefix;if(c.length===0)return!1;var d=this.editor,f=d.getModel(),f=a?this._success?b?this._start:d.getCaretOffset()+
+1:0:this._success?b?this._start:d.getCaretOffset():f.getCharCount()-1;if(c=d.getModel().find({string:c,start:f,reverse:!a,caseInsensitive:c.toLowerCase()===c}).next()){if(!b)this._start=f;this._ignoreSelection=this._success=!0;d.moveSelection(a?c.start:c.end,a?c.end:c.start);this._ignoreSelection=!1}else this._success=!1;this._status();return!0},isActive:function(){return this._active},isStatusActive:function(){return this.isActive()},setActive:function(a){if(this._active!==a)this._active=a,this._prefix=
+"",this._success=!0,a=this.editor.getTextView(),this._start=this.editor.getCaretOffset(),this.editor.setCaretOffset(this._start),this._active?(a.addEventListener("Verify",this._listener.onVerify),a.addEventListener("Selection",this._listener.onSelection),a.addKeyMode(this)):(a.removeEventListener("Verify",this._listener.onVerify),a.removeEventListener("Selection",this._listener.onSelection),a.removeKeyMode(this)),this._status()},_backspace:function(){var a=this._prefix,a=this._prefix=a.substring(0,
+a.length-1);return a.length===0?(this._ignoreSelection=this._success=!0,this.editor.setCaretOffset(this.editor.getSelection().start),this._ignoreSelection=!1,this._status(),!0):this.find(this._forward,!0)},_status:function(){if(this.isActive()){var a;a=this._forward?this._success?k.incrementalFindStr:k.incrementalFindStrNotFound:this._success?k.incrementalFindReverseStr:k.incrementalFindReverseStrNotFound;a=f.formatMessage(a,this._prefix);this.editor.reportStatus(a,this._success?"":"error")}else this.editor.reportStatus("")}});
+b.IncrementalFind=g;h.prototype={find:function(a,b,c){this.setOptions({reverse:!a});var d=this.getFindString(),f;if(b)d=b.findString||d,f=b.count;a=this.getOptions();this.setOptions(b);b=c?this._startOffset:this.getStartOffset();if((f=this._doFind(d,b,f))&&!c)this._startOffset=f.start;this.setOptions(a);this._hideAfterFind&&this.hide();return f},getStartOffset:function(){return this._start!==void 0?this._start:this._reverse?this._editor.getSelection().start-1:this._editor.getCaretOffset()},getFindString:function(){var a=
+this._editor.getSelection(),a=this._editor.getText(a.start,a.end);this._regex&&(a=c.escape(a));return a||this._lastString},getOptions:function(){return{showAll:this._showAll,caseInsensitive:this._caseInsensitive,wrap:this._wrap,wholeWord:this._wholeWord,incremental:this._incremental,regex:this._regex,findAfterReplace:this._findAfterReplace,hideAfterFind:this._hideAfterFind,reverse:this._reverse,findCallback:this._findCallback,start:this._start,end:this._end}},getReplaceString:function(){return""},
+hide:function(){this._visible=!1;if(this._savedOptions&&(this.setOptions(this._savedOptions.pop()),this._savedOptions.length===0))this._savedOptions=null;this._removeAllAnnotations();var a=this._editor.getTextView();a&&(a.removeEventListener("Focus",this._listeners.onEditorFocus),a.focus())},_processReplaceString:function(a){var b=a;if(this._regex){for(var b="",c=!1,d=this._editor.getModel().getLineDelimiter(),f=0;f<a.length;f++){var g=a.substring(f,f+1);if(c){switch(g){case "R":b+=d;break;case "r":b+=
+"\r";break;case "n":b+="\n";break;case "t":b+="\t";break;case "\\":b+="\\";break;default:b+="\\"+g}c=!1}else g==="\\"?c=!0:b+=g}c&&(b+="\\")}return b},isVisible:function(){return this._visible},replace:function(){var a=this.getFindString();if(a){var b=this._editor,c=this._processReplaceString(this.getReplaceString()),d=b.getSelection().start;if(b=b.getModel().find({string:a,start:d,reverse:!1,wrap:this._wrap,regex:this._regex,wholeWord:this._wholeWord,caseInsensitive:this._caseInsensitive}).next())this.startUndo(),
+this._doReplace(b.start,b.end,a,c),this.endUndo()}this._findAfterReplace&&a&&this._doFind(a,this.getStartOffset())},replaceAll:function(){var a=this.getFindString();if(a){this._replacingAll=!0;var b=this._editor,c=b.getTextView();b.reportStatus(k.replaceAll);var d=this._processReplaceString(this.getReplaceString()),g=this;window.setTimeout(function(){for(var h=0,i=0;;){var t=g._doFind(a,h,null,!0);if(!t)break;i++;i===1&&(c.setRedraw(!1),g.startUndo());g._doReplace(t.start,t.end,a,d);h=g.getStartOffset()}i>
+0&&(g.endUndo(),c.setRedraw(!0));h>0?b.reportStatus(f.formatMessage(k.replacedMatches,i)):b.reportStatus(k.nothingReplaced,"error");g._replacingAll=!1},100)}},setOptions:function(a){if(a){if((a.showAll===!0||a.showAll===!1)&&this._showAll!==a.showAll)if(this._showAll=a.showAll,this.isVisible())if(this._showAll)this._markAllOccurrences();else{var b=this._editor.getAnnotationModel();b&&b.removeAnnotations(i.AnnotationType.ANNOTATION_MATCHING_SEARCH)}if(a.caseInsensitive===!0||a.caseInsensitive===!1)this._caseInsensitive=
+a.caseInsensitive;if(a.wrap===!0||a.wrap===!1)this._wrap=a.wrap;if(a.wholeWord===!0||a.wholeWord===!1)this._wholeWord=a.wholeWord;if(a.incremental===!0||a.incremental===!1)this._incremental=a.incremental;if(a.regex===!0||a.regex===!1)this._regex=a.regex;if(a.findAfterReplace===!0||a.findAfterReplace===!1)this._findAfterReplace=a.findAfterReplace;if(a.hideAfterFind===!0||a.hideAfterFind===!1)this._hideAfterFind=a.hideAfterFind;if(a.reverse===!0||a.reverse===!1)this._reverse=a.reverse;if(a.hasOwnProperty("findCallback"))this._findCallback=
+a.findCallback;if(a.hasOwnProperty("start"))this._start=a.start;if(a.hasOwnProperty("end"))this._end=a.end}},show:function(a){this._visible=!0;if(a){if(!this._savedOptions)this._savedOptions=[];this._savedOptions.push(this.getOptions());this.setOptions(a)}this._startOffset=this._editor.getSelection().start;this._editor.getTextView().addEventListener("Focus",this._listeners.onEditorFocus);var b=this;window.setTimeout(function(){b._incremental&&b.find(!0,null,!0)},0)},startUndo:function(){this._undoStack&&
+this._undoStack.startCompoundChange()},endUndo:function(){this._undoStack&&this._undoStack.endCompoundChange()},_find:function(a,b,c){return this._editor.getModel().find({string:a,start:b,end:this._end,reverse:this._reverse,wrap:c?!1:this._wrap,regex:this._regex,wholeWord:this._wholeWord,caseInsensitive:this._caseInsensitive})},_doFind:function(a,b,c,d){var c=c||1,f=this._editor;if(!a)return this._removeAllAnnotations(),null;this._lastString=a;var g,h;if(this._regex)try{h=this._find(a,b,d)}catch(t){f.reportStatus(t.message,
+"error");return}else h=this._find(a,b,d);for(a=0;a<c&&h.hasNext();a++)g=h.next();if(!this._replacingAll){g?this._editor.reportStatus(""):this._editor.reportStatus(k.notFound,"error");if(this.isVisible()){c=i.AnnotationType.ANNOTATION_CURRENT_SEARCH;if(h=f.getAnnotationModel())h.removeAnnotations(c),g&&h.addAnnotation(i.AnnotationType.createAnnotation(c,g.start,g.end));if(this._showAll){this._timer&&window.clearTimeout(this._timer);var v=this;this._timer=window.setTimeout(function(){v._markAllOccurrences();
+v._timer=null},500)}}this._findCallback?this._findCallback(g):g&&f.moveSelection(g.start,g.end,null,!1)}return g},_doReplace:function(a,b,c,d){var f=this._editor;if(this._regex&&(d=f.getText(a,b).replace(RegExp(c,this._caseInsensitive?"i":""),d),!d))return;f.setText(d,a,b);f.setSelection(a,a+d.length,!0)},_markAllOccurrences:function(){var a=this._editor.getAnnotationModel();if(a){for(var b=i.AnnotationType.ANNOTATION_MATCHING_SEARCH,c=a.getAnnotations(),d=[],f;c.hasNext();){var g=c.next();g.type===
+b&&d.push(g)}if(this.isVisible()){c=this.getFindString();c=this._editor.getModel().find({string:c,regex:this._regex,wholeWord:this._wholeWord,caseInsensitive:this._caseInsensitive});for(f=[];c.hasNext();)g=c.next(),f.push(i.AnnotationType.createAnnotation(b,g.start,g.end))}a.replaceAnnotations(d,f)}},_removeAllAnnotations:function(){var a=this._editor.getAnnotationModel();a&&(a.removeAnnotations(i.AnnotationType.ANNOTATION_CURRENT_SEARCH),a.removeAnnotations(i.AnnotationType.ANNOTATION_MATCHING_SEARCH))},
+_removeCurrentAnnotation:function(){var a=this._editor.getAnnotationModel();a&&a.removeAnnotations(i.AnnotationType.ANNOTATION_CURRENT_SEARCH)}};b.Find=h;return b});
+define("orion/editor/actions","i18n!orion/editor/nls/messages,orion/keyBinding,orion/editor/annotations,orion/editor/tooltip,orion/editor/find,orion/util".split(","),function(k,m,n,i,c,d){function f(a,b,d){this.editor=a;this.undoStack=b;this._incrementalFind=new c.IncrementalFind(a);this._find=d?d:new c.Find(a,b);this._lastEditLocation=null;this.init()}function g(a,b,c,d){this.editor=a;this.undoStack=b;this.contentAssist=c;this.linkedMode=d;this.contentAssist&&this.contentAssist.addEventListener("ProposalApplied",
+this.contentAssistProposalApplied.bind(this));this.init()}var h=n.AnnotationType,b={};f.prototype={init:function(){var a=this.editor.getTextView();this._lastEditListener={onModelChanged:function(a){if(this.editor.isDirty())this._lastEditLocation=a.start+a.addedCharCount}.bind(this)};a.addEventListener("ModelChanged",this._lastEditListener.onModelChanged);a.setAction("undo",function(a){if(this.undoStack){var b=1;if(a&&a.count)b=a.count;for(;b>0;)this.undoStack.undo(),--b;return!0}return!1}.bind(this),
+{name:k.undo});a.setAction("redo",function(a){if(this.undoStack){var b=1;if(a&&a.count)b=a.count;for(;b>0;)this.undoStack.redo(),--b;return!0}return!1}.bind(this),{name:k.redo});a.setKeyBinding(new m.KeyBinding("f",!0),"find");a.setAction("find",function(){if(this._find){var a=this.editor.getSelection();(a=prompt(k.find,this.editor.getText(a.start,a.end)))&&this._find.find(!0,{findString:a})}}.bind(this),{name:k.find});a.setKeyBinding(new m.KeyBinding("k",!0),"findNext");a.setAction("findNext",function(a){return this._find?
+(this._find.find(!0,a),!0):!1}.bind(this),{name:k.findNext});a.setKeyBinding(new m.KeyBinding("k",!0,!0),"findPrevious");a.setAction("findPrevious",function(a){return this._find?(this._find.find(!1,a),!0):!1}.bind(this),{name:k.findPrevious});a.setKeyBinding(new m.KeyBinding("j",!0),"incrementalFind");a.setAction("incrementalFind",function(){this._incrementalFind&&this._incrementalFind.find(!0);return!0}.bind(this),{name:k.incrementalFind});a.setKeyBinding(new m.KeyBinding("j",!0,!0),"incrementalFindReverse");
+a.setAction("incrementalFindReverse",function(){this._incrementalFind&&this._incrementalFind.find(!1);return!0}.bind(this),{name:k.incrementalFindReverse});a.setAction("tab",function(){return this.indentLines()}.bind(this));a.setAction("shiftTab",function(){return this.unindentLines()}.bind(this),{name:k.unindentLines});a.setKeyBinding(new m.KeyBinding(38,!1,!1,!0),"moveLinesUp");a.setAction("moveLinesUp",function(){return this.moveLinesUp()}.bind(this),{name:k.moveLinesUp});a.setKeyBinding(new m.KeyBinding(40,
+!1,!1,!0),"moveLinesDown");a.setAction("moveLinesDown",function(){return this.moveLinesDown()}.bind(this),{name:k.moveLinesDown});a.setKeyBinding(new m.KeyBinding(38,!0,!1,!0),"copyLinesUp");a.setAction("copyLinesUp",function(){return this.copyLinesUp()}.bind(this),{name:k.copyLinesUp});a.setKeyBinding(new m.KeyBinding(40,!0,!1,!0),"copyLinesDown");a.setAction("copyLinesDown",function(){return this.copyLinesDown()}.bind(this),{name:k.copyLinesDown});a.setKeyBinding(new m.KeyBinding("d",!0,!1,!1),
+"deleteLines");a.setAction("deleteLines",function(a){return this.deleteLines(a)}.bind(this),{name:k.deleteLines});a.setKeyBinding(new m.KeyBinding("l",!d.isMac,!1,!1,d.isMac),"gotoLine");a.setAction("gotoLine",function(){return this.gotoLine()}.bind(this),{name:k.gotoLine});a.setKeyBinding(new m.KeyBinding(190,!0),"nextAnnotation");a.setAction("nextAnnotation",function(){return this.nextAnnotation(!0)}.bind(this),{name:k.nextAnnotation});a.setKeyBinding(new m.KeyBinding(188,!0),"previousAnnotation");
+a.setAction("previousAnnotation",function(){return this.nextAnnotation(!1)}.bind(this),{name:k.prevAnnotation});a.setKeyBinding(new m.KeyBinding("e",!0,!1,!0,!1),"expand");a.setAction("expand",function(){return this.expandAnnotation(!0)}.bind(this),{name:k.expand});a.setKeyBinding(new m.KeyBinding("c",!0,!1,!0,!1),"collapse");a.setAction("collapse",function(){return this.expandAnnotation(!1)}.bind(this),{name:k.collapse});a.setKeyBinding(new m.KeyBinding("e",!0,!0,!0,!1),"expandAll");a.setAction("expandAll",
+function(){return this.expandAnnotations(!0)}.bind(this),{name:k.expandAll});a.setKeyBinding(new m.KeyBinding("c",!0,!0,!0,!1),"collapseAll");a.setAction("collapseAll",function(){return this.expandAnnotations(!1)}.bind(this),{name:k.collapseAll});a.setKeyBinding(new m.KeyBinding("q",!d.isMac,!1,!1,d.isMac),"lastEdit");a.setAction("lastEdit",function(){return this.gotoLastEdit()}.bind(this),{name:k.lastEdit})},copyLinesDown:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;
+var b=a.getModel(),c=a.getSelection(),d=b.getLineAtOffset(c.start),c=b.getLineAtOffset(c.end>c.start?c.end-1:c.end),f=b.getLineStart(d),d=b.getLineEnd(c,!0),g=b.getLineCount(),h="",f=b.getText(f,d);c===g-1&&(f=(h=b.getLineDelimiter())+f);a.setText(f,d,d);a.setSelection(d+h.length,d+f.length);return!0},copyLinesUp:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getModel(),c=a.getSelection(),d=b.getLineAtOffset(c.start),c=b.getLineAtOffset(c.end>c.start?c.end-
+1:c.end),d=b.getLineStart(d),f=b.getLineEnd(c,!0),g=b.getLineCount(),h="",f=b.getText(d,f);c===g-1&&(f+=h=b.getLineDelimiter());a.setText(f,d,d);a.setSelection(d,d+f.length-h.length);return!0},deleteLines:function(a){var b=this.editor;if(b.getTextView().getOptions("readonly"))return!1;var c=1;if(a&&a.count)c=a.count;var d=b.getSelection(),f=b.getModel(),g=f.getLineAtOffset(d.start),a=f.getLineStart(g),c=d.start!==d.end||c===1?f.getLineAtOffset(d.end>d.start?d.end-1:d.end):Math.min(g+c-1,f.getLineCount()-
+1),c=f.getLineEnd(c,!0);b.setText("",a,c);return!0},expandAnnotation:function(a){var b=this.editor,c=b.getAnnotationModel();if(!c)return!0;var d=b.getModel(),f=b.getCaretOffset(),g=d.getLineAtOffset(f),f=d.getLineStart(g),g=d.getLineEnd(g,!0);d.getBaseModel&&(f=d.mapOffset(f),g=d.mapOffset(g),d.getBaseModel());for(var h,c=c.getAnnotations(f,g);!h&&c.hasNext();)d=c.next(),d.type===n.AnnotationType.ANNOTATION_FOLDING&&(h=d);h&&a!==h.expanded&&(a?h.expand():(b.setCaretOffset(h.start),h.collapse()));
+return!0},expandAnnotations:function(a){var b=this.editor,c=b.getTextView(),d=b.getAnnotationModel();if(!d)return!0;b.getModel();d=d.getAnnotations();for(c.setRedraw(!1);d.hasNext();)b=d.next(),b.type===n.AnnotationType.ANNOTATION_FOLDING&&a!==b.expanded&&(a?b.expand():b.collapse());c.setRedraw(!0);return!0},indentLines:function(){var a=this.editor,b=a.getTextView();if(b.getOptions("readonly"))return!1;if(b.getOptions("tabMode")){var c=a.getModel(),d=a.getSelection(),f=c.getLineAtOffset(d.start),
+g=c.getLineAtOffset(d.end>d.start?d.end-1:d.end);if(f!==g){var h=[];h.push("");for(var i=f;i<=g;i++)h.push(c.getLine(i,!0));i=c.getLineStart(f);c=c.getLineEnd(g,!0);b=b.getOptions("tabSize","expandTab");b=b.expandTab?Array(b.tabSize+1).join(" "):"\t";a.setText(h.join(b),i,c);a.setSelection(i===d.start?d.start:d.start+b.length,d.end+(g-f+1)*b.length);return!0}return!1}},gotoLastEdit:function(){typeof this._lastEditLocation==="number"&&this.editor.showSelection(this._lastEditLocation);return!0},gotoLine:function(){var a=
+this.editor,b=a.getModel().getLineAtOffset(a.getCaretOffset());if(b=prompt(k.gotoLinePrompty,b+1))b=parseInt(b,10),a.onGotoLine(b-1,0);return!0},moveLinesDown:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getModel(),c=a.getSelection(),d=b.getLineAtOffset(c.start),f=b.getLineAtOffset(c.end>c.start?c.end-1:c.end),g=b.getLineCount();if(f===g-1)return!0;var d=b.getLineStart(d),c=b.getLineEnd(f,!0),h=b.getLineEnd(f+1,!0)-(c-d),i=0;f!==g-2?b=b.getText(d,c):(f=b.getLineEnd(f),
+b=b.getText(f,c)+b.getText(d,f),i+=c-f);this.startUndo();a.setText("",d,c);a.setText(b,h,h);a.setSelection(h+i,h+i+b.length);this.endUndo();return!0},moveLinesUp:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getModel(),c=a.getSelection(),d=b.getLineAtOffset(c.start);if(d===0)return!0;var f=b.getLineAtOffset(c.end>c.start?c.end-1:c.end),g=b.getLineCount(),c=b.getLineStart(d-1),h=b.getLineStart(d),i=b.getLineEnd(f,!0),k=b.getText(h,i),s=0;f===g-1&&(f=b.getLineEnd(d-
+1),d=b.getLineEnd(d-1,!0),k+=b.getText(f,d),h=f,s=d-f);this.startUndo();a.setText("",h,i);a.setText(k,c,c);a.setSelection(c,c+k.length-s);this.endUndo();return!0},nextAnnotation:function(a){function b(a){return!!a.lineStyle||a.type===h.ANNOTATION_MATCHING_BRACKET||a.type===h.ANNOTATION_CURRENT_BRACKET||!f.isAnnotationTypeVisible(a.type)}var c=this.editor,d=c.getAnnotationModel();if(!d)return!0;var f=c.getOverviewRuler()||c.getAnnotationStyler();if(!f)return!0;for(var g=c.getModel(),p=c.getCaretOffset(),
+t=d.getAnnotations(a?p:0,a?g.getCharCount():p),k=null;t.hasNext();){var s=t.next();if(a){if(s.start<=p)continue}else if(s.start>=p)continue;if(!b(s)&&(k=s,a))break}if(k){for(var u=[k],t=d.getAnnotations(k.start,k.start);t.hasNext();)s=t.next(),s!==k&&!b(s)&&u.push(s);var j=c.getTextView(),m=g.getLineAtOffset(k.start),n=i.Tooltip.getTooltip(j);if(!n)return c.moveSelection(k.start),!0;c.moveSelection(k.start,k.start,function(){n.setTarget({getTooltipInfo:function(){var a=j.convert({x:j.getLocationAtOffset(k.start).x,
+y:j.getLocationAtOffset(g.getLineStart(m)).y},"document","page");return{contents:u,x:a.x,y:a.y+Math.floor(j.getLineHeight(m)*1.33)}}},0)})}return!0},unindentLines:function(){var a=this.editor,b=a.getTextView();if(b.getOptions("readonly"))return!1;if(b.getOptions("tabMode")){for(var c=a.getModel(),d=a.getSelection(),f=c.getLineAtOffset(d.start),g=c.getLineAtOffset(d.end>d.start?d.end-1:d.end),h=b.getOptions("tabSize"),i=Array(h+1).join(" "),k=[],s=b=0,u=f;u<=g;u++){var j=c.getLine(u,!0);if(c.getLineStart(u)!==
+c.getLineEnd(u))if(j.indexOf("\t")===0)j=j.substring(1),b++;else if(j.indexOf(i)===0)j=j.substring(h),b+=h;else return!0;u===f&&(s=b);k.push(j)}f=c.getLineStart(f);h=c.getLineEnd(g,!0);c=c.getLineStart(g);a.setText(k.join(""),f,h);g=f===d.start?d.start:d.start-s;d=Math.max(g,d.end-b+(d.end===c+1&&d.start!==d.end?1:0));a.setSelection(g,d);return!0}},startUndo:function(){this.undoStack&&this.undoStack.startCompoundChange()},endUndo:function(){this.undoStack&&this.undoStack.endCompoundChange()}};b.TextActions=
+f;g.prototype={init:function(){var a=this.editor.getTextView();a.setAction("lineStart",function(){return this.lineStart()}.bind(this));a.setAction("enter",function(){return this.autoIndent()}.bind(this));a.setKeyBinding(new m.KeyBinding("t",!0,!1,!0),"trimTrailingWhitespaces");a.setAction("trimTrailingWhitespaces",function(){return this.trimTrailingWhitespaces()}.bind(this),{name:k.trimTrailingWhitespaces});a.setKeyBinding(new m.KeyBinding(191,!0),"toggleLineComment");a.setAction("toggleLineComment",
+function(){return this.toggleLineComment()}.bind(this),{name:k.toggleLineComment});a.setKeyBinding(new m.KeyBinding(191,!0,!d.isMac,!1,d.isMac),"addBlockComment");a.setAction("addBlockComment",function(){return this.addBlockComment()}.bind(this),{name:k.addBlockComment});a.setKeyBinding(new m.KeyBinding(220,!0,!d.isMac,!1,d.isMac),"removeBlockComment");a.setAction("removeBlockComment",function(){return this.removeBlockComment()}.bind(this),{name:k.removeBlockComment});a.setKeyBinding(new m.KeyBinding("[",
+!1,!1,!1,!1,"keypress"),"autoPairSquareBracket");a.setAction("autoPairSquareBracket",function(){return this.autoPairBrackets("[","]")}.bind(this));a.setKeyBinding(new m.KeyBinding("]",!1,!1,!1,!1,"keypress"),"skipClosingSquareBracket");a.setAction("skipClosingSquareBracket",function(){return this.skipClosingBracket("]")}.bind(this));a.setKeyBinding(new m.KeyBinding("<",!1,!1,!1,!1,"keypress"),"autoPairAngleBracket");a.setAction("autoPairAngleBracket",function(){return this.autoPairBrackets("<",">")}.bind(this));
+a.setKeyBinding(new m.KeyBinding(">",!1,!1,!1,!1,"keypress"),"skipClosingAngleBracket");a.setAction("skipClosingAngleBracket",function(){return this.skipClosingBracket(">")}.bind(this));a.setKeyBinding(new m.KeyBinding("(",!1,!1,!1,!1,"keypress"),"autoPairParentheses");a.setAction("autoPairParentheses",function(){return this.autoPairBrackets("(",")")}.bind(this));a.setKeyBinding(new m.KeyBinding(")",!1,!1,!1,!1,"keypress"),"skipClosingParenthesis");a.setAction("skipClosingParenthesis",function(){return this.skipClosingBracket(")")}.bind(this));
+a.setKeyBinding(new m.KeyBinding("{",!1,!1,!1,!1,"keypress"),"autoPairBraces");a.setAction("autoPairBraces",function(){return this.autoPairBrackets("{","}")}.bind(this));a.setKeyBinding(new m.KeyBinding("}",!1,!1,!1,!1,"keypress"),"skipClosingBrace");a.setAction("skipClosingBrace",function(){return this.skipClosingBracket("}")}.bind(this));a.setKeyBinding(new m.KeyBinding("'",!1,!1,!1,!1,"keypress"),"autoPairSingleQuotation");a.setAction("autoPairSingleQuotation",function(){return this.autoPairQuotations("'")}.bind(this));
+a.setKeyBinding(new m.KeyBinding('"',!1,!1,!1,!1,"keypress"),"autoPairDblQuotation");a.setAction("autoPairDblQuotation",function(){return this.autoPairQuotations('"')}.bind(this));a.setAction("deletePrevious",function(){return this.deletePrevious()}.bind(this))},autoIndent:function(){var a=this.editor,b=a.getTextView();if(b.getOptions("readonly"))return!1;var c=a.getSelection();if(c.start===c.end){for(var d=a.getModel(),f=d.getLineAtOffset(c.start),g=d.getLine(f,!1),h=d.getLineStart(f),i=0,k=c.start-
+h,s;i<k&&((s=g.charCodeAt(i))===32||s===9);)i++;var h=g.substring(0,i),b=b.getOptions("tabSize","expandTab"),u=b.expandTab?Array(b.tabSize+1).join(" "):"\t",b=d.getLineDelimiter(),j=/^[\s]*\/\*[\*]*[\s]*$/,m=/^[\s]*\*/,n=/\*\/[\s]*$/,D=g.substring(0,k),y=g.substring(k),K;if(this.smartIndentation&&g.charCodeAt(K=D.trimRight().length-1)===123)return d=k-K-1,y=y.length-y.trimLeft().length,g=g.charCodeAt(k+y)===125?b+h+u+b+h:b+h+u,a.setText(g,c.start-d,c.end+y),a.setCaretOffset(c.start+b.length+h.length+
+u.length-d),!0;else if(this.autoCompleteComments&&!n.test(D)&&(j.test(D)||m.test(D))){if(i=j.exec(D)){g=b+h+" * ";g+=n.test(y)?y.substring(0,y.length-2).trim():y.trim();if(d.getLineCount()===f+1||!m.test(d.getLine(f+1)))g+=b+h+" */";a.setText(g,c.start,c.end+y.length);a.setCaretOffset(c.start+b.length+h.length+3);return!0}if(i=m.exec(D))for(f-=1;f>=0;f--)if(i=d.getLine(f,!1),j.test(i))return n.test(y)||g.charCodeAt(k)===47?(g=b+h+"*"+y,h=c.start+b.length+h.length+1):(g=b+h+"* "+y,h=c.start+b.length+
+h.length+2),a.setText(g,c.start,c.end+y.length),a.setCaretOffset(h),!0;else if(!m.test(i))break}else if(n.test(D)&&h.charCodeAt(h.length-1)===32)return g=b+h.substring(0,h.length-1),a.setText(g,c.start,c.end),a.setCaretOffset(c.start+g.length),!0;else if(i>0){for(i=k;i<g.length&&((s=g.charCodeAt(i++))===32||s===9);)c.end++;a.setText(d.getLineDelimiter()+h,c.start,c.end);return!0}}return!1},addBlockComment:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getModel(),
+c=a.getSelection(),d=this._findEnclosingComment(b,c.start,c.end);if(d.commentStart!==void 0&&d.commentEnd!==void 0)return!0;b=b.getText(c.start,c.end);if(b.length===0)return!0;var d=b.length,b=b.replace(/\/\*|\*\//g,""),f=b.length;a.setText("/*"+b+"*/",c.start,c.end);a.setSelection(c.start+2,c.end+2+(f-d));return!0},autoPairBrackets:function(a,b){if(a==="["&&!this.autoPairSquareBrackets)return!1;else if(a==="{"&&!this.autoPairBraces)return!1;else if(a==="("&&!this.autoPairParentheses)return!1;else if(a===
+"<"&&!this.autoPairAngleBrackets)return!1;var c=this.editor;if(c.getTextView().getOptions("readonly"))return!1;var d=c.getSelection(),f=c.getModel(),g=c.getCaretOffset()===f.getCharCount()?"":f.getText(d.start,d.start+1).trim(),h=/^$|[)}\]>]/;if(d.start===d.end&&h.test(g))return c.setText(a+b,d.start,d.start),c.setCaretOffset(d.start+1),!0;else if(d.start!==d.end)return f=f.getText(d.start,d.end),c.setText(a+f+b,d.start,d.end),c.setSelection(d.start+1,d.end+1),!0;return!1},autoPairQuotations:function(a){if(!this.autoPairQuotation)return!1;
+var b=this.editor;if(b.getTextView().getOptions("readonly"))return!1;var c=b.getSelection(),d=b.getModel(),f=b.getCaretOffset(),g=f===0?"":d.getText(c.start-1,c.start).trim(),h=f===d.getCharCount()?"":d.getText(c.start,c.start+1).trim(),f=/^"$|^'$/,i=/\w/,k=/^$|[)}\]>]/;if(c.start!==c.end){d=d.getText(c.start,c.end);if(f.test(d))return!1;b.setText(a+d+a,c.start,c.end);b.setSelection(c.start+1,c.end+1)}else if(h===a)b.setCaretOffset(c.start+1);else if(g===a||f.test(h)||i.test(g)||!k.test(h))return!1;
+else b.setText(a+a,c.start,c.start),b.setCaretOffset(c.start+1);return!0},contentAssistProposalApplied:function(a){a=a.data.proposal;if(a.positions&&a.positions.length>0&&this.linkedMode){for(var b=[],c=0;c<a.positions.length;++c)b[c]={positions:[{offset:a.positions[c].offset,length:a.positions[c].length}]};this.linkedMode.enterLinkedMode({groups:b,escapePosition:a.escapePosition})}else a.groups&&a.groups.length>0&&this.linkedMode?this.linkedMode.enterLinkedMode({groups:a.groups,escapePosition:a.escapePosition}):
+a.escapePosition&&this.editor.getTextView().setCaretOffset(a.escapePosition);return!0},deletePrevious:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getSelection();if(b.start!==b.end)return!1;var c=a.getModel(),d=a.getCaretOffset(),f=d===0?"":c.getText(b.start-1,b.start),c=d===c.getCharCount()?"":c.getText(b.start,b.start+1);(f==="("&&c===")"||f==="["&&c==="]"||f==="{"&&c==="}"||f==="<"&&c===">"||f==='"'&&c==='"'||f==="'"&&c==="'")&&a.setText("",b.start,b.start+
+1);return!1},_findEnclosingComment:function(a,b,c){var d=a.getLineAtOffset(b),f=a.getLineAtOffset(c),g,h,i,k,s,u;for(g=d;g>=0;g--)if(h=a.getLine(g),i=g===d?b-a.getLineStart(d):h.length,k=h.lastIndexOf("/*",i),h=h.lastIndexOf("*/",i),h>k)break;else if(k!==-1){s=a.getLineStart(g)+k;break}for(g=f;g<a.getLineCount();g++)if(h=a.getLine(g),i=g===f?c-a.getLineStart(f):0,k=h.indexOf("/*",i),h=h.indexOf("*/",i),k!==-1&&k<h)break;else if(h!==-1){u=a.getLineStart(g)+h;break}return{commentStart:s,commentEnd:u}},
+lineStart:function(){for(var a=this.editor,b=a.getModel(),c=a.getCaretOffset(),d=b.getLineAtOffset(c),f=b.getLineStart(d),b=b.getLine(d),d=0;d<b.length;d++){var g=b.charCodeAt(d);if(!(g===32||g===9))break}d+=f;return c!==d?(a.setSelection(d,d),!0):!1},removeBlockComment:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;var b=a.getModel(),c=a.getSelection(),d=b.getText(c.start,c.end),f,g,h;for(h=0;h<d.length;h++)if(d.substring(h,h+2)==="/*"){f=c.start+h;break}for(;h<d.length;h++)if(d.substring(h,
+h+2)==="*/"){g=c.start+h;break}if(f!==void 0&&g!==void 0)a.setText(b.getText(f+2,g),f,g+2),a.setSelection(f,g);else{d=this._findEnclosingComment(b,c.start,c.end);if(d.commentStart===void 0||d.commentEnd===void 0)return!0;b=b.getText(d.commentStart+2,d.commentEnd);a.setText(b,d.commentStart,d.commentEnd+2);a.setSelection(c.start-2,c.end-2)}return!0},toggleLineComment:function(){var a=this.editor;if(a.getTextView().getOptions("readonly"))return!1;for(var b=a.getModel(),c=a.getSelection(),d=b.getLineAtOffset(c.start),
+f=b.getLineAtOffset(c.end>c.start?c.end-1:c.end),g=!0,h=[],i,k,s=d;s<=f;s++)if(i=b.getLine(s,!0),h.push(i),!g||(k=i.indexOf("//"))===-1)g=!1;else if(k!==0){var u;for(u=0;u<k;u++)if(g=i.charCodeAt(u),!(g===32||g===9))break;g=u===k}s=b.getLineStart(d);u=b.getLineEnd(f,!0);if(g){for(g=0;g<h.length;g++)i=h[g],k=i.indexOf("//"),h[g]=i.substring(0,k)+i.substring(k+2);h=h.join("");i=b.getLineStart(f);b=s===c.start?c.start:c.start-2;c=c.end-2*(f-d+1)+(c.end===i+1?2:0)}else h.splice(0,0,""),h=h.join("//"),
+b=s===c.start?c.start:c.start+2,c=c.end+2*(f-d+1);a.setText(h,s,u);a.setSelection(b,c);return!0},trimTrailingWhitespaces:function(){var a=this.editor,b=a.getModel(),c=a.getSelection();a.getTextView().setRedraw(!1);a.getUndoStack().startCompoundChange();for(var d=/(\s+$)/,f=b.getLineCount(),g=0;g<f;g++){var h=b.getLine(g),i=d.exec(h);if(i){var k=b.getLineStart(g),h=i[0].length,i=k+i.index;b.setText("",i,i+h);if(c.start>i)c.start=Math.max(i,c.start-h);if(c.start!==c.end&&c.end>i)c.end=Math.max(i,c.end-
+h)}}a.getUndoStack().endCompoundChange();a.getTextView().setRedraw(!0);a.setSelection(c.start,c.end,!1)},startUndo:function(){this.undoStack&&this.undoStack.startCompoundChange()},skipClosingBracket:function(a){var b=this.editor;if(b.getTextView().getOptions("readonly"))return!1;var c=b.getSelection(),d=b.getModel();return(b.getCaretOffset()===d.getCharCount()?"":d.getText(c.start,c.start+1))===a?(b.setCaretOffset(c.start+1),!0):!1},endUndo:function(){this.undoStack&&this.undoStack.endCompoundChange()},
+setAutoPairParentheses:function(a){this.autoPairParentheses=a},setAutoPairBraces:function(a){this.autoPairBraces=a},setAutoPairSquareBrackets:function(a){this.autoPairSquareBrackets=a},setAutoPairAngleBrackets:function(a){this.autoPairAngleBrackets=a},setAutoPairQuotations:function(a){this.autoPairQuotation=a},setAutoCompleteComments:function(a){this.autoCompleteComments=a},setSmartIndentation:function(a){this.smartIndentation=a}};b.SourceCodeActions=g;if(!String.prototype.trimLeft)String.prototype.trimLeft=
+function(){return this.replace(/^\s+/g,"")};if(!String.prototype.trimRight)String.prototype.trimRight=function(){return this.replace(/\s+$/g,"")};return b});
+define("orion/editor/templates",[],function(){function k(k,i,c,d){this.prefix=k;this.description=i;this.template=c;this.name=d;this._parse()}function m(k,i){this._keywords=k||[];this._templates=[];this.addTemplates(i||[])}k.prototype={getProposal:function(k,i,c){var k=i-k.length,i={},d,f=c.delimiter!==void 0?c.delimiter:"\n";c.indentation&&(f+=c.indentation);for(var g=c.tab!==void 0?c.tab:"\t",h=0,b=this.variables,a=this.segments,c=[],e=0;e<a.length;e++){var l=a[e],o=b[l];if(o!==void 0)switch(l){case "${tab}":l=
+g;break;case "${delimiter}":l=f;break;case "${cursor}":l="";d=h;break;default:var q=i[l];q||(q=i[l]={data:o.data,positions:[]});l=o.substitution;q.data&&q.data.values&&(l=q.data.values[0]);q.positions.push({offset:k+h,length:l.length})}c.push(l);h+=l.length}var f=[],r;for(r in i)i.hasOwnProperty(r)&&f.push(i[r]);c=c.join("");if(d===void 0)d=c.length;return{proposal:c,name:this.name,description:this.description,groups:f,escapePosition:k+d,style:"noemphasis"}},match:function(k){return this.prefix.indexOf(k)===
+0},_parse:function(){var k=this.template,i=[],c={},d,f=0,k=k.replace(/\n/g,"${delimiter}"),k=k.replace(/\t/g,"${tab}");k.replace(/\$\{((?:[^\\}]+|\\.))*\}/g,function(g,h,b){var a=g.substring(2,g.length-1),h=g,e=a,l=null,o=e.indexOf(":");o!==-1&&(e=e.substring(0,o),h="${"+e+"}",l=JSON.parse(a.substring(o+1).replace("\\}","}").trim()));(a=c[h])||(a=c[h]={});a.substitution=e;if(l)a.data=l;(d=k.substring(f,b))&&i.push(d);i.push(h);f=b+g.length;return e});(d=k.substring(f,k.length))&&i.push(d);this.segments=
+i;this.variables=c}};m.prototype={addTemplates:function(m){for(var i=this.getTemplates(),c=0;c<m.length;c++)i.push(new k(m[c].prefix,m[c].description,m[c].template,m[c].name))},computeProposals:function(k,i,c){var d=this.getPrefix(k,i,c),f=[];this.isValid(d,k,i,c)&&(f=f.concat(this.getTemplateProposals(d,i,c)),f=f.concat(this.getKeywordProposals(d)));return f},getKeywords:function(){return this._keywords},getKeywordProposals:function(k){var i=[],c=this.getKeywords();if(c){for(var d=0;d<c.length;d++)c[d].indexOf(k)===
+0&&i.push({proposal:c[d].substring(k.length),description:c[d],style:"noemphasis_keyword"});0<i.length&&i.splice(0,0,{proposal:"",description:"Keywords",style:"noemphasis_title_keywords",unselectable:!0})}return i},getPrefix:function(k,i,c){return c.prefix},getTemplates:function(){return this._templates},getTemplateProposals:function(k,i,c){for(var d=[],f=this.getTemplates(),g=0;g<f.length;g++){var h=f[g];h.match(k)&&(h=h.getProposal(k,i,c),this.removePrefix(k,h),d.push(h))}0<d.length&&(d.sort(function(b,
+a){return b.name<a.name?-1:b.name>a.name?1:0}),d.splice(0,0,{proposal:"",description:"Templates",style:"noemphasis_title",unselectable:!0}));return d},removePrefix:function(k,i){if(!(i.overwrite=i.proposal.substring(0,k.length)!==k))i.proposal=i.proposal.substring(k.length)},isValid:function(){return!0}};return{Template:k,TemplateContentAssist:m}});
+define("orion/editor/linkedMode","i18n!orion/editor/nls/messages,orion/keyBinding,orion/editor/keyModes,orion/editor/annotations,orion/editor/templates,orion/objects,orion/util".split(","),function(k,m,n,i,c,d){function f(c,b,a){var e=c.getTextView();n.KeyMode.call(this,e);this.editor=c;this.undoStack=b;this.contentAssist=a;this.linkedModeModel=null;e.setAction("linkedModeEnter",function(){this.exitLinkedMode(!0);return!0}.bind(this));e.setAction("linkedModeCancel",function(){this.exitLinkedMode(!1);
+return!0}.bind(this));e.setAction("linkedModeNextGroup",function(){var a=this.linkedModeModel;this.selectLinkedGroup((a.selectedGroupIndex+1)%a.groups.length);return!0}.bind(this));e.setAction("linkedModePreviousGroup",function(){var a=this.linkedModeModel;this.selectLinkedGroup(a.selectedGroupIndex>0?a.selectedGroupIndex-1:a.groups.length-1);return!0}.bind(this));this.linkedModeListener={onActivating:function(){this._groupContentAssistProvider&&(this.contentAssist.setProviders([this._groupContentAssistProvider]),
+this.contentAssist.setProgress(null))}.bind(this),onModelChanged:function(a){if(!this.ignoreVerify){for(var b=this.editor.mapOffset(a.start),c=this.linkedModeModel,e,d;c;)if(e=this._getPositionChanged(c,b,b+a.removedCharCount),d=e.position,d===void 0||d.model!==c)this.exitLinkedMode(!1),c=this.linkedModeModel;else break;if(c){c=0;a=a.addedCharCount-a.removedCharCount;e=e.positions;for(var f,g=0;g<e.length;++g){f=e[g];d=f.position;var h=d.offset<=b&&b<=d.offset+d.length;h&&!f.ansestor?(d.offset+=c,
+d.length+=a,c+=a):(d.offset+=c,f.ansestor&&h&&(d.length+=a));if(f.escape)f.model.escapePosition=d.offset}this._updateAnnotations(e)}}}.bind(this),onVerify:function(a){if(!this.ignoreVerify){for(var b=this.editor,c=b.mapOffset(a.start),e=this.editor.mapOffset(a.end),d=this.linkedModeModel,f,g;d;)if(f=this._getPositionChanged(d,c,e),g=f.position,g===void 0||g.model!==d)this.exitLinkedMode(!1),d=this.linkedModeModel;else break;if(d){var h=this._compoundChange;h?h.owner.model===d&&h.owner.group===g.group||
+(this.endUndo(),this.startUndo()):this.startUndo();d.selectedGroupIndex=g.group;var h=0,i=a.text.length-(e-c);f=f.positions;var j;c-=g.position.offset;for(var k=e-g.position.offset,m=0;m<f.length;++m)if(j=f[m],e=j.position,j.oldOffset=e.offset,j.model===d&&j.group===g.group?(e.offset+=h,e.length+=i,h+=i):(e.offset+=h,j.ansestor&&(e.length+=g.count*i)),j.escape)j.model.escapePosition=e.offset;this.ignoreVerify=!0;for(m=f.length-1;m>=0;m--)j=f[m],j.model===d&&j.group===g.group&&b.setText(a.text,j.oldOffset+
+c,j.oldOffset+k);this.ignoreVerify=!1;a.text=null;this._updateAnnotations(f)}}}.bind(this)}}var g={};f.prototype=new n.KeyMode;d.mixin(f.prototype,{createKeyBindings:function(){var c=m.KeyBinding,b=[];b.push({actionID:"linkedModeEnter",keyBinding:new c(13)});b.push({actionID:"linkedModeCancel",keyBinding:new c(27)});b.push({actionID:"linkedModeNextGroup",keyBinding:new c(9)});b.push({actionID:"linkedModePreviousGroup",keyBinding:new c(9,!1,!0)});return b},enterLinkedMode:function(c){if(!this.linkedModeModel){var b=
+this.editor.getTextView();b.addKeyMode(this);b.addEventListener("Verify",this.linkedModeListener.onVerify);b.addEventListener("ModelChanged",this.linkedModeListener.onModelChanged);this.contentAssist.addEventListener("Activating",this.linkedModeListener.onActivating);this.editor.reportStatus(k.linkedModeEntered,null,!0)}this._sortedPositions=null;if(this.linkedModeModel)c.previousModel=this.linkedModeModel,c.parentGroup=this.linkedModeModel.selectedGroupIndex,this.linkedModeModel.nextModel=c;this.linkedModeModel=
+c;this.selectLinkedGroup(0)},exitLinkedMode:function(c){if(this.isActive()){if(this._compoundChange)this.endUndo(),this._compoundChange=null;this._sortedPositions=null;var b=this.linkedModeModel;this.linkedModeModel=b.previousModel;b.parentGroup=b.previousModel=void 0;if(this.linkedModeModel)this.linkedModeModel.nextModel=void 0;if(!this.linkedModeModel){var a=this.editor,e=a.getTextView();e.removeKeyMode(this);e.removeEventListener("Verify",this.linkedModeListener.onVerify);e.removeEventListener("ModelChanged",
+this.linkedModeListener.onModelChanged);e=this.contentAssist;e.removeEventListener("Activating",this.linkedModeListener.onActivating);e.offset=void 0;this.editor.reportStatus(k.linkedModeExited,null,!0);c&&a.setCaretOffset(b.escapePosition,!1)}this.selectLinkedGroup(0)}},startUndo:function(){if(this.undoStack){var c=this,b=this.linkedModeModel;this._compoundChange=this.undoStack.startCompoundChange({model:b,group:b.selectedGroupIndex,end:function(){c._compoundChange=null}})}},endUndo:function(){this.undoStack&&
+this.undoStack.endCompoundChange()},isActive:function(){return!!this.linkedModeModel},isStatusActive:function(){return!!this.linkedModeModel},selectLinkedGroup:function(d){var b=this.linkedModeModel;if(b){b.selectedGroupIndex=d;var d=b.groups[d],a=d.positions[0],e=this.editor;e.setSelection(a.offset,a.offset+a.length);if(b=this.contentAssist)if(b.offset=void 0,d.data&&d.data.type==="link"&&d.data.values)(this._groupContentAssistProvider=new c.TemplateContentAssist(d.data.values)).getPrefix=function(){var b=
+e.getSelection();return b.start===b.end&&(b=e.getCaretOffset(),a.offset<=b&&b<=a.offset+a.length)?e.getText(a.offset,b):""},b.offset=a.offset,b.deactivate(),b.activate();else if(this._groupContentAssistProvider)this._groupContentAssistProvider=null,b.deactivate()}this._updateAnnotations()},_getModelPositions:function(c,b,a){for(var e=b.groups,d=0;d<e.length;d++)for(var f=e[d].positions,g=0;g<f.length;g++){var i=f[g];a&&(i={offset:i.offset+a,length:i.length});i={index:g,group:d,count:f.length,model:b,
+position:i};c.push(i);if(b.nextModel&&b.nextModel.parentGroup===d)i.ansestor=!0,this._getModelPositions(c,b.nextModel,(a||0)+f[g].offset-f[0].offset)}},_getSortedPositions:function(c){var b=this._sortedPositions;if(!b){for(b=[];c.previousModel;)c=c.previousModel;for(this._getModelPositions(b,c);c;)c.escapePosition!==void 0&&b.push({escape:!0,model:c,position:{offset:c.escapePosition,length:0}}),c=c.nextModel;b.sort(function(a,b){return a.position.offset-b.position.offset});this._sortedPositions=b}return b},
+_getPositionChanged:function(c,b,a){for(var e,c=this._getSortedPositions(c),d=c.length-1;d>=0;d--){var f=c[d].position;if(f.offset<=b&&a<=f.offset+f.length){e=c[d];break}}return{position:e,positions:c}},_updateAnnotations:function(c){var b=this.editor.getAnnotationModel();if(b){var a=[],e=[];b.getTextModel();for(var d=b.getAnnotations(),f;d.hasNext();)switch(f=d.next(),f.type){case i.AnnotationType.ANNOTATION_LINKED_GROUP:case i.AnnotationType.ANNOTATION_CURRENT_LINKED_GROUP:case i.AnnotationType.ANNOTATION_SELECTED_LINKED_GROUP:a.push(f)}if(d=
+this.linkedModeModel)for(var c=c||this._getSortedPositions(d),g=0;g<c.length;g++)if(f=c[g],f.model===d){var k=i.AnnotationType.ANNOTATION_LINKED_GROUP;f.group===d.selectedGroupIndex&&(k=f.index===0?i.AnnotationType.ANNOTATION_SELECTED_LINKED_GROUP:i.AnnotationType.ANNOTATION_CURRENT_LINKED_GROUP);f=f.position;f=i.AnnotationType.createAnnotation(k,f.offset,f.offset+f.length,"");e.push(f)}b.replaceAnnotations(a,e)}}});g.LinkedMode=f;return g});
+define("orion/editor/factories","orion/editor/actions,orion/editor/undoStack,orion/editor/rulers,orion/editor/annotations,orion/editor/textDND,orion/editor/linkedMode".split(","),function(k,m,n,i,c,d){function f(){}function g(){}function h(){}function b(){}function a(){}function e(){}var l={};f.prototype={createKeyBindings:function(a,b,c,e){var e=new k.TextActions(a,b,e),f=new d.LinkedMode(a,b,c),a=new k.SourceCodeActions(a,b,c,f);return{textActions:e,linkedMode:f,sourceCodeActions:a}}};l.KeyBindingsFactory=
+f;g.prototype={createUndoStack:function(a){a=a.getTextView();return new m.UndoStack(a,200)}};l.UndoFactory=g;h.prototype={createLineNumberRuler:function(a){return new n.LineNumberRuler(a,"left",{styleClass:"ruler lines"},{styleClass:"rulerLines odd"},{styleClass:"rulerLines even"})}};l.LineNumberRulerFactory=h;b.prototype={createFoldingRuler:function(a){return new n.FoldingRuler(a,"left",{styleClass:"ruler folding"})}};l.FoldingRulerFactory=b;a.prototype={createAnnotationModel:function(a){return new i.AnnotationModel(a)},
+createAnnotationStyler:function(a,b){return new i.AnnotationStyler(a,b)},createAnnotationRulers:function(a){var b=new n.AnnotationRuler(a,"left",{styleClass:"ruler annotations"}),a=new n.OverviewRuler(a,"right",{styleClass:"ruler overview"});return{annotationRuler:b,overviewRuler:a}}};l.AnnotationFactory=a;e.prototype={createTextDND:function(a,b){return new c.TextDND(a.getTextView(),b)}};l.TextDNDFactory=e;return l});
+define("orion/editor/editorFeatures",["orion/editor/factories","orion/editor/actions","orion/editor/linkedMode","orion/objects"],function(k,m,n,i){return i.mixin({},k,m,n)});
+(function(k,m){typeof define==="function"&&define.amd?define("orion/Deferred",m):typeof exports==="object"?module.exports=m():(k.orion=k.orion||{},k.orion.Deferred=m())})(this,function(){function k(){for(var f;f=c.shift();)f();d=!1}function m(f){c.push(f);d||(d=!0,setTimeout(k,0))}function n(c){return function(){c.apply(void 0,arguments)}}function i(){function d(){for(var b;b=l.shift();){var f=b.deferred,g=e==="fulfilled"?"resolve":"reject";if(typeof b[g]==="function")try{var h=(0,b[g])(a),i=h&&(typeof h===
+"object"||typeof h==="function")&&h.then;if(typeof i==="function")if(h===f.promise)f.reject(new TypeError);else{var k=h.cancel;typeof k==="function"?f._protected(c).parentCancel=k.bind(h):delete f._protected(c).parentCancel;i.call(h,n(f.resolve),n(f.reject),n(f.progress))}else f.resolve(h)}catch(j){f.reject(j)}else f[g](a)}}function g(b){delete q.parentCancel;e="rejected";a=b;l.length&&m(d)}function h(b){function c(a){return function(b){t||(t=!0,a(b))}}var t=!1;delete q.parentCancel;try{var v=b&&
+(typeof b==="object"||typeof b==="function")&&b.then;if(typeof v==="function")if(b===k)g(new TypeError);else{e="assumed";var s=b&&b.cancel;if(typeof s!=="function"){var u=new i,b=u.promise;try{v(u.resolve,u.reject,u.progress)}catch(j){u.reject(j)}s=b.cancel;v=b.then}a=b;v.call(b,c(h),c(g));q.parentCancel=s.bind(b)}else e="fulfilled",a=b,l.length&&m(d)}catch(w){c(g)(w)}}function b(){var a=q.parentCancel;if(a)delete q.parentCancel,a();else if(!e)a=Error("Cancel"),a.name="Cancel",g(a)}var a,e,l=[],k=
+this,q={};Object.defineProperty(this,"_protected",{value:function(a){if(a!==c)throw Error("protected");return q}});this.resolve=function(a){e||h(a);return k};this.reject=function(a){e||g(a);return k};this.progress=function(a){e||l.forEach(function(b){if(b.progress)try{b.progress(a)}catch(c){}});return k.promise};this.cancel=function(){q.parentCancel?setTimeout(b,0):b();return k};this.then=function(a,b,g){a={resolve:a,reject:b,progress:g,deferred:new i};l.push(a);a.deferred._protected(c).parentCancel=
+k.promise.cancel.bind(k);(e==="fulfilled"||e==="rejected")&&m(d);return a.deferred.promise};this.promise={then:k.then,cancel:k.cancel}}var c=[],d=!1;i.all=function(c,d){function h(b,c){l||(e[b]=c,--a===0&&k.resolve(e))}function b(a,b){if(!l){if(d)try{h(a,d(b));return}catch(c){b=c}k.reject(b)}}var a=c.length,e=[],l=!1,k=new i;k.then(void 0,function(){l=!0;c.forEach(function(a){a.cancel&&a.cancel()})});a===0?k.resolve(e):c.forEach(function(a,c){a.then(h.bind(void 0,c),b.bind(void 0,c))});return k.promise};
+i.when=function(c,d,h,b){var a;if(!(c&&typeof c.then==="function"))a=new i,a.resolve(c),c=a.promise;return c.then(d,h,b)};return i});
+define("orion/webui/littlelib",["orion/util"],function(k){function m(c,d){d||(d=document);return d.querySelectorAll(c)}function n(c){if(c.tabIndex>=0)return c;if(c.hasChildNodes())for(var d=0;d<c.childNodes.length;d++){var b=n(c.childNodes[d]);if(b)return b}return null}function i(c){if(c.tabIndex>=0)return c;if(c.hasChildNodes())for(var d=c.childNodes.length-1;d>=0;d--){var b=i(c.childNodes[d]);if(b)return b}return null}function c(f,h){if(f.nodeType===3){var b=d.exec(f.nodeValue);b&&b.length>1&&h(f,
+b)}if(f.hasChildNodes())for(b=0;b<f.childNodes.length;b++)c(f.childNodes[b],h)}var d=/\$\{([^\}]+)\}/,f=null;return{$:function(c,d){d||(d=document);return d.querySelector(c)},$$:m,$$array:function(c,d){return Array.prototype.slice.call(m(c,d))},node:function(c){var d=c;typeof c==="string"&&(d=document.getElementById(c));return d},contains:function(c,d){if(!c||!d)return!1;if(c===d)return!0;var b=c.compareDocumentPosition(d);return Boolean(b&16)},bounds:function(c){c=c.getBoundingClientRect();return{left:c.left+
+document.documentElement.scrollLeft,top:c.top+document.documentElement.scrollTop,width:c.width,height:c.height}},empty:function(c){for(;c.hasChildNodes();)c.removeChild(c.firstChild)},firstTabbable:n,lastTabbable:i,stop:function(c){if(window.document.all)c.keyCode=0;c.preventDefault&&(c.preventDefault(),c.stopPropagation())},processTextNodes:function(d,f){c(d,function(b,a){b.parentNode.replaceChild(document.createTextNode(f[a[1]]||a[1]),b)})},processDOMNodes:function(d,f){c(d,function(b,a){var c=
+f[a[1]];if(c){var d=document.createRange(),g=a.index;d.setStart(b,g);d.setEnd(b,g+a[0].length);d.deleteContents();d.insertNode(c)}})},addAutoDismiss:function(c,d){function b(a){f.forEach(function(b){var c=!1,d=b.excludeNodes.some(function(b){return document.body.contains(b)?(c=!0,b.contains(a.target)):!1});if(c&&!d)try{b.dismiss(a)}catch(f){typeof console!=="undefined"&&console&&console.error(f&&f.message)}});f=f.filter(function(a){return a.excludeNodes.some(function(a){return document.body.contains(a)})})}
+f===null&&(f=[],document.addEventListener("click",b,!0),k.isIOS&&document.addEventListener("touchend",function(a){function b(){a.target.removeEventListener("click",b)}a.touches.length===0&&a.target.addEventListener("click",b)},!1));f.push({excludeNodes:c,dismiss:d})},setFramesEnabled:function(c){for(var d=document.getElementsByTagName("iframe"),b=0;b<d.length;b++)d[b].parentNode.style.pointerEvents=c?"":"none"},removeAutoDismiss:function(c){f=f.filter(function(d){return c!==d.dismiss})},KEY:{BKSPC:8,
+TAB:9,ENTER:13,ESCAPE:27,SPACE:32,PAGEUP:33,PAGEDOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,INSERT:45,DEL:46}}});
+define("orion/editor/contentAssist","i18n!orion/editor/nls/messages,orion/keyBinding,orion/editor/keyModes,orion/editor/eventTarget,orion/Deferred,orion/objects,orion/editor/util,orion/util,orion/webui/littlelib".split(","),function(k,m,n,i,c,d,f,g,h){var b,a,e;function l(c){this.textView=c;this.state=b;this.resetProviderInfoArray();var d=this;this.contentAssistListener={onModelChanging:function(a){this._latestModelChangingEvent=a}.bind(this),onSelection:function(c){this.isDeactivatingChange(this._latestModelChangingEvent,
+c)?this.setState(b):this.isActive()&&(this.state===a&&this.setState(e),this.filterProposals(c));this._latestModelChangingEvent=null}.bind(this),onScroll:function(){this.setState(b)}.bind(this)};c.setKeyBinding(g.isMac?new m.KeyBinding(" ",!1,!1,!1,!0):new m.KeyBinding(" ",!0),"contentAssist");c.setKeyBinding(g.isMac?new m.KeyBinding(" ",!1,!1,!0,!0):new m.KeyBinding(" ",!0,!1,!0),"contentAssist");c.setAction("contentAssist",function(){c.getOptions("readonly")||d.activate();return!0},{name:k.contentAssist})}
+function o(a,b){var c=a.textView;n.KeyMode.call(this,c);this.contentAssist=a;this.widget=b;this.proposals=[];var d=this;this.contentAssist.addEventListener("ProposalsComputed",function(a){d.proposals=a.data.proposals;if(d.proposals.length===0)d.selectedIndex=-1,d.cancel();else{for(d.selectedIndex=0;d.proposals[d.selectedIndex]&&d.proposals[d.selectedIndex].unselectable;)d.selectedIndex++;if(d.proposals[d.selectedIndex]){if(d.widget){var b=!0;if(a.autoApply){for(a=d.selectedIndex+1;d.proposals[a]&&
+d.proposals[a].unselectable;)a++;d.proposals[a]||(b=!1,d.contentAssist.apply(d.proposals[d.selectedIndex]))}b&&(d.widget.show(),d.widget.selectNode(d.selectedIndex))}}else d.selectedIndex=-1,d.cancel()}});c.setAction("contentAssistApply",function(){return this.enter()}.bind(this));c.setAction("contentAssistCancel",function(){return this.cancel()}.bind(this));c.setAction("contentAssistNextProposal",function(){return this.lineDown()}.bind(this));c.setAction("contentAssistPreviousProposal",function(){return this.lineUp()}.bind(this));
+c.setAction("contentAssistNextPage",function(){return this.pageDown()}.bind(this));c.setAction("contentAssistPreviousPage",function(){return this.pageUp()}.bind(this));c.setAction("contentAssistHome",function(){this.widget&&this.widget.scrollIndex(0,!0);return this.lineDown(0)}.bind(this));c.setAction("contentAssistEnd",function(){return this.lineUp(this.proposals.length-1)}.bind(this));c.setAction("contentAssistTab",function(){return this.tab()}.bind(this));this.widget&&(this.widget.setContentAssistMode(this),
+this.widget.createAccessible())}function q(a,b){this.contentAssist=a;this.textView=this.contentAssist.getTextView();this.isShowing=this.textViewListenerAdded=!1;var c=this.textView.getOptions("parent").ownerDocument;this.parentNode=typeof b==="string"?c.getElementById(b):b;if(!this.parentNode){this.parentNode=g.createElement(c,"div");this.parentNode.className="contentassist";var d=c.getElementsByTagName("body")[0];if(d)d.appendChild(this.parentNode);else throw Error("parentNode is required");}this.parentNode.addEventListener("scroll",
+this.onScroll.bind(this));var e=this;this.textViewListener={onMouseDown:function(a){(a.event.target||a.event.srcElement).parentElement!==e.parentNode&&e.contentAssist.deactivate()}};this.contentAssist.addEventListener("Deactivating",function(){e.hide()});this.scrollListener=function(){e.isShowing&&e.position()};f.addEventListener(c,"scroll",this.scrollListener)}b=1;a=2;e=3;var r={selected:"selected",hr:"proposal-hr",emphasis:"proposal-emphasis",noemphasis:"proposal-noemphasis",noemphasis_keyword:"proposal-noemphasis-keyword",
+noemphasis_title:"proposal-noemphasis-title",noemphasis_title_keywords:"proposal-noemphasis-title-keywords",dfault:"proposal-default"};l.prototype={apply:function(a){if(!a)return!1;var c=this.textView,d=c.getSelection(),e=this._initialCaretOffset,f=e,j=d=Math.max(d.start,d.end),g=c.getModel();g.getBaseModel&&(f=g.mapOffset(f),j=g.mapOffset(j),g=g.getBaseModel());a.overwrite&&(e=this.getPrefixStart(g,f));f={proposal:a,start:f,end:j};this.setState(b);c.setText(typeof a==="string"?a:a.proposal,e,d);
+this.dispatchEvent({type:"ProposalApplied",data:f});return!0},activate:function(c,d){if(this.state===b)this._autoTriggered=d?!0:!1,this.setState(a,c)},deactivate:function(){this.setState(b)},getTextView:function(){return this.textView},isActive:function(){return this.state===a||this.state===e},isDeactivatingChange:function(a,b){var c=!1;b.newValue.start<this._initialCaretOffset?c=!0:a&&(c=a.removedLineCount>0||a.addedLineCount>0);return c},setState:function(c,d){var e;if(c===a)this._filterText="",
+e="Activating",this._mode&&this._mode.setActive(!0);else if(c===b)e="Deactivating",this._mode&&this._mode.setActive(!1),this._initialCaretOffset=-1,this._filterText="";e&&this.dispatchEvent({type:e,providerInfoArray:d});this.state=c;this.onStateChange(c)},setMode:function(a){this._mode=a},onStateChange:function(c){if(c===b){if(this.listenerAdded)this._latestModelChangingEvent=null,this.textView.removeEventListener("ModelChanging",this.contentAssistListener.onModelChanging),this.textView.removeEventListener("Scroll",
+this.contentAssistListener.onScroll),this.textView.removeEventListener("Selection",this.contentAssistListener.onSelection),this.listenerAdded=!1}else if(c===a){if(!this.listenerAdded)this.textView.addEventListener("ModelChanging",this.contentAssistListener.onModelChanging),this.textView.addEventListener("Scroll",this.contentAssistListener.onScroll),this.textView.addEventListener("Selection",this.contentAssistListener.onSelection),this.listenerAdded=!0;this.computeProposals()}},computeProposals:function(){var a=
+this,b=this.textView.getCaretOffset(),c=this.textView.getSelection(),c=Math.min(c.start,c.end);this._initialCaretOffset=Math.min(b,c);this._computeProposals(this._initialCaretOffset).then(function(b){a._computedProposals=b;a.isActive()&&(b=a._flatten(b),a.dispatchEvent({type:"ProposalsComputed",data:{proposals:b},autoApply:!a._autoTriggered}))})},getPrefixStart:function(a,b){for(var c=b;c>0&&/[A-Za-z0-9_]/.test(a.getText(c-1,c));)c--;return c},handleError:function(a){typeof console!=="undefined"&&
+(console.log("Error retrieving content assist proposals"),console.log(a&&a.stack))},_computeProposals:function(a){var b=this._providerInfoArray,e=this.textView,f=e.getSelection(),g=e.getModel(),j=a;if(g.getBaseModel)j=g.mapOffset(j),f.start=g.mapOffset(f.start),f.end=g.mapOffset(f.end),g=g.getBaseModel();for(var a=g.getLine(g.getLineAtOffset(j)),h=0;h<a.length&&/\s/.test(a.charAt(h));)h++;var h=a.substring(0,h),e=e.getOptions("tabSize","expandTab"),e=e.expandTab?Array(e.tabSize+1).join(" "):"\t",
+i={line:a,offset:j,prefix:g.getText(this.getPrefixStart(g,j),j),selection:f,delimiter:g.getLineDelimiter(),tab:e,indentation:h},l=this,b=b.map(function(a){var a=a.provider,b;try{var e,f;if(e=a.computeContentAssist){var h=l.editorContextProvider,k=h.getEditorContext();i=d.mixin(i,h.getOptions());f=e.apply(a,[k,i])}else if(e=a.getProposals||a.computeProposals)f=e.apply(a,[g.getText(),j,i]);b=l.progress?l.progress.progress(f,"Generating content assist proposal"):f}catch(s){l.handleError(s)}return c.when(b)});
+return c.all(b,this.handleError)},filterProposals:function(){var a="",b=0;if(this._latestModelChangingEvent){a=this._latestModelChangingEvent.text;if(b=this._latestModelChangingEvent.removedCharCount)this._filterText=this._filterText.substring(0,this._filterText.length-b);if(a)this._filterText=this._filterText.concat(a);a=this.textView.getModel();a.getBaseModel&&(a=a.getBaseModel());var c=this.textView.getText(this.getPrefixStart(a,this._initialCaretOffset),this._initialCaretOffset),d=[];this._computedProposals.forEach(function(a){a=
+a.filter(function(a){if(r[a.style]===r.hr||r[a.style]===r.noemphasis_title)return!0;var b="";if(a.overwrite){if(a.name)b=a.name;else if(a.proposal)b=a.proposal;else return!1;return 0===b.indexOf(c+this._filterText)}else return a.name||a.proposal?(b=!1,a.name&&(b=0===a.name.indexOf(c+this._filterText)),!b&&a.proposal&&(b=0===a.proposal.indexOf(this._filterText)),b):typeof a==="string"?0===a.indexOf(this._filterText):!1},this);a.length>0&&d.push(a)},this);d=this._removeExtraUnselectableElements(d);
+this.dispatchEvent({type:"ProposalsComputed",data:{proposals:this._flatten(d)},autoApply:!1})}},_removeExtraUnselectableElements:function(a){return a.map(function(a){return a.filter(function(b,c){var d=!0;if(r[b.style]===r.hr)0===c||a.length-1===c?d=!1:r.hr===r[a[c-1].style]&&(d=!1);else if(r[b.style]===r.noemphasis_title){var e=a[c+1];e?r[e.style]===r.noemphasis_title&&(d=!1):d=!1}return d})})},setEditorContextProvider:function(a){this.editorContextProvider=a},_generateProviderId:function(){this._uniqueProviderIdCounter?
+this._uniqueProviderIdCounter++:this._uniqueProviderIdCounter=0;return"ContentAssistGeneratedID_"+this._uniqueProviderIdCounter},setAutoTriggerEnabled:function(a){this._autoTriggerEnabled=a;this._updateAutoTriggerListenerState()},setProviders:function(a){this.setProviderInfoArray(a.map(function(a){return{provider:a,id:this._generateProviderId()}},this))},setProviderInfoArray:function(a){this.resetProviderInfoArray();this._providerInfoArray=a;this._charTriggersInstalled=a.some(function(a){return a.charTriggers});
+this._updateAutoTriggerListenerState()},resetProviderInfoArray:function(){this._providerInfoArray=[];this._charTriggersInstalled=!1;this._updateAutoTriggerListenerState()},setProgress:function(a){this.progress=a},setStyleAccessor:function(a){this._styleAccessor=a},_flatten:function(a){return a.reduce(function(a,b){var c=a;if(Array.isArray(b)&&b.length>0){var c=b,d=a;b[0].style&&0===r[b[0].style].indexOf(r.noemphasis)&&(c=a,d=b);c.length>0&&c[c.length-1].style&&r.hr!==r[c[c.length-1].style]&&(c=c.concat({proposal:"",
+name:"",description:"---------------------------------",style:"hr",unselectable:!0}));c=c.concat(d)}return c},[])},_triggerListener:function(){if(this._styleAccessor){var a=this.textView.getCaretOffset(),b=null,c=[];if(this._charTriggersInstalled){var d=this.textView.getText(a-1,a);this._providerInfoArray.forEach(function(e){var f=e.charTriggers;if(f&&f.test(d)){var f=!1,g=e.excludedStyles;g&&(b||(b=this._styleAccessor.getStyles(a-1)),f=b.some(function(a){return g.test(a.style)}));f||c.push(e)}},
+this);c.length>0&&this.activate(c,!0)}}},_updateAutoTriggerListenerState:function(){if(!this._boundTriggerListener)this._boundTriggerListener=this._triggerListener.bind(this);if(this._triggerListenerInstalled){if(!this._autoTriggerEnabled||!this._charTriggersInstalled)this.textView.removeEventListener("Modify",this._boundTriggerListener),this._triggerListenerInstalled=!1}else if(this._autoTriggerEnabled&&this._charTriggersInstalled)this.textView.addEventListener("Modify",this._boundTriggerListener),
+this._triggerListenerInstalled=!0}};i.EventTarget.addMixin(l.prototype);o.prototype=new n.KeyMode;d.mixin(o.prototype,{createKeyBindings:function(){var a=m.KeyBinding,b=[];b.push({actionID:"contentAssistApply",keyBinding:new a(13)});b.push({actionID:"contentAssistCancel",keyBinding:new a(27)});b.push({actionID:"contentAssistNextProposal",keyBinding:new a(40)});b.push({actionID:"contentAssistPreviousProposal",keyBinding:new a(38)});b.push({actionID:"contentAssistNextPage",keyBinding:new a(34)});b.push({actionID:"contentAssistPreviousPage",
+keyBinding:new a(33)});b.push({actionID:"contentAssistHome",keyBinding:new a(h.KEY.HOME)});b.push({actionID:"contentAssistEnd",keyBinding:new a(h.KEY.END)});b.push({actionID:"contentAssistTab",keyBinding:new a(9)});return b},cancel:function(){this.getContentAssist().deactivate()},getContentAssist:function(){return this.contentAssist},getProposals:function(){return this.proposals},isActive:function(){return this.getContentAssist().isActive()},setActive:function(a){a?this.contentAssist.textView.addKeyMode(this):
+this.contentAssist.textView.removeKeyMode(this)},lineUp:function(a,b){return this.selectNew(a,b,!1)},lineDown:function(a,b){return this.selectNew(a,b,!0)},selectNew:function(a,b,c){if(c){if(void 0===a&&(a=this.selectedIndex+1),a>=this.proposals.length)if(b)return!0;else a=0}else if(void 0===a&&(a=this.selectedIndex-1),0>a)if(b)return!0;else a=this.proposals.length-1;for(var d=a;this.proposals[a]&&this.proposals[a].unselectable;){if(c){if(a++,a>=this.proposals.length)if(b)return!0;else a=0}else if(a--,
+0>a)if(b)return!0;else a=this.proposals.length-1;if(a===d){a=-1;break}}this.selectedIndex=a;this.widget&&this.widget.selectNode(a);return!0},pageUp:function(){if(this.widget){var a=this.widget.getTopIndex();a===this.selectedIndex&&(this.widget.scrollIndex(a,!1),a=this.widget.getTopIndex());return 0===a?this.lineDown(a,!0):this.lineUp(a,!0)}else return this.lineUp()},pageDown:function(){if(this.widget){var a=this.widget.getBottomIndex();a===this.selectedIndex&&(this.widget.scrollIndex(a,!0),a=this.widget.getBottomIndex());
+return this.lineDown(a,!0)}else return this.lineDown()},enter:function(){return this.contentAssist.apply(this.proposals[this.selectedIndex]||null)},tab:function(){return this.widget?(this.widget.parentNode.focus(),!0):!1}});q.prototype={onClick:function(a){if(!a)a=window.event;this.contentAssist.apply(this.getProposal(a.target||a.srcElement));this.textView.focus()},onScroll:function(){this.previousCloneNode&&!this.preserveCloneThroughScroll&&(this._removeCloneNode(),this.previousSelectedNode.classList.add(r.selected));
+this.preserveCloneThroughScroll=!1},createDiv:function(a,b,c){var d=b.ownerDocument,e=g.createElement(d,"div");e.id="contentoption"+c;e.setAttribute("role","option");e.className=r[a.style]?r[a.style]:r.dfault;a.style==="hr"?a=g.createElement(d,"hr"):(a=this._createDisplayNode(e,a,c),e.contentAssistProposalIndex=c);e.appendChild(a);b.appendChild(e)},createAccessible:function(){var a=this._contentAssistMode,b=this;this.parentNode.addEventListener("keydown",function(c){if(!c)c=window.event;c.preventDefault&&
+c.preventDefault();if(c.keyCode===h.KEY.ESCAPE)return a.cancel();else if(c.keyCode===h.KEY.UP)return a.lineUp();else if(c.keyCode===h.KEY.DOWN)return a.lineDown();else if(c.keyCode===h.KEY.ENTER)return a.enter();else if(c.keyCode===h.KEY.PAGEDOWN)return a.pageDown();else if(c.keyCode===h.KEY.PAGEUP)return a.pageUp();else if(c.keyCode===h.KEY.HOME)return b.scrollIndex(0,!0),a.lineDown(0);else if(c.keyCode===h.KEY.END)return a.lineUp(a.getProposals().length-1);return!1})},_createDisplayNode:function(a,
+b,c){var d=null,e=null;if(typeof b==="string")e=b;else if(b.description&&typeof b.description==="string")if(b.name&&typeof b.name==="string"){var f=this._createNameNode(b.name);f.contentAssistProposalIndex=c;d=document.createElement("span");d.appendChild(f);f=document.createTextNode(b.description);d.appendChild(f);a.setAttribute("title",b.name+b.description)}else e=b.description;else e=b.proposal;e&&(d=this._createNameNode(e),a.setAttribute("title",e));d.contentAssistProposalIndex=c;return d},_createNameNode:function(a){var b=
+document.createElement("span");b.classList.add("proposal-name");b.appendChild(document.createTextNode(a));return b},getProposal:function(a){var b=null,a=a.contentAssistProposalIndex;void 0!==a&&(b=this._contentAssistMode.getProposals()[a]||null);return b},getTopIndex:function(){for(var a=this.parentNode.childNodes,b=0;b<a.length;b++)if(a[b].offsetTop>=this.parentNode.scrollTop)return b;return 0},getBottomIndex:function(){for(var a=this.parentNode.childNodes,b=0;b<a.length;b++){var c=a[b];if(c.offsetTop+
+c.offsetHeight>this.parentNode.scrollTop+this.parentNode.clientHeight)return Math.max(0,b-1)}return a.length-1},scrollIndex:function(a,b){this.parentNode.childNodes[a].scrollIntoView(b);this.preserveCloneThroughScroll=!0},selectNode:function(a){var b=null;if(this.previousSelectedNode)this.previousSelectedNode.classList.remove(r.selected),this.previousSelectedNode=null,this.previousCloneNode&&this._removeCloneNode();if(-1!==a){b=this.parentNode.childNodes[a];b.classList.add(r.selected);this.parentNode.setAttribute("aria-activedescendant",
+b.id);b.focus();if(b.offsetTop<this.parentNode.scrollTop)b.scrollIntoView(!0),this.preserveCloneThroughScroll=!0;else if(b.offsetTop+b.offsetHeight>this.parentNode.scrollTop+this.parentNode.clientHeight)b.scrollIntoView(!1),this.preserveCloneThroughScroll=!0;var c=h.bounds(b.firstChild||b),d=h.bounds(this.parentNode),a=window.getComputedStyle(this.parentNode),e=window.getComputedStyle(b),e=parseInt(a.paddingLeft)+parseInt(a.paddingRight)+parseInt(e.paddingLeft)+parseInt(e.paddingRight);if(c.width>=
+d.width-e){e=parseInt(a.top);d=b.cloneNode(!0);d.classList.add("cloneProposal");d.style.top=e+b.offsetTop-this.parentNode.scrollTop+"px";d.style.left=a.left;d.setAttribute("id",d.id+"_clone");c=c.left+c.width-parseInt(document.documentElement.clientWidth);if(c>0)a=parseInt(a.left)-c,0>a&&(a=0),d.style.left=a+"px";a=document.createElement("div");a.id="clone_contentassist";a.classList.add("contentassist");a.classList.add("cloneWrapper");a.appendChild(d);a.onclick=this.parentNode.onclick;this.parentNode.parentNode.insertBefore(a,
+this.parentNode);var f=function(a){a.contentAssistProposalIndex=b.contentAssistProposalIndex;if(a.hasChildNodes())for(var c=0;c<a.childNodes.length;c++)f(a.childNodes[c])};f(a);b.classList.remove(r.selected);this.previousCloneNode=a}}this.previousSelectedNode=b},setContentAssistMode:function(a){this._contentAssistMode=a},show:function(){var a=this._contentAssistMode.getProposals();if(a.length===0)this.hide();else{this.parentNode.innerHTML="";for(var b=0;b<a.length;b++)this.createDiv(a[b],this.parentNode,
+b);this.position();this.parentNode.onclick=this.onClick.bind(this);this.isShowing=!0;if(!this.textViewListenerAdded)this.textView.addEventListener("MouseDown",this.textViewListener.onMouseDown),this.textViewListenerAdded=!0}},hide:function(){this.parentNode.ownerDocument.activeElement===this.parentNode&&this.textView.focus();this.parentNode.style.display="none";this.parentNode.onclick=null;this.isShowing=!1;if(this.textViewListenerAdded)this.textView.removeEventListener("MouseDown",this.textViewListener.onMouseDown),
+this.textViewListenerAdded=!1;if(this.previousSelectedNode)this.previousSelectedNode=null,this.previousCloneNode&&this._removeCloneNode()},position:function(){var a=this.contentAssist,b=this.textView;if(a.offset!==void 0){var a=a.offset,c=b.getModel();c.getBaseModel&&(a=c.mapOffset(a,!0))}else a=this.textView.getCaretOffset();a=b.getLocationAtOffset(a);a.y+=b.getLineHeight();this.textView.convert(a,"document","page");this.parentNode.style.position="fixed";this.parentNode.style.left=a.x+"px";this.parentNode.style.top=
+a.y+"px";this.parentNode.style.display="block";this.parentNode.scrollTop=0;b=this.parentNode.ownerDocument;c=b.documentElement.clientWidth;if(a.y+this.parentNode.offsetHeight>b.documentElement.clientHeight)this.parentNode.style.top=a.y-this.parentNode.offsetHeight-this.textView.getLineHeight()+"px";if(a.x+this.parentNode.offsetWidth>c)this.parentNode.style.left=c-this.parentNode.offsetWidth+"px"},_removeCloneNode:function(){this.parentNode.parentNode.contains(this.previousCloneNode)&&this.parentNode.parentNode.removeChild(this.previousCloneNode);
+this.previousCloneNode=null}};return{ContentAssist:l,ContentAssistMode:o,ContentAssistWidget:q}});
+define("orion/editor/stylers/lib/syntax",[],function(){return{id:"orion.lib",grammars:[{id:"orion.lib",patterns:[{include:"#brace_open"},{include:"#brace_close"},{include:"#bracket_open"},{include:"#bracket_close"},{include:"#parenthesis_open"},{include:"#parenthesis_close"},{include:"#number_decimal"},{include:"#number_hex"},{include:"#string_doubleQuote"},{include:"#string_singleQuote"}],repository:{brace_open:{match:"{",name:"punctuation.section.block.begin"},brace_close:{match:"}",name:"punctuation.section.block.end"},
+bracket_open:{match:"\\[",name:"punctuation.section.bracket.begin"},bracket_close:{match:"\\]",name:"punctuation.section.bracket.end"},parenthesis_open:{match:"\\(",name:"punctuation.section.parens.begin"},parenthesis_close:{match:"\\)",name:"punctuation.section.parens.end"},doc_block:{begin:"/\\*\\*",end:"\\*/",name:"comment.block.documentation",patterns:[{match:"@(?:(?!\\*/)\\S)*",name:"keyword.other.documentation.tag"},{match:"\\<\\S*\\>",name:"keyword.other.documentation.markup"},{match:"(\\b)(TODO)(\\b)(((?!\\*/).)*)",
+name:"meta.annotation.task.todo",captures:{2:{name:"keyword.other.documentation.task"},4:{name:"comment.block"}}}]},number_decimal:{match:"\\b-?(?:\\.\\d+|\\d+\\.?\\d*)(?:[eE][+-]?\\d+)?\\b",name:"constant.numeric.number"},number_hex:{match:"\\b0[xX][0-9A-Fa-f]+\\b",name:"constant.numeric.hex"},string_doubleQuote:{match:'"(?:\\\\.|[^"])*"?',name:"string.quoted.double"},string_singleQuote:{match:"'(?:\\\\.|[^'])*'?",name:"string.quoted.single"},todo_comment_singleLine:{match:"(\\b)(TODO)(\\b)(.*)",
+name:"meta.annotation.task.todo",captures:{2:{name:"keyword.other.documentation.task"},4:{name:"comment.line"}}}}},{id:"orion.c-like",patterns:[{include:"orion.lib"},{include:"#comment_singleLine"},{include:"#comment_block"}],repository:{comment_singleLine:{match:"//.*",name:"comment.line.double-slash",patterns:[{include:"orion.lib#todo_comment_singleLine"}]},comment_block:{begin:"/\\*",end:"\\*/",name:"comment.block",patterns:[{match:"(\\b)(TODO)(\\b)(((?!\\*/).)*)",name:"meta.annotation.task.todo",
+captures:{2:{name:"keyword.other.documentation.task"},4:{name:"comment.block"}}}]}}}],keywords:[]}});
+define("orion/editor/stylers/text_css/syntax",["orion/editor/stylers/lib/syntax"],function(k){var m="alignment-adjust,alignment-baseline,animation-delay,animation-direction,animation-duration,animation-iteration-count,animation-name,animation-play-state,animation-timing-function,animation,appearance,azimuth,backface-visibility,background-attachment,background-clip,background-color,background-image,background-origin,background-position,background-repeat,background-size,background,baseline-shift,binding,bleed,bookmark-label,bookmark-level,bookmark-state,bookmark-target,border-bottom-color,border-bottom-left-radius,border-bottom-right-radius,border-bottom-style,border-bottom-width,border-bottom,border-collapse,border-color,border-image-outset,border-image-repeat,border-image-slice,border-image-source,border-image-width,border-image,border-left-color,border-left-style,border-left-width,border-left,border-radius,border-right-color,border-right-style,border-right-width,border-right,border-spacing,border-style,border-top-color,border-top-left-radius,border-top-right-radius,border-top-style,border-top-width,border-top,border-width,border,bottom,box-align,box-decoration-break,box-direction,box-flex-group,box-flex,box-lines,box-ordinal-group,box-orient,box-pack,box-shadow,box-sizing,break-after,break-before,break-inside,caption-side,clear,clip,color-profile,color,column-count,column-fill,column-gap,column-rule-color,column-rule-style,column-rule-width,column-rule,column-span,column-width,columns,content,counter-increment,counter-reset,crop,cue-after,cue-before,cue,cursor,direction,display,dominant-baseline,drop-initial-after-adjust,drop-initial-after-align,drop-initial-before-adjust,drop-initial-before-align,drop-initial-size,drop-initial-value,elevation,empty-cells,fit-position,fit,flex-align,flex-flow,flex-inline-pack,flex-order,flex-pack,float-offset,float,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,font,grid-columns,grid-rows,hanging-punctuation,height,hyphenate-after,hyphenate-before,hyphenate-character,hyphenate-lines,hyphenate-resource,hyphens,icon,image-orientation,image-rendering,image-resolution,inline-box-align,left,letter-spacing,line-height,line-stacking-ruby,line-stacking-shift,line-stacking-strategy,line-stacking,list-style-image,list-style-position,list-style-type,list-style,margin-bottom,margin-left,margin-right,margin-top,margin,mark-after,mark-before,mark,marker-offset,marks,marquee-direction,marquee-loop,marquee-play-count,marquee-speed,marquee-style,max-height,max-width,min-height,min-width,move-to,nav-down,nav-index,nav-left,nav-right,nav-up,opacity,orphans,outline-color,outline-offset,outline-style,outline-width,outline,overflow-style,overflow-x,overflow-y,overflow,padding-bottom,padding-left,padding-right,padding-top,padding,page-break-after,page-break-before,page-break-inside,page-policy,page,pause-after,pause-before,pause,perspective-origin,perspective,phonemes,pitch-range,pitch,play-during,position,presentation-level,punctuation-trim,quotes,rendering-intent,resize,rest-after,rest-before,rest,richness,right,rotation-point,rotation,ruby-align,ruby-overhang,ruby-position,ruby-span,size,speak-header,speak-numeral,speak-punctuation,speak,speech-rate,stress,string-set,table-layout,target-name,target-new,target-position,target,text-align-last,text-align,text-decoration,text-emphasis,text-height,text-indent,text-justify,text-outline,text-shadow,text-transform,text-wrap,top,transform-origin,transform-style,transform,transition-delay,transition-duration,transition-property,transition-timing-function,transition,unicode-bidi,vertical-align,visibility,voice-balance,voice-duration,voice-family,voice-pitch-range,voice-pitch,voice-rate,voice-stress,voice-volume,volume,white-space-collapse,white-space,widows,width,word-break,word-spacing,word-wrap,z-index".split(","),k=
+k.grammars;k.push({id:"orion.css",contentTypes:["text/css"],patterns:[{include:"orion.lib"},{include:"orion.c-like#comment_block"},{match:"(?:-webkit-|-moz-|-ms-|\\b)(?:"+m.join("|")+")\\b",name:"keyword.control.css"},{match:"(?i)\\b-?(?:\\.\\d+|\\d+\\.?\\d*)(?:%|em|ex|ch|rem|vw|vh|vmin|vmax|in|cm|mm|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?\\b",name:"constant.numeric.value.css"},{begin:"(['\"])(?:\\\\.|[^\\\\\\1])*\\\\$",end:"^(?:$|(?:\\\\.|[^\\\\\\1])*(\\1|[^\\\\]$))",name:"string.quoted.multiline.css"}],
+repository:{number_hex:{match:"#[0-9A-Fa-f]+\\b",name:"constant.numeric.hex.css"}}});return{id:k[k.length-1].id,grammars:k,keywords:m}});
+define("orion/editor/cssContentAssist",["orion/editor/templates","orion/editor/stylers/text_css/syntax"],function(k,m){function n(a){return JSON.stringify(a).replace("}","\\}")}function i(){}for(var c={type:"link",values:"visible,hidden,scroll,auto,no-display,no-content".split(",")},d={type:"link",values:"solid,dashed,dotted,double,groove,ridge,inset,outset".split(",")},f={type:"link",values:[]},g=0;g<10;g++)f.values.push(g.toString());for(var h={type:"link",values:"black,white,red,green,blue,magenta,yellow,cyan,grey,darkred,darkgreen,darkblue,darkmagenta,darkcyan,darkyellow,darkgray,lightgray".split(",")},
+b=[{prefix:"rule",description:"rule - class selector rule",template:".${class} {\n\t${cursor}\n}"},{prefix:"rule",description:"rule - id selector rule",template:"#${id} {\n\t${cursor}\n}"},{prefix:"outline",description:"outline - outline style",template:"outline: ${color:"+n(h)+"} ${style:"+n(d)+"} ${width:"+n(f)+"}px;"},{prefix:"background-image",description:"background-image - image style",template:'background-image: url("${uri}");'},{prefix:"url",description:"url - url image",template:'url("${uri}");'},
+{prefix:"rgb",description:"rgb - rgb color",template:"rgb(${red},${green},${blue});"},{prefix:"@",description:"import - import style sheet",template:'@import "${uri}";'}],a=[{prop:"display",values:{type:"link",values:"none,block,box,flex,inline,inline-block,inline-flex,inline-table,list-item,table,table-caption,table-cell,table-column,table-column-group,table-footer-group,table-header-group,table-row,table-row-group,inherit".split(",")}},{prop:"overflow",values:c},{prop:"overflow-x",values:c},{prop:"overflow-y",
+values:c},{prop:"float",values:{type:"link",values:["left","right","none","inherit"]}},{prop:"position",values:{type:"link",values:["absolute","fixed","relative","static","inherit"]}},{prop:"cursor",values:{type:"link",values:"auto,crosshair,default,e-resize,help,move,n-resize,ne-resize,nw-resize,pointer,progress,s-resize,se-resize,sw-resize,text,w-resize,wait,inherit".split(",")}},{prop:"color",values:h},{prop:"border-top-color",values:h},{prop:"border-bottom-color",values:h},{prop:"border-right-color",
+values:h},{prop:"border-left-color",values:h},{prop:"background-color",values:h},{prop:"font-style",values:{type:"link",values:["italic","normal","oblique","inherit"]}},{prop:"font-weight",values:{type:"link",values:"bold,normal,bolder,lighter,100,200,300,400,500,600,700,800,900,inherit".split(",")}},{prop:"white-space",values:{type:"link",values:"pre,pre-line,pre-wrap,nowrap,normal,inherit".split(",")}},{prop:"word-wrap",values:{type:"link",values:["normal","break-word"]}},{prop:"visibility",values:{type:"link",
+values:["hidden","visible","collapse","inherit"]}}],g=0;g<a.length;g++)c=a[g],b.push({prefix:c.prop,description:c.prop+" - "+c.prop+" style",template:c.prop+": ${value:"+n(c.values)+"};"});a="width,height,top,bottom,left,right,min-width,min-height,max-width,max-height,margin,padding,padding-left,padding-right,padding-top,padding-bottom,margin-left,margin-top,margin-bottom,margin-right".split(",");for(g=0;g<a.length;g++)c=a[g],b.push({prefix:c,description:c+" - "+c+" pixel style",template:c+": ${value}px;"});
+a=["padding","margin"];for(g=0;g<a.length;g++)c=a[g],b.push({prefix:c,description:c+" - "+c+" top right bottom left style",template:c+": ${top}px ${left}px ${bottom}px ${right}px;"}),b.push({prefix:c,description:c+" - "+c+" top right,left bottom style",template:c+": ${top}px ${right_left}px ${bottom}px;"}),b.push({prefix:c,description:c+" - "+c+" top,bottom right,left style",template:c+": ${top_bottom}px ${right_left}px"});a=["border","border-top","border-bottom","border-left","border-right"];for(g=
+0;g<a.length;g++)c=a[g],b.push({prefix:c,description:c+" - "+c+" style",template:c+": ${width:"+n(f)+"}px ${style:"+n(d)+"} ${color:"+n(h)+"};"});i.prototype=new k.TemplateContentAssist(m.keywords,b);i.prototype.getPrefix=function(a,b){for(var c=b;c&&/[A-Za-z\-\@]/.test(a.charAt(c-1));)c--;return c?a.substring(c,b):""};return{CssContentAssistProvider:i}});
+define("orion/editor/htmlContentAssist",["orion/editor/templates"],function(k){function m(){}var n=new k.Template("","Simple HTML document",'<!DOCTYPE html>\n<html lang="en">\n\t<head>\n\t\t<meta charset=utf-8>\n\t\t<title>${title}</title>\n\t</head>\n\t<body>\n\t\t<h1>${header}</h1>\n\t\t<p>\n\t\t\t${cursor}\n\t\t</p>\n\t</body>\n</html>'),i=[{prefix:"<img",name:"<img>",description:" - HTML image element",template:'<img src="${cursor}" alt="${Image}"/>'},{prefix:"<a",name:"<a>",description:" - HTML anchor element",
+template:'<a href="${cursor}"></a>'},{prefix:"<ul",name:"<ul>",description:" - HTML unordered list",template:"<ul>\n\t<li>${cursor}</li>\n</ul>"},{prefix:"<ol",name:"<ol>",description:" - HTML ordered list",template:"<ol>\n\t<li>${cursor}</li>\n</ol>"},{prefix:"<dl",name:"<dl>",description:" - HTML definition list",template:"<dl>\n\t<dt>${cursor}</dt>\n\t<dd></dd>\n</dl>"},{prefix:"<table",name:"<table>",description:" - basic HTML table",template:"<table>\n\t<tr>\n\t\t<td>${cursor}</td>\n\t</tr>\n</table>"},
+{prefix:"<\!--",name:"<\!-- --\>",description:" - HTML comment",template:"<\!-- ${cursor} --\>"}],c,d,f,g,h="abbr,b,button,canvas,cite,command,dd,del,dfn,dt,em,embed,font,h1,h2,h3,h4,h5,h6,i,ins,kbd,label,li,mark,meter,object,option,output,progress,q,rp,rt,samp,small,strong,sub,sup,td,time,title,tt,u,var".split(",");for(g=0;g<h.length;g++)c=h[g],f="<"+c+"></"+c+">",d="<"+c+">${cursor}</"+c+">",i.push({prefix:"<"+c,description:f,template:d});h="address,article,aside,audio,bdo,blockquote,body,caption,code,colgroup,datalist,details,div,fieldset,figure,footer,form,head,header,hgroup,iframe,legend,map,menu,nav,noframes,noscript,optgroup,p,pre,ruby,script,section,select,span,style,tbody,textarea,tfoot,th,thead,tr,video".split(",");
+for(g=0;g<h.length;g++)c=h[g],f="<"+c+"></"+c+">",d="<"+c+">\n\t${cursor}\n</"+c+">",i.push({prefix:"<"+c,description:f,template:d});h="area,base,br,col,hr,input,link,meta,param,keygen,source".split(",");for(g=0;g<h.length;g++)c=h[g],d=f="<"+c+"/>",i.push({prefix:"<"+c,description:f,template:d});m.prototype=new k.TemplateContentAssist([],i);m.prototype.getPrefix=function(b,a){for(var c="",d=a;d&&/[A-Za-z0-9<!-]/.test(b.charAt(d-1));)if(d--,b.charAt(d)==="<"){c=b.substring(d,a);break}return c};m.prototype.computeProposals=
+function(b,a,c){return b.length===0?[n.getProposal("",a,c)]:k.TemplateContentAssist.prototype.computeProposals.call(this,b,a,c).sort(function(a,b){var c=a.prefix||a.proposal,d=b.prefix||b.proposal;if(c){if(!d)return 1}else return-1;return c.toLowerCase().localeCompare(d.toLowerCase())})};return{HTMLContentAssistProvider:m}});
+define("orion/editor/stylers/application_javascript/syntax",["orion/editor/stylers/lib/syntax"],function(k){var m="break,case,class,catch,continue,const,debugger,default,delete,do,else,enum,export,extends,false,finally,for,function,if,implements,import,in,instanceof,interface,let,new,null,package,private,protected,public,return,static,super,switch,this,throw,true,try,typeof,undefined,var,void,while,with,yield".split(","),k=k.grammars;k.push({id:"orion.js",contentTypes:["application/javascript"],patterns:[{include:"orion.lib#doc_block"},
+{include:"orion.c-like"},{match:"\\b(?:"+m.join("|")+")\\b",name:"keyword.control.js"},{begin:"(['\"])(?:\\\\.|[^\\\\\\1])*\\\\$",end:"^(?:$|(?:\\\\.|[^\\\\\\1])*(\\1|[^\\\\]$))",name:"string.quoted.multiline.js"}]});return{id:k[k.length-1].id,grammars:k,keywords:m}});
+define("orion/editor/jsTemplateContentAssist",["orion/editor/templates","orion/editor/stylers/application_javascript/syntax"],function(k,m){function n(){}var i=[{prefix:"if",name:"if",description:" - if statement",template:"if (${condition}) {\n\t${cursor}\n}"},{prefix:"if",name:"if",description:" - if else statement",template:"if (${condition}) {\n\t${cursor}\n} else {\n\t\n}"},{prefix:"for",name:"for",description:" - iterate over array",template:"for (var ${i}=0; ${i}<${array}.length; ${i}++) {\n\t${cursor}\n}"},
+{prefix:"for",name:"for",description:" - iterate over array with local var",template:"for (var ${i}=0; ${i}<${array}.length; ${i}++) {\n\tvar ${value} = ${array}[${i}];\n\t${cursor}\n}"},{prefix:"for",name:"for..in",description:" - iterate over properties of an object",template:"for (var ${property} in ${object}) {\n\tif (${object}.hasOwnProperty(${property})) {\n\t\t${cursor}\n\t}\n}"},{prefix:"while",name:"while",description:" - while loop with condition",template:"while (${condition}) {\n\t${cursor}\n}"},
+{prefix:"do",name:"do",description:" - do while loop with condition",template:"do {\n\t${cursor}\n} while (${condition});"},{prefix:"switch",name:"switch",description:" - switch case statement",template:"switch (${expression}) {\n\tcase ${value1}:\n\t\t${cursor}\n\t\tbreak;\n\tdefault:\n}"},{prefix:"case",name:"case",description:" - case statement",template:"case ${value}:\n\t${cursor}\n\tbreak;"},{prefix:"try",name:"try",description:" - try..catch statement",template:"try {\n\t${cursor}\n} catch (${err}) {\n}"},
+{prefix:"try",name:"try",description:" - try..catch statement with finally block",template:"try {\n\t${cursor}\n} catch (${err}) {\n} finally {\n}"},{prefix:"typeof",name:"typeof",description:" - typeof statement",template:'typeof ${object} === "${type:'+JSON.stringify({type:"link",values:"undefined,object,boolean,number,string,function,xml".split(",")}).replace("}","\\}")+'}"'},{prefix:"instanceof",name:"instanceof",description:" - instanceof statement",template:"${object} instanceof ${type}"},{prefix:"with",
+name:"with",description:" - with statement",template:"with (${object}) {\n\t${cursor}\n}"},{prefix:"function",name:"function",description:" - function declaration",template:"/**\n * @name ${name}\n * @param ${parameter}\n */\nfunction ${name} (${parameter}) {\n\t${cursor}\n}"},{prefix:"function",name:"function",description:" - function expression",template:"/**\n * @name ${name}\n * @function\n * @param ${parameter}\n */\n${name}: function(${parameter}) {\n\t${cursor}\n}"},{prefix:"define",name:"define",
+description:" - define function call",template:"/* global define */\ndefine('${name}',[\n'${import}'\n], function(${importname}) {\n\t${cursor}\n});"},{prefix:"nls",name:"nls",description:" - non NLS string",template:"${cursor} //$NON-NLS-${0}$"},{prefix:"log",name:"log",description:" - console log",template:"console.log(${object});"},{prefix:"mongodb",name:"mongodb",description:" - Node.js require statement for MongoDB",template:"var ${name} = require('mongodb');\n"},{prefix:"mongodb",name:"mongodb client",
+description:" - create a new MongoDB client",template:"var MongoClient = require('mongodb').MongoClient;\nvar Server = require('mongodb').Server;\n${cursor}"},{prefix:"mongodb",name:"mongodb open",description:" - create a new MongoDB client and open a connection",template:"var MongoClient = require('mongodb').MongoClient;\nvar Server = require('mongodb').Server;\nvar ${client} = new MongoClient(new Server(${host}, ${port}));\ntry {\n\t${client}.open(function(error, ${client}) {\n\t\tvar ${db} = ${client}.db(${name});\n\t\t${cursor}\n\t});\n} finally {\n\t${client}.close();\n};"},
+{prefix:"mongodb",name:"mongodb connect",description:" - connect to an existing MongoDB database",template:"var MongoClient = require('mongodb').MongoClient;\nMongoClient.connect(${url}, function(error, db) {\n\t${cursor}\n});\n"},{prefix:"mongodb",name:"mongodb connect (Cloud Foundry)",description:" - connect to an existing MongoDB database using Cloud Foundry",template:"if (${process}.env.VCAP_SERVICES) {\n\tvar env = JSON.parse(${process}.env.VCAP_SERVICES);\n\tvar mongo = env['${mongo-version}'][0].credentials;\n} else {\n\tvar mongo = {\n\t\tusername : 'username',\n\t\tpassword : 'password',\n\t\turl : 'mongodb://username:password@localhost:27017/database'\n\t};\n}\nvar MongoClient = require('mongodb').MongoClient;\nMongoClient.connect(mongo.url, function(error, db) {\n\t${cursor}\n});\n"},
+{prefix:"mongodb",name:"mongodb collection",description:" - create a MongoDB database collection",template:"${db}.collection(${id}, function(${error}, collection) {\n\t${cursor}\n});"},{prefix:"mongodb",name:"mongodb strict collection",description:" - create a MongoDB database strict collection",template:"${db}.collection(${id}, {strict:true}, function(${error}, collection) {\n\t${cursor}\n});"},{prefix:"redis",name:"redis",description:" - Node.js require statement for Redis",template:"var ${name} = require('redis');\n"},
+{prefix:"redis",name:"redis client",description:" - create a new Redis client",template:"var ${name} = require('redis');\nvar ${client} = ${name}.createClient(${port}, ${host}, ${options});\n"},{prefix:"redis",name:"redis connect",description:" - create a new Redis client and connect",template:"var ${name} = require('redis');\nvar ${client} = ${name}.createClient(${port}, ${host}, ${options});\ntry {\n\t${cursor}\n} finally {\n\t${client}.close();\n}\n"},{prefix:"redis",name:"redis set",description:" - create a new Redis client set call",
+template:"client.set(${key}, ${value});\n"},{prefix:"redis",name:"redis get",description:" - create a new Redis client get call",template:"client.get(${key}, function(${error}, ${reply}) {\n\t${cursor}\n});\n"},{prefix:"redis",name:"redis on",description:" - create a new Redis client event handler",template:"client.on(${event}, function(${arg}) {\n\t${cursor}});\n"},{prefix:"pg",name:"postgres",description:" - Node.js require statement for Postgres DB",template:"var pg = require('pg');\n"},{prefix:"pg",
+name:"postgres client",description:" - create a new Postgres DB client",template:"var pg = require('pg');\nvar url = \"postgres://postgres:${port}@${host}/${database}\";\nvar ${client} = new pg.Client(url);\n"},{prefix:"pg",name:"postgres connect",description:" - create a new Postgres DB client and connect",template:"var pg = require('pg');\nvar url = \"postgres://postgres:${port}@${host}/${database}\";\nvar ${client} = new pg.Client(url);\n${client}.connect(function(error) {\n\t${cursor}\n});\n"},
+{prefix:"pg",name:"postgres query",description:" - create a new Postgres DB query statement",template:"${client}.query(${sql}, function(error, result) {\n\t${cursor}\n});\n"},{prefix:"mysql",name:"mysql",description:" - Node.js require statement for MySQL DB",template:"var mysql = require('mysql');\n"},{prefix:"mysql",name:"mysql connection",description:" - create a new MySQL DB connection",template:"var mysql = require('mysql');\nvar ${connection} = mysql.createConnection({\n\thost : ${host},\n\tuser : ${username},\n\tpassword : ${password}\n});\ntry {\n\t${connection}.connect();\n\t${cursor}\n} finally {\n\t${connection}.end();\n}"},
+{prefix:"mysql",name:"mysql query",description:" - create a new MySQL DB query statement",template:"${connection}.query(${sql}, function(error, rows, fields) {\n\t${cursor}\n});\n"},{prefix:"express",name:"express",description:" - Node.js require statement for Express",template:"var ${name} = require('express');"},{prefix:"express",name:"express app",description:" - create a new Express app",template:"var express = require('express');\nvar ${app} = express();\n${cursor}\napp.listen(${timeout});\n"},
+{prefix:"express",name:"express configure",description:" - create an Express app configure statement",template:"app.configure(function() {\n\tapp.set(${id}, ${value});\n});"},{prefix:"express",name:"express specific configure",description:" - create a specific Express app configure statement",template:"app.configure(${name}, function() {\n\tapp.set(${id}, ${value});\n});"},{prefix:"express",name:"express app get",description:" - create a new Express app.get call",template:"var value = app.get(${id}, function(request, result){\n\t${cursor}\n});\n"},
+{prefix:"express",name:"express app set",description:" - create a new Express app set call",template:"app.set(${id}, ${value});\n"},{prefix:"express",name:"express app use",description:" - create a new Express app use statement",template:"app.use(${fnOrObject});\n"},{prefix:"express",name:"express app engine",description:" - create a new Express app engine statement",template:"app.engine(${fnOrObject});\n"},{prefix:"express",name:"express app param",description:" - create a new Express app param statement",
+template:"app.param(${id}, ${value});\n"},{prefix:"express",name:"express app error use",description:" - create a new Express app error handling use statement",template:"app.use(function(error, request, result, next) {\n\tresult.send(${code}, ${message});\n});\n"},{prefix:"amqp",name:"amqp",description:" - Node.js require statement for AMQP framework",template:"var amqp = require('amqp');\n"},{prefix:"amqp",name:"amqp connection",description:" - create a new AMQP connection ",template:"var amqp = require('amqp');\nvar ${connection} = amqp.createConnection({\n\thost: ${host},\n\tport: ${port},\n\tlogin: ${login},\n\tpassword: ${password}\n});\n"},
+{prefix:"amqp",name:"amqp on",description:" - create a new AMQP connection on statement",template:"${connection}.on(${event}, function() {\n\t${cursor}\n});\n"},{prefix:"amqp",name:"amqp queue",description:" - create a new AMQP connection queue statement",template:"${connection}.queue(${id}, function(queue) {\n\tqueue.bind('#'); //catch all messages\n\tqueue.subscribe(function (message, headers, deliveryInfo) {\n\t\t// Receive messages\n\t});\n\t${cursor}\n});\n"},{prefix:"amqp",name:"amqp exchange",
+description:" - create a new AMQP connection exchange",template:"var exchange = ${connection}.exchange(${id}, {type: 'topic'}, function(exchange) {\n\t${cursor}\n});\n"}];n.prototype=new k.TemplateContentAssist(m.keywords,i);n.prototype.isValid=function(c,d,f){c=d.charAt(f-c.length-1);return!c||":!@#$^&*.?<>".indexOf(c)===-1};return{JSTemplateContentAssistProvider:n}});
+define("orion/editor/AsyncStyler",["i18n!orion/editor/nls/messages","orion/editor/annotations"],function(k,m){function n(d){return d.getProperty("objectClass").indexOf(c)!==-1&&d.getProperty("type")==="highlighter"}function i(c,d,h){this.initialize(c,d,h);this.lineStyles=[]}var c="orion.edit.highlighter",d=c+" service must be an event emitter";m.AnnotationType.registerType("orion.annotation.highlightError",{title:k.syntaxError,html:"<div class='annotationHTML error'></div>",rangeStyle:{styleClass:"annotationRange error"}});
+i.prototype={initialize:function(d,g,h){this.textView=d;this.serviceRegistry=g;this.annotationModel=h;this.services=[];var b=this;this.listener={onModelChanging:function(a){b.onModelChanging(a)},onModelChanged:function(a){b.onModelChanged(a)},onDestroy:function(a){b.onDestroy(a)},onLineStyle:function(a){b.onLineStyle(a)},onStyleReady:function(a){b.onStyleReady(a)},onServiceAdded:function(a){b.onServiceAdded(a.serviceReference,b.serviceRegistry.getService(a.serviceReference))},onServiceRemoved:function(a){b.onServiceRemoved(a.serviceReference,
+b.serviceRegistry.getService(a.serviceReference))}};d.addEventListener("ModelChanging",this.listener.onModelChanging);d.addEventListener("ModelChanged",this.listener.onModelChanged);d.addEventListener("Destroy",this.listener.onDestroy);d.addEventListener("LineStyle",this.listener.onLineStyle);g.addEventListener("registered",this.listener.onServiceAdded);g.addEventListener("unregistering",this.listener.onServiceRemoved);d=g.getServiceReferences(c);for(h=0;h<d.length;h++){var a=d[h];n(a)&&this.addServiceListener(g.getService(a))}},
+onDestroy:function(){this.destroy()},destroy:function(){if(this.textView)this.textView.removeEventListener("ModelChanging",this.listener.onModelChanging),this.textView.removeEventListener("ModelChanged",this.listener.onModelChanged),this.textView.removeEventListener("Destroy",this.listener.onDestroy),this.textView.removeEventListener("LineStyle",this.listener.onLineStyle),this.textView=null;if(this.services){for(var c=0;c<this.services.length;c++)this.removeServiceListener(this.services[c]);this.services=
+null}if(this.serviceRegistry)this.serviceRegistry.removeEventListener("registered",this.listener.onServiceAdded),this.serviceRegistry.removeEventListener("unregistering",this.listener.onServiceRemoved),this.serviceRegistry=null;this.lineStyles=this.listener=null},onModelChanging:function(c){this.startLine=this.textView.getModel().getLineAtOffset(c.start)},onModelChanged:function(c){var d=this.startLine;(c.addedLineCount||c.removedLineCount)&&Array.prototype.splice.apply(this.lineStyles,[d,c.removedLineCount].concat(this._getEmptyStyle(c.addedLineCount)))},
+onStyleReady:function(c){var d=c.lineStyles||c.style,c=Number.MAX_VALUE,h=-1,b=this.textView.getModel(),a;for(a in d)Object.prototype.hasOwnProperty.call(d,a)&&(this.lineStyles[a]=d[a],c=Math.min(c,a),h=Math.max(h,a));c=Math.max(c,0);h=Math.min(h,b.getLineCount());if(d=this.annotationModel){for(var e=d.getAnnotations(b.getLineStart(c),b.getLineEnd(h)),i=[];e.hasNext();){var k=e.next();k.type==="orion.annotation.highlightError"&&i.push(k)}e=[];for(k=c;k<=h;k++){a=k;var q=this.lineStyles[a],q=q&&q.errors;
+a=b.getLineStart(a);if(q)for(var r=0;r<q.length;r++){var p=q[r];e.push(m.AnnotationType.createAnnotation("orion.annotation.highlightError",p.start+a,p.end+a))}}d.replaceAnnotations(i,e)}this.textView.redrawLines(c,h+1)},onLineStyle:function(c){function d(b,a){for(var c=b.length,f=[],g=0;g<c;g++){var h=b[g];f.push({start:h.start+a,end:h.end+a,style:h.style})}return f}var h=this.lineStyles[c.lineIndex];if(h)if(h.ranges)c.ranges=d(h.ranges,c.lineStart);else if(h.style)c.style=h.style},_getEmptyStyle:function(c){for(var d=
+[],h=0;h<c;h++)d.push(null);return d},setContentType:function(c){this.contentType=c;if(this.services)for(c=0;c<this.services.length;c++){var d=this.services[c];if(d.setContentType){var h=this.serviceRegistry.getService("orion.page.progress");h?h.progress(d.setContentType(this.contentType),"Styling content type: "+this.contentType.id?this.contentType.id:this.contentType):d.setContentType(this.contentType)}}},onServiceAdded:function(c,d){n(c)&&this.addServiceListener(d)},onServiceRemoved:function(c,
+d){this.services.indexOf(d)!==-1&&this.removeServiceListener(d)},addServiceListener:function(c){if(typeof c.addEventListener==="function"){if(c.addEventListener("orion.edit.highlighter.styleReady",this.listener.onStyleReady),this.services.push(c),c.setContentType&&this.contentType){var g=this.serviceRegistry.getService("orion.page.progress");g?g.progress(c.setContentType(this.contentType),"Styling content type: "+this.contentType.id?this.contentType.id:this.contentType):c.setContentType(this.contentType)}}else typeof console!==
+"undefined"&&console.log(Error(d))},removeServiceListener:function(c){typeof c.removeEventListener==="function"?(c.removeEventListener("orion.edit.highlighter.styleReady",this.listener.onStyleReady),c=this.services.indexOf(c),c!==-1&&this.services.splice(c,1)):typeof console!=="undefined"&&console.log(Error(d))}};return i});
+define("orion/editor/mirror",["i18n!orion/editor/nls/messages","orion/editor/eventTarget","orion/editor/annotations"],function(k,m,n){function i(b){this.string=b;this.tokenStart=this.pos=0}function c(){return{token:function(b){return b.skipToEnd()}}}function d(){this._modes={};this.mimeModes={};this.options={};this.StringStream=i;this.defineMode("null",c);this.defineMIME("text/plain","null")}function f(b){var a=[],c;for(c in b)Object.prototype.hasOwnProperty.call(b,c)&&a.push(c);return a}function g(b,
+a,c){c=c||{};this.model=b;this.codeMirror=a;this.isWhitespaceVisible=typeof c.whitespacesVisible==="undefined"?!1:c.whitespacesVisible;this.mode=null;this.isModeLoaded=!1;this.lines=[];this.dirtyLines=[];this.startLine=Number.MAX_VALUE;this.endLine=-1;this.timer=null;this.initialize(b)}function h(b,a,c){this.init(b,a,c)}i.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos===0},peek:function(){return this.string[this.pos]},next:function(){return this.string[this.pos++]},
+eat:function(b){var a=this.string[this.pos];return typeof a==="string"&&(a===b||b.test&&b.test(a)||typeof b==="function"&&b(a))?this.string[this.pos++]:void 0},eatWhile:function(b){for(var a=!1;this.eat(b)!==void 0;)a=!0;return a},eatSpace:function(){return this.eatWhile(/\s/)},skipToEnd:function(){this.pos=this.string.length},skipTo:function(b){b=this.string.indexOf(b,this.pos);return b!==-1?(this.pos=b,!0):!1},match:function(b,a,c){a=a===!0||typeof a==="undefined";if(typeof b==="string"){var d=
+c?this.string.toLowerCase():this.string,b=c?b.toLowerCase():b,c=d.indexOf(b,this.pos);if(c!==-1&&a)this.pos=c+b.length;return c!==-1}else return(b=this.string.substring(this.pos).match(b))&&a&&typeof b[0]==="string"&&(this.pos+=b.index+b[0].length),b},backUp:function(b){this.pos-=b},column:function(){for(var b=0,a=0;a<this.tokenStart;)b+=this.string[a++]==="\t"?4:1;return b},indentation:function(){for(var b=this.string.search(/\S/),a=0,c=0;c<b;)a+=this.string[c++]==="\t"?4:1;return a},current:function(){return this.string.substring(this.tokenStart,
+this.pos)},advance:function(){this.tokenStart=this.pos}};d.prototype={options:{},setOption:function(b,a){this.options[b]=a},getOption:function(b){return this.options[b]},copyState:function(b,a){if(typeof b.copyState==="function")return b.copyState(a);var c={},d;for(d in a){var f=a[d];c[d]=f instanceof Array?f.slice():f}return c},startState:function(b,a){return b.startState(a)},defineMode:function(b,a){this._modes[b]=a},defineMIME:function(b,a){this.mimeModes[b]=a},getMode:function(b,a){var c={},d;
+typeof a==="string"&&this.mimeModes[a]&&(a=this.mimeModes[a]);typeof a==="object"&&(c=a,d=this._modes[a.name]);d=d||this._modes[a];return typeof d!=="function"?(typeof console!=="undefined"&&console&&console.log("Mode not found: "+a),this.getMode(b,"null")):d(b,c)},listModes:function(){return f(this._modes)},listMIMEs:function(){return f(this.mimeModes)},_getModeName:function(b){b=this.mimeModes[b];if(typeof b==="object")b=b.name;return b}};g.prototype={initialize:function(){var b=this;this.listener=
+{onModelChanging:function(a){b._onModelChanging(a)},onModelChanged:function(a){b._onModelChanged(a)},onDestroy:function(a){b._onDestroy(a)}};this.model.addEventListener("Changing",this.listener.onModelChanging);this.model.addEventListener("Changed",this.listener.onModelChanged);this.model.addEventListener("Destroy",this.listener.onDestroy)},destroy:function(){this.model&&(this.model.removeEventListener("Changing",this.listener.onModelChanging),this.model.removeEventListener("Changed",this.listener.onModelChanged),
+this.model.removeEventListener("Destroy",this.listener.onDestroy));this.dirtyLines=this.lines=this.mode=this.codeMirror=this.model=null;clearTimeout(this.timer);this.timer=null},_onModelChanging:function(b){this.startLine=this.model.getLineAtOffset(b.start)},_onModelChanged:function(b){this._dbgEvent(b);var a=this.startLine;(b.removedLineCount||b.addedLineCount)&&Array.prototype.splice.apply(this.lines,[a+1,b.removedLineCount].concat(this._newLines(b.addedLineCount)));this.mode&&(b=Math.max(b.addedLineCount,
+b.removedLineCount),b=a+Math.min(b,500),this.highlight(a,b),this.highlightLater(b+1))},_onDestroy:function(){this.destroy()},setViewportIndex:function(b){this.viewportIndex=b},_dbgEvent:function(){},_dbgStyle:function(){},_newLines:function(b){for(var a=[],c=0;c<b;c++)a.push({style:null,eolState:null});return a},setMode:function(b,a){if(b)this.mode=this.codeMirror.getMode(this.codeMirror.options,b),this.lines=this._newLines(this.model.getLineCount()),a&&this.highlight()},highlight:function(b,a,c){if(this.mode){for(var d=
+this.model.getLineCount(),b=typeof b==="undefined"?0:b,a=typeof a==="undefined"?d-1:Math.min(a,d-1),d=this.mode,f=this.getState(b),g=b;g<=a;g++){var h=this.lines[g];this.highlightLine(g,h,f);h.eolState=this.codeMirror.copyState(d,f)}this._expandRange(b,a);if(!c)this.onHighlightDone()}},highlightLater:function(b){this.dirtyLines.push(b);var a=this;this.timer=setTimeout(function(){a._highlightJob()},50)},_highlightJob:function(){for(var b=+new Date+30,a=this.mode.compareStates,c=this.model.getLineCount();this.dirtyLines.length;){var d=
+this.viewportIndex,f=this.lines[d],d=f&&!f.eolState?d:this.dirtyLines.pop();if(d>=c)break;this._expandRange(d,d);for(var f=this._getResumeLineIndex(d),d=f+1,f=(f=f>=0&&this.lines[f].eolState)?this.codeMirror.copyState(this.mode,f):this.mode.startState(),g=0,h=d;h<c;h++){var i=this.lines[h],k=i.eolState,m=this.highlightLine(h,i,f);i.eolState=this.codeMirror.copyState(this.mode,f);m&&this._expandRange(d,h+1);var i=a&&k&&a(k,i.eolState),s=!a&&!m&&g++>3;if(i||s)break;else if(!k||m)g=0;k=h<c||this.dirtyLines.length;
+if(+new Date>b&&k){this.highlightLater(h+1);this.onHighlightDone();return}}}this.onHighlightDone()},onHighlightDone:function(){this.startLine!==Number.MAX_VALUE&&this.endLine!==-1&&this.dispatchEvent({type:"Highlight",start:this.startLine,end:this.endLine});this.startLine=Number.MAX_VALUE;this.endLine=-1},_getResumeLineIndex:function(b){for(var a=this.lines,c=b-1;c>=0;c--)if(a[c].eolState||b-c>40)return c;return-1},getState:function(b){var a=this.mode,c=this.lines,d,f;for(d=b-1;d>=0;d--)if(f=c[d],
+f.eolState||b-d>40)break;var g=d>=0&&c[d].eolState;if(g){g=this.codeMirror.copyState(a,g);for(d=Math.max(0,d);d<b-1;d++)f=c[d],this.highlightLine(d,f,g),f.eolState=this.codeMirror.copyState(a,g);return g}else return a.startState()},highlightLine:function(b,a,c){if(this.mode){var d=this.model;d.getLineStart(b)===d.getLineEnd(b)&&this.mode.blankLine&&this.mode.blankLine(c);for(var f=a.style||[],b=d.getLine(b),b=new i(b),d=!a.style,g=[],h=0;!b.eol();h++){var k=this.mode.token(b,c)||null,m=b.current();
+this._whitespaceStyle(k,m,b.tokenStart);k=[b.tokenStart,b.pos,k];m=f[h];g.push(k);d=d||!m||m[0]!==k[0]||m[1]!==k[1]||m[2]!==k[2];b.advance()}if(d=d||g.length!==f.length)a.style=g.length?g:null;return d}},_whitespaceStyle:function(b,a,c){if(!b&&this.isWhitespaceVisible&&/\s+/.test(a)){for(var b=[],d,f,g=0;g<a.length;g++){var h=a[g];h!==f&&(f&&b.push([c+d,c+g,f==="\t"?"punctuation separator tab":"punctuation separator space"]),d=g,f=h)}b.push([c+d,c+g,f==="\t"?"punctuation separator tab":"punctuation separator space"]);
+return b}return null},_expandRange:function(b,a){this.startLine=Math.min(this.startLine,b);this.endLine=Math.max(this.endLine,a)},toStyleRangesAndErrors:function(b,a){var c=b.style;if(!c)return null;for(var d=[],f=[],g=typeof a==="undefined"?0:this.model.getLineStart(a),h=0;h<c.length;h++){var i=c[h],k=!i[2]?null:i[2]==="punctuation separator tab"||i[2]==="punctuation separator space"?i[2]:"cm-"+i[2];k&&(i={start:g+i[0],end:g+i[1],style:{styleClass:k}},d.push(i),k==="cm-error"&&f.push(i))}return[d,
+f]},getLineStyle:function(b){return this.lines[b]},getLineStyles:function(){return this.lines}};m.EventTarget.addMixin(g.prototype);n.AnnotationType.registerType("orion.annotation.highlightError",{title:k.syntaxError,html:"<div class='annotationHTML error'></div>",rangeStyle:{styleClass:"annotationRange error"}});h.prototype={init:function(b,a,c){this.textView=b;this.annotationModel=c;this.modeApplier=new g(b.getModel(),a);var d=this;this.listener={onLineStyle:function(a){d.onLineStyle(a)},onDestroy:function(a){d.onDestroy(a)},
+onHighlight:function(a){d.onHighlight(a)}};b.addEventListener("LineStyle",this.listener.onLineStyle);b.addEventListener("Destroy",this.listener.onDestroy);this.modeApplier.addEventListener("Highlight",this.listener.onHighlight)},destroy:function(){this.modeApplier&&(this.modeApplier.removeEventListener("Highlight",this.listener.onHighlight),this.modeApplier.destroy());this.textView&&(this.textView.removeEventListener("LineStyle",this.listener.onLineStyle),this.textView.removeEventListener("Destroy",
+this.listener.onDestroy));this.listener=this.modeApplier=this.annotationModel=this.textView=null},setMode:function(b){this.modeApplier.setMode(b)},onLineStyle:function(b){var a=b.lineIndex,c=this.modeApplier,d=c.getLineStyle(a);if(!d||!d.eolState){var f=this.textView.getModel().getLineCount();c.highlight(a,Math.min(a+20,f-1),!0);d=c.getLineStyle(a)}f=this.textView.getModel();if(d){var g=c.toStyleRangesAndErrors(d,a);if(g&&(b.ranges=g[0],b=this.annotationModel)){c=[];d=[];if(g=g[1])for(var h=0;h<g.length;h++){var i=
+g[h];i.style.styleClass==="cm-error"&&d.push(n.AnnotationType.createAnnotation("orion.annotation.highlightError",i.start,i.end))}for(a=b.getAnnotations(f.getLineStart(a),f.getLineEnd(a));a.hasNext();)f=a.next(),f.type==="orion.annotation.highlightError"&&c.push(f);b.replaceAnnotations(c,d)}}},onHighlight:function(b){this.textView.redrawLines(b.start,b.end)},onDestroy:function(){this.destroy()}};return{Mirror:d,ModeApplier:g,CodeMirrorStyler:h}});
+define("orion/editor/textMateStyler",["orion/regex"],function(k){function m(c){var d;if(c instanceof Array){d=Array(c.length);for(var f=0;f<c.length;f++)d[f]=m(c[f])}else for(f in d={},c)if(Object.prototype.hasOwnProperty.call(c,f)){var g=c[f];d[f]=typeof g==="object"&&g!==null?m(g):g}return d}function n(c,d,f){this.initialize(c);this.grammar=m(d);this.externalGrammars=f?m(f):[];this._styles={};this._tree=null;this._allGrammars={};this.preprocess(this.grammar)}var i={unsupported:[{regex:/\(\?[ims\-]:/,
+func:function(){return"option on/off for subexp"}},{regex:/\(\?<([=!])/,func:function(c){return c[1]==="="?"lookbehind":"negative lookbehind"}},{regex:/\(\?>/,func:function(){return"atomic group"}}],toRegExp:function(c){function d(b,a){throw Error('Unsupported regex feature "'+b+'": "'+a[0]+'" at index: '+a.index+" in "+a.input);}var f="",g,c=i.processGlobalFlag("x",c,function(b){for(var a="",c=!1,d=b.length,f=0;f<d;){var g=b.charAt(f);if(!c&&g==="#")for(;f<d&&g!=="\r"&&g!=="\n";)g=b.charAt(++f);
+else if(!c&&/\s/.test(g))for(;f<d&&/\s/.test(g);)g=b.charAt(++f);else g==="\\"?(a+=g,/\s/.test(b.charAt(f+1))||(a+=b.charAt(f+1),f+=1)):(g==="["?c=!0:g==="]"&&(c=!1),a+=g),f+=1}return a}),c=i.processGlobalFlag("i",c,function(b){f+="i";return b});for(g=0;g<this.unsupported.length;g++){var h;(h=this.unsupported[g].regex.exec(c))&&d(this.unsupported[g].func(h),h)}return RegExp(c,f)},processGlobalFlag:function(c,d,f){function g(b,a){for(var c=0,d=b.length,f=-1,g=a;g<d&&f===-1;g++)switch(b.charAt(g)){case "\\":g++;
+break;case "(":c++;break;case ")":c--,c===0&&(f=g)}return f}var h="(?"+c+")",c="(?"+c+":";if(d.substring(0,h.length)===h)return f(d.substring(h.length));else if(d.substring(0,c.length)===c){h=g(d,0);if(h<d.length-1)throw Error("Only a "+c+") group that encloses the entire regex is supported in: "+d);return f(d.substring(c.length,h))}return d},hasBackReference:function(c){return/\\\d+/.test(c.source)},getSubstitutedRegex:function(c,d,f){for(var f=typeof f==="undefined"?!0:!1,c=c.source.split(/(\\\d+)/g),
+g=[],h=0;h<c.length;h++){var b=c[h],a=/\\(\d+)/.exec(b);a?(b=d[a[1]]||"",g.push(f?k.escape(b):b)):g.push(b)}return RegExp(g.join(""))},groupify:function(c,d){for(var f=c.source,g=f.length,h=[],b=0,a=[],e=1,i=1,k=[],m={},r={},p=0;p<g;p++){var n=h[h.length-1],v=f.charAt(p);switch(v){case "(":if(n===4)h.pop(),k.push(")"),a[a.length-1].end=p;var s=p+2<g?f.charAt(p+1)+""+f.charAt(p+2):null;if(s==="?:"||s==="?="||s==="?!"){var u;s==="?:"?u=1:(u=3,b++);h.push(u);a.push({start:p,end:-1,type:u});k.push(v);
+k.push(s);p+=s.length}else h.push(2),a.push({start:p,end:-1,type:2,oldNum:e,num:i}),k.push(v),b===0&&(r[i]=null),m[e]=i,e++,i++;break;case ")":n=h.pop();n===3&&b--;a[a.length-1].end=p;k.push(v);break;case "*":case "+":case "?":case "}":var j=v,w=f.charAt(p-1),s=p-1;if(v==="}"){for(u=p-1;f.charAt(u)!=="{"&&u>=0;u--);w=f.charAt(u-1);s=u-1;j=f.substring(u,p+1)}u=a[a.length-1];if(w===")"&&(u.type===2||u.type===4)){k.splice(u.start,0,"(");k.push(j);k.push(")");v={start:u.start,end:k.length-1,type:4,num:u.num};
+for(w=0;w<a.length;w++)if(n=a[w],(n.type===2||n.type===4)&&n.start>=u.start&&n.end<=s)if(n.start+=1,n.end+=1,n.num+=1,n.type===2)m[n.oldNum]=n.num;a.push(v);i++;break}default:v!=="|"&&n!==2&&n!==4&&b===0&&(h.push(4),a.push({start:p,end:-1,type:4,num:i}),k.push("("),r[i]=null,i++),k.push(v),v==="\\"&&(v=f.charAt(p+1),k.push(v),p+=1)}}for(;h.length;)h.pop(),k.push(")");var f=RegExp(k.join("")),g={},d=d||m,x;for(x in d)d.hasOwnProperty(x)&&(g[x]="\\"+d[x]);f=this.getSubstitutedRegex(f,g,!1);return[f,
+m,r]},complexCaptures:function(c){if(!c)return!1;for(var d in c)if(c.hasOwnProperty(d)&&d!=="0")return!0;return!1}};n.prototype={initialize:function(c){this.textView=c;this.textView.stylerOptions=this;var d=this;this._listener={onModelChanged:function(c){d.onModelChanged(c)},onDestroy:function(c){d.onDestroy(c)},onLineStyle:function(c){d.onLineStyle(c)},onStorage:function(c){d.onStorage(c)}};c.addEventListener("ModelChanged",this._listener.onModelChanged);c.addEventListener("Destroy",this._listener.onDestroy);
+c.addEventListener("LineStyle",this._listener.onLineStyle);c.redrawLines()},onDestroy:function(){this.destroy()},destroy:function(){if(this.textView)this.textView.removeEventListener("ModelChanged",this._listener.onModelChanged),this.textView.removeEventListener("Destroy",this._listener.onDestroy),this.textView.removeEventListener("LineStyle",this._listener.onLineStyle),this.textView=null;this._listener=this._tree=this._styles=this.grammar=null},preprocess:function(c){for(c=[c];c.length!==0;){var d=
+c.pop();if(!d._resolvedRule||!d._typedRule)if(d._resolvedRule=this._resolve(d),d._typedRule=this._createTypedRule(d),this.addStyles(d.name),this.addStyles(d.contentName),this.addStylesForCaptures(d.captures),this.addStylesForCaptures(d.beginCaptures),this.addStylesForCaptures(d.endCaptures),d._resolvedRule!==d&&c.push(d._resolvedRule),d.patterns)for(var f=0;f<d.patterns.length;f++)c.push(d.patterns[f])}},addStyles:function(c){if(c&&!this._styles[c]){this._styles[c]=[];for(var d=c.split("."),f=0;f<
+d.length;f++)this._styles[c].push(d.slice(0,f+1).join("-"))}},addStylesForCaptures:function(c){for(var d in c)c.hasOwnProperty(d)&&this.addStyles(c[d].name)},ContainerRule:function(){function c(c){this.rule=c;this.subrules=c.patterns}c.prototype.valueOf=function(){return"aa"};return c}(),BeginEndRule:function(){function c(c){this.rule=c;this.beginRegex=i.toRegExp(c.begin);this.endRegex=i.toRegExp(c.end);this.subrules=c.patterns||[];this.endRegexHasBackRef=i.hasBackReference(this.endRegex);var f=i.complexCaptures(c.captures),
+c=i.complexCaptures(c.beginCaptures)||i.complexCaptures(c.endCaptures);if(this.isComplex=f||c)f=i.groupify(this.beginRegex),this.beginRegex=f[0],this.beginOld2New=f[1],this.beginConsuming=f[2],f=i.groupify(this.endRegex,this.beginOld2New),this.endRegex=f[0],this.endOld2New=f[1],this.endConsuming=f[2]}c.prototype.valueOf=function(){return this.beginRegex};return c}(),MatchRule:function(){function c(c){this.rule=c;this.matchRegex=i.toRegExp(c.match);if(this.isComplex=i.complexCaptures(c.captures))c=
+i.groupify(this.matchRegex),this.matchRegex=c[0],this.matchOld2New=c[1],this.matchConsuming=c[2]}c.prototype.valueOf=function(){return this.matchRegex};return c}(),_createTypedRule:function(c){return c.match?new this.MatchRule(c):c.begin?new this.BeginEndRule(c):new this.ContainerRule(c)},_resolve:function(c){var d=c;if(c.include){if(c.begin||c.end||c.match)throw Error('Unexpected regex pattern in "include" rule '+c.include);c=c.include;if(c.charAt(0)==="#"){if(d=this.grammar.repository&&this.grammar.repository[c.substring(1)],
+!d)throw Error("Couldn't find included rule "+c+" in grammar repository");}else if(c==="$self")d=this.grammar;else if(c==="$base")throw Error('Include "$base" is not supported');else if(d=this._allGrammars[c],!d)for(var f=0;f<this.externalGrammars.length;f++){var g=this.externalGrammars[f];if(g.scopeName===c){this.preprocess(g);d=this._allGrammars[c]=g;break}}}return d},ContainerNode:function(){function c(c,f){this.parent=c;this.rule=f;this.children=[];this.end=this.start=null}c.prototype.addChild=
+function(c){this.children.push(c)};c.prototype.valueOf=function(){var c=this.rule;return"ContainerNode { "+(c.include||"")+" "+(c.name||"")+(c.comment||"")+"}"};return c}(),BeginEndNode:function(){function c(c,f,g){this.parent=c;this.rule=f;this.children=[];this.setStart(g);this.endMatch=this.end=null;this.endRegexSubstituted=f.endRegexHasBackRef?i.getSubstitutedRegex(f.endRegex,g):null}c.prototype.addChild=function(c){this.children.push(c)};c.prototype.getIndexInParent=function(){return this.parent?
+this.parent.children.indexOf(this):-1};c.prototype.setStart=function(c){this.start=c.index;this.beginMatch=c};c.prototype.setEnd=function(c){c&&typeof c==="object"?(this.endMatch=c,this.end=c.index+c[0].length):(this.endMatch=null,this.end=c)};c.prototype.shiftStart=function(c){this.start+=c;this.beginMatch.index+=c};c.prototype.shiftEnd=function(c){this.end+=c;this.endMatch&&(this.endMatch.index+=c)};c.prototype.valueOf=function(){return"{"+this.rule.beginRegex+" range="+this.start+".."+this.end+
+"}"};return c}(),push:function(c,d){if(d)for(var f=d.length;f>0;)c.push(d[--f])},exec:function(c,d,f){(d=c.exec(d))&&(d.index+=f);c.lastIndex=0;return d},afterMatch:function(c){return c.index+c[0].length},getEndMatch:function(c,d,f){if(c instanceof this.BeginEndNode){var g=c.rule,c=c.endRegexSubstituted||g.endRegex;return!c?null:this.exec(c,d,f)}return null},initialParse:function(){this.textView.getModel().getCharCount();this._tree=new this.ContainerNode(null,this.grammar._typedRule);this.parse(this._tree,
+!1,0)},onModelChanged:function(c){var d=c.addedCharCount,f=c.removedCharCount,c=c.start;if(this._tree){var g=this.textView.getModel(),h=g.getCharCount(),g=g.getLineEnd(g.getLineAtOffset(c)-1),b=this.getFirstDamaged(g,g),g=g===-1?0:g,d=b?this.parse(b,!0,g,c,d,f):h;this.textView.redrawRange(g,d)}else this.initialParse()},getFirstDamaged:function(c,d){if(c<0)return this._tree;for(var f=[this._tree],g=null;f.length;){var h=f.pop();if(!h.parent||this.isDamaged(h,c,d)){h instanceof this.BeginEndNode&&(g=
+h);for(var b=0;b<h.children.length;b++)f.push(h.children[b])}}return g||this._tree},isDamaged:function(c,d,f){return c.start<=f&&c.end>d},parse:function(c,d,f,g,h,b){var a=this.textView.getModel(),e=a.getLineStart(a.getLineCount()-1),i=a.getCharCount(),k=this.getInitialExpected(c,f),m=-1;if(d)c.repaired=!0,c.endNeedsUpdate=!0,m=(m=c.children[c.children.length-1])?a.getLineEnd(a.getLineAtOffset(m.end+(h-b))):-1,g=a.getLineEnd(a.getLineAtOffset(g+b)),m=Math.max(m,g);for(var m=m===-1?i:m,g=k,n=c,p=!1,
+t=f,v=-1;n&&(!d||t<m);){var s=this.getNextMatch(a,n,t);s||(t=t>=e?i:a.getLineStart(a.getLineAtOffset(t)+1));var u=s&&s.match,j=s&&s.rule,w=s&&s.isEnd;if(s&&s.isSub){if(t=this.afterMatch(u),j instanceof this.BeginEndRule)p=!0,d&&j===g.rule&&n===g.parent?(n=g,n.setStart(u),n.repaired=!0,n.endNeedsUpdate=!0,g=this.getNextExpected(g,"begin")):(d&&(this.prune(n,g),d=!1),u=new this.BeginEndNode(n,j,u),n.addChild(u),n=u)}else if(w||t===i){if(n instanceof this.BeginEndNode)u?(p=!0,v=Math.max(v,n.end),n.setEnd(u),
+t=this.afterMatch(u),d&&n===g&&n.parent===g.parent?(n.repaired=!0,delete n.endNeedsUpdate,g=this.getNextExpected(g,"end")):d&&(this.prune(n,g),d=!1)):(n.setEnd(i),delete n.endNeedsUpdate);n=n.parent}d&&t>=m&&!p&&(this.prune(c,k),d=!1)}this.removeUnrepairedChildren(c,d,f);this.cleanup(d,c,f,m,i,h,b);return d?Math.max(v,t):t},removeUnrepairedChildren:function(c,d,f){if(d){for(var d=c.children,g=-1,h=0;h<d.length;h++){var b=d[h];if(!b.repaired&&this.isDamaged(b,f,Number.MAX_VALUE)){g=h;break}}if(g!==
+-1)c.children.length=g}},cleanup:function(c,d,f,g,h,b,a){if(c){c=b-a;h=this.getIntersecting(g-c+1,h);d=this.getIntersecting(f,g);for(f=0;f<h.length;f++)g=h[f],!g.repaired&&g instanceof this.BeginEndNode&&(g.shiftEnd(c),g.shiftStart(c));for(f=0;f<d.length;f++)g=d[f],g.repaired&&g.endNeedsUpdate&&g.shiftEnd(c),delete g.endNeedsUpdate,delete g.repaired}else{d=this.getIntersecting(f,g);for(f=0;f<d.length;f++)delete d[f].repaired}},getNextMatch:function(c,d,f,g){var h=c.getLineAtOffset(f),h=c.getLineEnd(h),
+b=c.getText(f,h),a=[],e=[],c=[],h=[];for(this.push(a,d.rule.subrules);a.length;){var i=a.length?a.pop():null,i=i&&i._resolvedRule._typedRule;if(i instanceof this.ContainerRule&&e.indexOf(i)===-1)e.push(i),this.push(a,i.subrules);else if(!i||!g||i.matchRegex){var k=i&&this.exec(i.matchRegex||i.beginRegex,b,f);k&&(c.push(k),h.push(i))}}a=Number.MAX_VALUE;e=-1;for(i=0;i<c.length;i++)if(k=c[i],k.index<a)a=k.index,e=i;if(!g&&(f=this.getEndMatch(d,b,f)))if(g=d.rule.applyEndPatternLast,e===-1||f.index<a||
+!g&&f.index===a)return{isEnd:!0,rule:d.rule,match:f};return e===-1?null:{isSub:!0,rule:h[e],match:c[e]}},getInitialExpected:function(c,d){var f,g;if(c===this._tree)for(f=0;f<c.children.length;f++){if(g=c.children[f],g.start>=d)return g}else if(c instanceof this.BeginEndNode&&c.endMatch){var h=c.endMatch.index;for(f=0;f<c.children.length;f++)if(g=c.children[f],g.start>=d)break;if(g&&g.start<h)return g}return c},getNextExpected:function(c,d){if(d==="begin"){var f=c.children[0];return f?f:c}else if(d===
+"end"&&(f=c.parent)){var g=f.children[f.children.indexOf(c)+1];return g?g:f}return null},prune:function(c,d){if(d.parent===c)c.children.length=d.getIndexInParent();else if(c instanceof this.BeginEndNode)c.endMatch=null,c.end=null;if(c.parent)c.parent.children.length=c.getIndexInParent()+1},onLineStyle:function(c){this._tree||this.initialParse();var d=c.lineStart,f=this.textView.getModel(),g=f.getLineEnd(c.lineIndex),h=f.getLineEnd(f.getLineAtOffset(d)-1),h=this.getFirstDamaged(h,h),d=this.getLineScope(f,
+h,d,g);c.ranges=this.toStyleRanges(d);c.ranges.sort(function(b,a){return b.start-a.start})},getLineScope:function(c,d,f,g){for(var h=f,b=this.getInitialExpected(d,f),a=[],e=[];d&&h<g;){var i=this.getNextMatch(c,d,h);if(!i)break;var k=i&&i.match,m=i&&i.rule,n=i&&i.isSub,i=i&&i.isEnd;k.index!==h&&e.push({start:h,end:k.index,node:d});if(n)h=this.afterMatch(k),m instanceof this.BeginEndRule?(this.addBeginScope(a,k,m),d=b,b=this.getNextExpected(b,"begin")):this.addMatchScope(a,k,m);else if(i)h=this.afterMatch(k),
+this.addEndScope(a,k,m),b=this.getNextExpected(b,"end"),d=d.parent}h<g&&e.push({start:h,end:g,node:d});c=this.getInheritedLineScope(e,f,g);return a.concat(c)},getInheritedLineScope:function(c){for(var d=[],f=0;f<c.length;f++)for(var g=c[f],h=g.node;h;){var b=h.rule.rule,a=b.name;if(b=b.contentName||a){this.addScopeRange(d,g.start,g.end,b);break}h=h.parent}return d},addBeginScope:function(c,d,f){var g=f.rule;this.addCapturesScope(c,d,g.beginCaptures||g.captures,f.isComplex,f.beginOld2New,f.beginConsuming)},
+addEndScope:function(c,d,f){var g=f.rule;this.addCapturesScope(c,d,g.endCaptures||g.captures,f.isComplex,f.endOld2New,f.endConsuming)},addMatchScope:function(c,d,f){var g=f.rule,h=g.name;(g=g.captures)?this.addCapturesScope(c,d,g,f.isComplex,f.matchOld2New,f.matchConsuming):this.addScope(c,d,h)},addScope:function(c,d,f){f&&c.push({start:d.index,end:this.afterMatch(d),scope:f})},addScopeRange:function(c,d,f,g){g&&c.push({start:d,end:f,scope:g})},addCapturesScope:function(c,d,f,g,h,b){if(f)if(g){for(var g=
+{1:0},a=0,e=1;d[e]!==void 0;e++)b[e]!==void 0&&(a+=d[e].length),d[e+1]!==void 0&&(g[e+1]=a);b=d.index;for(a=1;f[a];a++){var e=f[a].name,i=h[a],k=b+g[i];typeof d[i]!=="undefined"&&this.addScopeRange(c,k,k+d[i].length,e)}}else this.addScope(c,d,f[0]&&f[0].name)},getIntersecting:function(c,d){for(var f=[],g=this._tree?[this._tree]:[];g.length;){var h=g.pop(),b=!1;h instanceof this.ContainerNode?b=!0:this.isDamaged(h,c,d)&&(b=!0,f.push(h));if(b)for(var b=h.children.length,a=0;a<b;a++)g.push(h.children[a])}return f.reverse()},
+toStyleRanges:function(c){for(var d=[],f=0;f<c.length;f++){var g=c[f],h=this._styles[g.scope];if(!h)throw Error("styles not found for "+g.scope);h=h.join(" ");d.push({start:g.start,end:g.end,style:{styleClass:h}})}return d}};return{RegexUtil:i,TextMateStyler:n}});
+define("orion/editor/htmlGrammar",[],function(){return{HtmlGrammar:function(){return{scopeName:"source.html",uuid:"3B5C76FB-EBB5-D930-F40C-047D082CE99B",patterns:[{begin:"<!(doctype|DOCTYPE)",end:">",contentName:"entity.name.tag.doctype.html",beginCaptures:{0:{name:"entity.name.tag.doctype.html"}},endCaptures:{0:{name:"entity.name.tag.doctype.html"}}},{begin:"<\!--",end:"--\>",beginCaptures:{0:{name:"punctuation.definition.comment.html"}},endCaptures:{0:{name:"punctuation.definition.comment.html"}},
+patterns:[{match:"--",name:"invalid.illegal.badcomment.html"}],contentName:"comment.block.html"},{match:"<[A-Za-z0-9_\\-:]+(?= ?)",name:"entity.name.tag.html"},{include:"#attrName"},{include:"#qString"},{include:"#qqString"},{include:"#entity"},{match:"</[A-Za-z0-9_\\-:]+>",name:"entity.name.tag.html"},{match:">",name:"entity.name.tag.html"}],repository:{attrName:{match:"[A-Za-z\\-:]+(?=\\s*=\\s*['\"])",name:"entity.other.attribute.name.html"},qqString:{match:'(")[^"]+(")',name:"string.quoted.double.html"},
+qString:{match:"(')[^']+(')",name:"string.quoted.single.html"},entity:{match:"&[A-Za-z0-9]+;",name:"constant.character.entity.html"}}}}}});
+define("orion/editor/textStyler",["orion/editor/annotations"],function(k){function m(a,b){this._unnamedCounter=0;this._patterns=[];this._rootId=b;a.forEach(function(a){this._addRepositoryPatterns(a.repository||{},a.id);this._addPatterns(a.patterns||[],a.id)}.bind(this))}function n(a,b,c,d,e){this.start=a.start;this.end=a.end;this.contentStart=a.contentStart;this.contentEnd=a.contentEnd;this.pattern=b;this._styler=c;this._parent=e;this._linePatterns=[];this._blockPatterns=[];this._enclosurePatterns=
+{};if(d)this._initPatterns(),this._subBlocks=t(d,d.getText(this.start,this.end),this,this.start)}function i(a){this._styler=a}function c(a,b,c,d){this.highlightCaretLine=this.whitespacesVisible=this.spacesVisible=this.tabsVisible=!1;this.detectTasks=this.foldingEnabled=!0;this.view=a;this.annotationModel=b;this.patternManager=new m(c,d);this._accessor=new i(this);this._bracketAnnotations=void 0;var e=this;this._listener={onChanged:function(a){e._onModelChanged(a)},onDestroy:function(a){e._onDestroy(a)},
+onLineStyle:function(a){e._onLineStyle(a)},onMouseDown:function(a){e._onMouseDown(a)},onSelection:function(a){e._onSelection(a)}};c=a.getModel();c.getBaseModel&&(c=c.getBaseModel());c.addEventListener("Changed",this._listener.onChanged);a.addEventListener("MouseDown",this._listener.onMouseDown);a.addEventListener("Selection",this._listener.onSelection);a.addEventListener("Destroy",this._listener.onDestroy);a.addEventListener("LineStyle",this._listener.onLineStyle);d=c.getCharCount();this._rootBlock=
+new n({start:0,contentStart:0,end:d,contentEnd:d},null,this,c);this._computeFolding(this._rootBlock.getBlocks());b&&this.detectTasks&&(d=[],v(this._rootBlock,c,d),b.replaceAnnotations([],d));a.redrawLines()}var d={styleClass:"meta annotation currentLine"},f=/$/,g=/\\(\d)/g,h=/(.*)(?:[\r\n]|$)/g,b={regex:/ /g,style:{styleClass:"punctuation separator space",unmergeable:!0}},a={regex:/\t/g,style:{styleClass:"punctuation separator tab",unmergeable:!0}},e=function(a,b,c,d){var e=c,f=a.lastIndex;h.lastIndex=
+c;var c=h.exec(b),g,i;a.lastIndex=0;if(c){for(i=c.index;0<=--i;)if(g=b.charAt(i),g==="\n"||g==="\r")break;g=b.substring(i+1,c.index+c[1].length);a.lastIndex=i=c.index-i-1}for(;c&&c.index<b.length;){var k;if(d){var l=a.lastIndex;if(a.test(g))a.lastIndex=l,k=a.exec(g)}else k=a.exec(g);if(k)return k.index+=e,k.index-=i,a.lastIndex=f,k;i=0;e+=c[0].length;if(c=h.exec(b))g=c[1],a.lastIndex=0}a.lastIndex=f;return null},l=function(a,b){var c=a.toString();g.lastIndex=0;if(!g.test(c))return a;g.lastIndex=0;
+for(var d=g.exec(c);d;)c=c.replace(d[0],b[d[1]]||""),g.lastIndex=0,d=g.exec(c);return RegExp(c.substring(1,c.length-2),"g")},o=function(a,b,c,d){if(b=e(a.pattern.regex?a.pattern.regex:a.pattern.regexBegin,b,d,!0)){a.result=b;for(d=0;d<c.length;d++)if(b.index<c[d].result.index||b.index===c[d].result.index&&a.pattern.pattern.index<c[d].pattern.pattern.index){c.splice(d,0,a);return}c.push(a)}},q=function(a,b,c,d){if(b[0])d.push({start:c,end:c+a[0].length,style:b[0].name});else for(var e=0,f=1;f<a.length;f++)if(a[f]){var g=
+b[f];if(g){var i=c+e;d.push({start:i,end:i+a[f].length,style:g.name})}e+=a[f].length}},r=function(a,b,c){var d=a.start;b.forEach(function(b){d<=b.start&&c.push({start:d,end:b.start,style:a.style});c.push(b);d=b.end});d<a.end&&c.push({start:d,end:a.end,style:a.style})},p=function(a,b,c,d,g){if(c=c.getLinePatterns()){var i=[];c.forEach(function(b){var c=b.regex||b.regexBegin;c.oldLastIndex=c.lastIndex;(c=e(c,a,0))&&i.push({result:c,pattern:b})});i.sort(function(a,b){return a.result.index<b.result.index?
+-1:a.result.index>b.result.index?1:a.pattern.pattern.index<b.pattern.pattern.index?-1:1});for(var h=0;i.length>0;){var k=i[0];i.splice(0,1);if(!(k.result.index<h)){var m=k.result.index,p,n=[];if(k.pattern.regex){h=k.result;p=m+h[0].length;p={start:b+m,end:b+p,style:k.pattern.pattern.name};if(!g){k.pattern.pattern.captures&&q(h,k.pattern.pattern.captures,b+m,n);n.sort(function(a,b){return a.start<b.start?-1:a.start>b.start?1:0});for(m=0;m<n.length-1;m++)if(n[m+1].start<n[m].end){var t={start:n[m+1].end,
+end:n[m].end,style:n[m].style};n[m].end=n[m+1].start;n.splice(m+2,0,t)}}r(p,n,d)}else{h=k.pattern.regexEnd;h=l(h,k.result);h=e(h,a,k.result.index+k.result[0].length);if(!h)f.lastIndex=0,h=f.exec(a);p=h.index+h[0].length;d.push({start:b+m,end:b+p,style:k.pattern.pattern.name})}h=h.index+h[0].length}o(k,a,i,h)}c.forEach(function(a){a=a.regex||a.regexBegin;a.lastIndex=a.oldLastIndex})}},t=function(a,b,c,d){var g=[];c.getBlockPatterns().forEach(function(a){var c=e(a.regexBegin||a.regex,b,0);c&&g.push({result:c,
+pattern:a})}.bind(this));if(!g.length)return g;g.sort(function(a,b){return a.result.index<b.result.index?-1:a.result.index>b.result.index?1:a.pattern.pattern.index<b.pattern.pattern.index?-1:1});for(var h=0,i=[];g.length>0;){var k=g[0];g.splice(0,1);if(!(k.result.index<h)){var m=a.getLineAtOffset(d+k.result.index),q=a.getLine(m),r=[];p(q,a.getLineStart(m),c,r);m=d+k.result.index;for(q=0;q<r.length;q++)if(r[q].start===m){var h=k.result.index,t=null,v=k.pattern.regexEnd;if(v){h+=k.result[0].length;
+for(var v=l(v,k.result),B=h;!t;){B=e(v,b,B);if(!B)f.lastIndex=0,B=f.exec(b);var E=[],G=new n({start:m,end:d+B.index+B[0].length,contentStart:d+h,contentEnd:d+B.index},k.pattern,c.getStyler(),a,c);p(b.substring(h,B.index+B[0].length),h,G,E);if(!E.length||E[E.length-1].end<=B.index)t=G;B=B.index+B[0].length}}else t=new n({start:m,end:m+k.result[0].length,contentStart:m,contentEnd:m+k.result[0].length},k.pattern,c.getStyler(),a,c);i.push(t);h=t.end-d;break}q===r.length&&(h=k.result.index+1)}o(k,b,g,
+h)}return i},v=function(a,b,c){if(a.getAnnotationModel()){var d=k.AnnotationType.ANNOTATION_TASK;if(a.getLinePatterns().length&&a.pattern&&a.pattern.pattern.name&&a.pattern.pattern.name.indexOf("comment")===0){var e=[];p(b.getText(a.contentStart,a.end),a.contentStart,a,e,!0);for(var f=0;f<e.length;f++)e[f].style==="meta.annotation.task.todo"&&c.push(k.AnnotationType.createAnnotation(d,e[f].start,e[f].end,b.getText(e[f].start,e[f].end)))}a.getBlocks().forEach(function(a){v(a,b,c)}.bind(this))}};m.prototype=
+{getPatterns:function(a){var b=[0],c={},d=RegExp("^"+(a?typeof a==="string"?a:a.qualifiedId:this._rootId)+"#[^#]+$"),e=[];this._patterns.forEach(function(a){if(d.test(a.qualifiedId))a.include?e.push(a):(a.index=b[0]++,c[a.id]=a)}.bind(this));e.forEach(function(a){this._processInclude(a,b,c)}.bind(this));var f=[];Object.keys(c).forEach(function(a){f.push(c[a])});return f},_addPatterns:function(a,b){a.forEach(function(a){this._addPattern(a,this._NO_ID+this._unnamedCounter++,b)}.bind(this))},_addRepositoryPatterns:function(a,
+b){Object.keys(a).forEach(function(c){this._addPattern(a[c],c,b)}.bind(this))},_addPattern:function(a,b,c){a.parentId=c;a.id=b;a.qualifiedId=a.parentId+"#"+a.id;this._patterns.push(a);a.patterns&&!a.include&&this._addPatterns(a.patterns,a.qualifiedId)},_processInclude:function(a,b,c){var d,e=a.include.indexOf("#");d=e===0?RegExp("^"+a.qualifiedId.substring(0,a.qualifiedId.indexOf("#"))+a.include+"$"):e===-1?RegExp("^"+a.include+"#"+this._NO_ID+"[^#]+$"):RegExp("^"+a.include+"$");var f=[];this._patterns.forEach(function(a){if(d.test(a.qualifiedId))if(a.include)f.push(a);
+else if(!c[a.id])a.index=b[0]++,c[a.id]=a}.bind(this));f.forEach(function(a){this._processInclude(a,b,c)}.bind(this))},_NO_ID:"NoID"};n.prototype={adjustEnd:function(a){this.end+=a;this.contentEnd+=a;this._subBlocks.forEach(function(b){b.adjustEnd(a)})},adjustStart:function(a){this.start+=a;this.contentStart+=a;this._subBlocks.forEach(function(b){b.adjustStart(a)})},computeStyle:function(a,b){if(!this.pattern||!(this.start<=b&&b<this.end))return null;var c={start:this.start,end:this.end,style:this.pattern.pattern.name};
+if(this.contentStart<=b&&b<this.contentEnd)return this.pattern.pattern.contentName?{start:this.contentStart,end:this.contentEnd,style:this.pattern.pattern.contentName}:c;var d,e,f,g;if(b<this.contentStart){e=this.pattern.pattern.beginCaptures||this.pattern.pattern.captures;if(!e)return c;d=this.pattern.regexBegin;f=a.getText(this.start,this.contentStart);g=this.start}else{e=this.pattern.pattern.endCaptures||this.pattern.pattern.captures;if(!e)return c;d=this.pattern.regexEnd;f=a.getText(this.contentEnd,
+this.end);g=this.contentEnd}d.lastIndex=0;if(f=d.exec(f)){d=[];q(f,e,g,d);for(e=0;e<d.length;e++)if(d[e].start<=b&&b<d[e].end)return d[e]}return c},getAnnotationModel:function(){return this._styler._getAnnotationModel()},getBlockPatterns:function(){return this._blockPatterns},getBlocks:function(){return this._subBlocks},getEnclosurePatterns:function(){return this._enclosurePatterns},getLinePatterns:function(){return this._linePatterns},getParent:function(){return this._parent},getPatternManager:function(){return this._styler._getPatternManager()},
+getStyler:function(){return this._styler},isRenderingWhitespace:function(){return this._styler._isRenderingWhitespace()},_initPatterns:function(){var a=function(a){var b=/^\(\?i\)\s*/.exec(a);b&&(a=a.substring(b[0].length));return a};this.getPatternManager().getPatterns(this.pattern?this.pattern.pattern:null).forEach(function(b){var c;if(b.match&&!b.begin&&!b.end){c="g";var d=a(b.match);d!==b.match&&(c+="i");c={regex:RegExp(d,c),pattern:b};this._linePatterns.push(c);if(b.patterns)this._blockPatterns.push(c);
+else if(b.name&&b.name.indexOf("punctuation.section")===0&&(b.name.indexOf(".begin")!==-1||b.name.indexOf(".end")!==-1))this._enclosurePatterns[b.name]=c}else if(!b.match&&b.begin&&b.end){c="g";d=a(b.begin);d!==b.begin&&(c+="i");var e="g",f=a(b.end);f!==b.end&&(e+="i");c={regexBegin:RegExp(d,c),regexEnd:RegExp(f,e),pattern:b};this._linePatterns.push(c);this._blockPatterns.push(c)}}.bind(this))}};i.prototype={getStyles:function(a){return this._styler.getStyles(a)}};c.prototype={destroy:function(){var a=
+this.view;if(a){var b=a.getModel();b.getBaseModel&&(b=b.getBaseModel());b.removeEventListener("Changed",this._listener.onChanged);a.removeEventListener("MouseDown",this._listener.onMouseDown);a.removeEventListener("Selection",this._listener.onSelection);a.removeEventListener("Destroy",this._listener.onDestroy);a.removeEventListener("LineStyle",this._listener.onLineStyle);this.view=null}},getStyleAccessor:function(){return this._accessor},getStyles:function(a){var b=[],c=this.view.getModel();c.getBaseModel&&
+(c=c.getBaseModel());var d=this._findBlock(this._rootBlock,a),e=c.getLineAtOffset(a),f=c.getLine(e),g=[];p(f,c.getLineStart(e),d,g);for(e=0;e<g.length;e++){if(a<g[e].start)break;if(g[e].start<=a&&a<g[e].end){b.push(g[e]);break}}for(;d;)(g=d.computeStyle(c,a))&&b.splice(0,0,g),d=d.getParent();return b},setHighlightCaretLine:function(a){this.highlightCaretLine=a},setWhitespacesVisible:function(a,b){if(this.whitespacesVisible!==a)this.whitespacesVisible=a,b&&this.view.redraw()},setTabsVisible:function(a){if(this.tabsVisible!==
+a)this.tabsVisible=a,this.setWhitespacesVisible(this.tabsVisible||this.spacesVisible,!1),this.view.redraw()},setSpacesVisible:function(a){if(this.spacesVisible!==a)this.spacesVisible=a,this.setWhitespacesVisible(this.tabsVisible||this.spacesVisible,!1),this.view.redraw()},setDetectHyperlinks:function(){},setFoldingEnabled:function(a){this.foldingEnabled=a},setDetectTasks:function(a){this.detectTasks=a},_binarySearch:function(a,b,c,d,e){var f;d===void 0&&(d=-1);if(e===void 0)e=a.length;for(;e-d>1;)if(f=
+Math.floor((e+d)/2),b<=a[f].start)e=f;else if(c&&b<a[f].end){e=f;break}else d=f;return e},_computeFolding:function(a){if(this.foldingEnabled){var b=this.view.getModel();if(b.getBaseModel){var c=this.annotationModel;if(c){c.removeAnnotations(k.AnnotationType.ANNOTATION_FOLDING);for(var d=[],e=b.getBaseModel(),f=0;f<a.length;f++){var g=a[f];(g=this._createFoldingAnnotation(b,e,g.start,g.end))&&d.push(g)}c.replaceAnnotations(null,d)}}}},_createFoldingAnnotation:function(a,b,c,d){var e=b.getLineAtOffset(c),
+b=b.getLineAtOffset(d);return e===b?null:new (k.AnnotationType.getType(k.AnnotationType.ANNOTATION_FOLDING))(c,d,a)},_findBlock:function(a,b){var c=a.getBlocks();if(!c.length)return a;var d=this._binarySearch(c,b,!0);return d<c.length&&c[d].start<=b&&b<c[d].end?this._findBlock(c[d],b):a},_findBrackets:function(a,b,c,d,e,f){for(var g=[],h=[],i=e,k=c.getBlocks(),l=this._binarySearch(k,e,!0);l<k.length;l++){if(k[l].start>=f)break;var m=k[l].start,n=k[l].end;i<m&&(p(d.substring(i-e,m-e),i,c,h),h.forEach(function(c){c.style.indexOf(a.pattern.name)===
+0?g.push(c.start+1):c.style.indexOf(b.pattern.name)===0&&g.push(-(c.start+1))}),h=[]);i=n}i<f&&(p(d.substring(i-e,f-e),i,c,h),h.forEach(function(c){c.style.indexOf(a.pattern.name)===0?g.push(c.start+1):c.style.indexOf(b.pattern.name)===0&&g.push(-(c.start+1))}));return g},_findMatchingBracket:function(a,b,c){for(var d=a.getLineAtOffset(c),f=a.getLineEnd(d),g=a.getText(c,f),h,i=b.getEnclosurePatterns(),k=Object.keys(i),l=0;l<k.length;l++){var m=i[k[l]],n=e(m.regex,g,0);if(n&&n.index===0){h=m;break}}if(!h)return-1;
+g=!1;h.pattern.name.indexOf(".begin")!==-1?(g=!0,l=h.pattern.name.replace(".begin",".end")):l=h.pattern.name.replace(".end",".begin");i=i[l];if(!i)return-1;k=a.getLine(d);m=a.getLineStart(d);f=this._findBrackets(h,i,b,k,m,f);for(l=0;l<f.length;l++)if(k=f[l]>=0?1:-1,f[l]*k-1===c){c=1;if(g){for(l++;l<f.length;l++)if(k=f[l]>=0?1:-1,c+=k,c===0)return f[l]*k-1;d+=1;for(l=a.getLineCount();d<l;){k=a.getLine(d);m=a.getLineStart(d);f=a.getLineEnd(d);f=this._findBrackets(h,i,b,k,m,f);for(g=0;g<f.length;g++)if(k=
+f[g]>=0?1:-1,c+=k,c===0)return f[g]*k-1;d++}}else{for(l--;l>=0;l--)if(k=f[l]>=0?1:-1,c+=k,c===0)return f[l]*k-1;for(d-=1;d>=0;){k=a.getLine(d);m=a.getLineStart(d);f=a.getLineEnd(d);f=this._findBrackets(h,i,b,k,m,f);for(l=f.length-1;l>=0;l--)if(k=f[l]>=0?1:-1,c+=k,c===0)return f[l]*k-1;d--}}break}return-1},_getAnnotationModel:function(){return this.annotationModel},_getLineStyle:function(a){if(this.highlightCaretLine){var b=this.view,c=b.getModel(),b=b.getSelection();if(b.start===b.end&&c.getLineAtOffset(b.start)===
+a)return d}return null},_getPatternManager:function(){return this.patternManager},_getStyles:function(a,b,c,d){b.getBaseModel&&(d=b.mapOffset(d));for(var f=d+c.length,g=[],h=d,i=a.getBlocks(),k=this._binarySearch(i,d,!0);k<i.length;k++){if(i[k].start>=f)break;var l=i[k].start,m=i[k].end;h<l&&p(c.substring(h-d,l-d),h,a,g);var n=Math.max(h,l);if(n===l&&i[k].pattern.regexBegin){var o=e(i[k].pattern.regexBegin,c.substring(n-d),0);if(o){var r=i[k].pattern.pattern.beginCaptures||i[k].pattern.pattern.captures;
+r?q(o,r,n,g):g.push({start:n,end:n+o[0].length,style:i[k].pattern.pattern.name});n+=o[0].length}}var l=Math.min(f,m),t=[];if(l===m&&i[k].pattern.regexEnd&&(h=c.substring(l-h-(i[k].end-i[k].contentEnd)),o=e(i[k].pattern.regexEnd,h,0)))(r=i[k].pattern.pattern.endCaptures||i[k].pattern.pattern.captures)?q(o,r,l-o[0].length,t):i[k].pattern.pattern.name&&t.push({start:l-o[0].length,end:l,style:i[k].pattern.pattern.name}),l-=o[0].length;var h=this._getStyles(i[k],b,c.substring(n-d,l-d),n),v=i[k].pattern.pattern.contentName||
+i[k].pattern.pattern.name;if(v){var H=n;h.forEach(function(a){a.start-H&&g.push({start:H,end:a.start,style:v});g.push(a);H=a.end});l-H&&g.push({start:H,end:l,style:v})}else g=g.concat(h);g=g.concat(t);h=m}h<f&&p(c.substring(h-d,f-d),h,a,g);if(b.getBaseModel)for(a=0;a<g.length;a++)c=g[a].end-g[a].start,g[a].start=b.mapOffset(g[a].start,!0),g[a].end=g[a].start+c;return g},_isRenderingWhitespace:function(){return this.whitespacesVisible&&(this.tabsVisible||this.spacesVisible)},_onDestroy:function(){this.destroy()},
+_onLineStyle:function(c){if(c.textView===this.view)c.style=this._getLineStyle(c.lineIndex);c.ranges=this._getStyles(this._rootBlock,c.textView.getModel(),c.lineText,c.lineStart);c.ranges.forEach(function(a){if(a.style)a.style={styleClass:a.style.replace(/\./g," ")}});this._isRenderingWhitespace()&&(this.spacesVisible&&this._spliceStyles(b,c.ranges,c.lineText,c.lineStart),this.tabsVisible&&this._spliceStyles(a,c.ranges,c.lineText,c.lineStart))},_onSelection:function(a){var b=a.oldValue,c=a.newValue,
+d=this.view,a=d.getModel(),e;if(this.highlightCaretLine){var f=a.getLineAtOffset(b.start);e=a.getLineAtOffset(c.start);var g=c.start===c.end,b=b.start===b.end;f===e&&b&&g||(b&&d.redrawLines(f,f+1),(f!==e||!b)&&g&&d.redrawLines(e,e+1))}if(this.annotationModel){var b=this._bracketAnnotations,h,i;if(c.start===c.end&&(i=d.getCaretOffset())>0)i-=1,a.getBaseModel&&(i=a.mapOffset(i),a=a.getBaseModel()),c=this._findBlock(this._rootBlock,i),a=this._findMatchingBracket(a,c,i),a!==-1&&(h=[k.AnnotationType.createAnnotation(k.AnnotationType.ANNOTATION_MATCHING_BRACKET,
+a,a+1),k.AnnotationType.createAnnotation(k.AnnotationType.ANNOTATION_CURRENT_BRACKET,i,i+1)]);this._bracketAnnotations=h;this.annotationModel.replaceAnnotations(b,h)}},_onMouseDown:function(a){if(a.clickCount===2){var b=this.view,c=b.getModel(),d=b.getOffsetAtLocation(a.x,a.y);if(d>0){var e=d-1,f=c;c.getBaseModel&&(e=c.mapOffset(e),f=c.getBaseModel());var g=this._findBlock(this._rootBlock,e),e=this._findMatchingBracket(f,g,e);e!==-1&&(a.preventDefault(),a=e,c.getBaseModel&&(a=c.mapOffset(a,!0)),d>
+a&&(d--,a++),b.setSelection(a,d))}}},_onModelChanged:function(a){var b=a.start,c=a.removedCharCount,a=a.addedCharCount-c,d=this.view,e=d.getModel(),f=e.getBaseModel?e.getBaseModel():e,c=b+c,g=f.getCharCount(),i=this._rootBlock.getBlocks(),h=i.length,l=f.getLineStart(f.getLineAtOffset(b)),m=this._binarySearch(i,l,!0),n=this._binarySearch(i,c,!1,m-1,h),o;m<h&&i[m].start<=l&&l<i[m].end?(o=i[m].start,o>b&&(o+=a)):o=m===h&&h>0&&g-a===i[h-1].end?i[h-1].start:l;var p;do n<h?(p=i[n].end,p>b&&(p+=a),n+=1):
+(n=h,p=g),l=f.getText(o,p),l=t(f,l,this._rootBlock,o);while(l.length&&i.length&&n<h&&l[l.length-1].pattern.pattern.id!==i[n-1].pattern.pattern.id);for(g=m;g<i.length;g++)h=i[g],h.start>b&&h.adjustStart(a),h.start>b&&h.adjustEnd(a);var q=n-m!==l.length;if(!q)for(g=0;g<l.length;g++){var h=i[m+g],r=l[g];if(h.start!==r.start||h.end!==r.end||h.type!==r.type){q=!0;break}}g=[m,n-m].concat(l);Array.prototype.splice.apply(i,g);q&&(g=o,h=p,e!==f&&(g=e.mapOffset(g,!0),h=e.mapOffset(h,!0)),d.redrawRange(g,h));
+if(this.annotationModel){d=[];i=[];m=[];o=this.annotationModel.getAnnotations(o,p);for(p=this.foldingEnabled&&f!==e;o.hasNext();)if(h=o.next(),p&&h.type===k.AnnotationType.ANNOTATION_FOLDING){m.push(h);for(g=0;g<l.length;g++)if(h.start===l[g].start&&h.end===l[g].end)break;g===l.length?(d.push(h),h.expand()):(g=h.start,n=h.end,g>b&&(g-=a),n>b&&(n-=a),g<=b&&b<n&&g<=c&&c<n&&(g=f.getLineAtOffset(h.start),n=f.getLineAtOffset(h.end),g!==n?h.expanded||h.expand():this.annotationModel.removeAnnotation(h)));
+for(g=0;g<l.length;g++){h=l[g];for(n=0;n<m.length;n++)if(m[n].start===h.start&&m[n].end===h.end)break;n===m.length&&(h=this._createFoldingAnnotation(e,f,h.start,h.end))&&i.push(h)}}else h.type===k.AnnotationType.ANNOTATION_TASK&&d.push(h);if(this.detectTasks)for(g=0;g<l.length;g++)v(l[g],f,i);this.annotationModel.replaceAnnotations(d,i)}},_spliceStyles:function(a,b,c,d){for(var e=a.regex,f=e.lastIndex=0,g=e.exec(c);g;){for(g=d+g.index;f<b.length;){if(g<b[f].end)break;f++}var h={start:g,end:g+1,style:a.style};
+if(f<b.length&&b[f].start<=g){var i={start:g+1,end:b[f].end,style:b[f].style};b[f].end=g;b.splice(f+1,0,i);b.splice(f+1,0,h);f+=2}else b.splice(f,0,h),f++;g=e.exec(c)}}};return{TextStyler:c}});
+define("orion/editor/stylers/text_x-php/syntax",["orion/editor/stylers/lib/syntax"],function(k){var m="abstract,and,array,as,break,callable,case,catch,class,clone,const,continue,declare,default,die,do,echo,else,elseif,empty,enddeclare,endfor,endforeach,endif,endswitch,endwhile,eval,exit,extends,false,FALSE,final,finally,for,foreach,function,global,goto,if,implements,include,include_once,insteadof,interface,instanceof,isset,list,namespace,new,null,NULL,or,parent,print,private,protected,public,require,require_once,return,self,static,switch,throw,trait,try,true,TRUE,unset,use,var,while,xor,yield,__halt_compiler,__CLASS__,__DIR__,__FILE__,__FUNCTION__,__LINE__,__METHOD__,__NAMESPACE__,__TRAIT__".split(","),k=
+k.grammars;k.push({id:"orion.php",contentTypes:["text/x-php"],patterns:[{include:"orion.lib#doc_block"},{include:"orion.c-like"},{match:"(?i)<\\?(?:=|php)?(?:\\s|$)",name:"entity.name.declaration.php"},{match:"<%=?(?:\\s|$)",name:"entity.name.declaration.php"},{match:"#.*",name:"comment.line.number-sign.php",patterns:[{include:"orion.lib#todo_comment_singleLine"}]},{begin:"<<<(\\w+)$",end:"^\\1;$",name:"string.unquoted.heredoc.php"},{begin:"<<<'(\\w+)'$",end:"^\\1;$",name:"string.unquoted.heredoc.nowdoc.php"},
+{match:"\\b0[bB][01]+\\b",name:"constant.numeric.binary.php"},{match:"\\b(?:"+m.join("|")+")\\b",name:"keyword.control.php"}]});return{id:"orion.php",grammars:k,keywords:m}});
+define("orion/editor/stylers/application_xml/syntax",["orion/editor/stylers/lib/syntax"],function(k){k=k.grammars;k.push({id:"orion.xml",contentTypes:["application/xml","application/xhtml+xml"],patterns:[{include:"#comment"},{include:"#xmlDeclaration"},{begin:"<!(?:doctype|DOCTYPE)",end:">",captures:{0:{name:"entity.name.tag.doctype.xml"}},patterns:[{include:"#comment"},{include:"orion.lib#string_doubleQuote"},{include:"orion.lib#string_singleQuote"}],name:"meta.tag.doctype.xml"},{begin:"</?[A-Za-z0-9]+",
+end:"/?>",captures:{0:{name:"entity.name.tag.xml"}},name:"meta.tag.xml",patterns:[{include:"#comment"},{include:"orion.lib#string_doubleQuote"},{include:"orion.lib#string_singleQuote"}]},{match:"&lt;|&gt;|&amp;",name:"constant.character"}],repository:{comment:{begin:"<\!--",end:"--\>",name:"comment.block.xml",patterns:[{match:"(\\b)(TODO)(\\b)(((?!--\>).)*)",name:"meta.annotation.task.todo",captures:{2:{name:"keyword.other.documentation.task"},4:{name:"comment.line"}}}]},xmlDeclaration:{begin:"<\\?xml",
+end:"\\?>",captures:{0:{name:"entity.name.tag.declaration.xml"}},patterns:[{include:"#comment"},{include:"orion.lib#string_doubleQuote"},{include:"orion.lib#string_singleQuote"}],name:"meta.tag.declaration.xml"}}});return{id:k[k.length-1].id,grammars:k,keywords:[]}});
+define("orion/editor/stylers/text_html/syntax",["orion/editor/stylers/lib/syntax","orion/editor/stylers/application_javascript/syntax","orion/editor/stylers/text_css/syntax","orion/editor/stylers/text_x-php/syntax","orion/editor/stylers/application_xml/syntax"],function(k,m,n,i,c){k=k.grammars.concat(m.grammars).concat(n.grammars).concat(i.grammars).concat(c.grammars);k.push({id:"orion.html",contentTypes:["text/html"],patterns:[{include:"orion.xml"},{begin:"(?i)(<style)([^>]*)(>)",end:"(?i)(</style>)",
+captures:{1:{name:"entity.name.tag.html"},3:{name:"entity.name.tag.html"}},contentName:"source.css.embedded.html",patterns:[{include:"orion.css"}]},{begin:"(?i)<script\\s*>|<script\\s.*?(?:language\\s*=\\s*(['\"])javascript\\1|type\\s*=\\s*(['\"])(?:text|application)/(?:javascript|ecmascript)\\2).*?>",end:"(?i)<\/script>",captures:{0:{name:"entity.name.tag.html"}},contentName:"source.js.embedded.html",patterns:[{include:"orion.js"}]},{begin:"(?i)<script\\s.*?(?:language\\s*=\\s*(['\"])php\\1|type\\s*=\\s*(['\"])text/x-php\\2).*?>",
+end:"(?i)<\/script>",captures:{0:{name:"entity.name.tag.html"}},contentName:"source.php.embedded.html",patterns:[{include:"orion.php"}]},{begin:"(?i)<\\?(?:=|php)?(?:\\s|$)",end:"\\?>",captures:{0:{name:"entity.name.declaration.php"}},contentName:"source.php.embedded.html",patterns:[{include:"orion.php"}]},{begin:"<%=?(?:\\s|$)",end:"%>",captures:{0:{name:"entity.name.declaration.php"}},contentName:"source.php.embedded.html",patterns:[{include:"orion.php"}]}],repository:{xmlDeclaration:{}}});return{id:k[k.length-
+1].id,grammars:k,keywords:[]}});
+define("orion/editor/edit","require,orion/editor/shim,orion/editor/textView,orion/editor/textModel,orion/editor/textTheme,orion/editor/projectionTextModel,orion/editor/eventTarget,orion/keyBinding,orion/editor/rulers,orion/editor/annotations,orion/editor/tooltip,orion/editor/undoStack,orion/editor/textDND,orion/editor/editor,orion/editor/editorFeatures,orion/editor/contentAssist,orion/editor/cssContentAssist,orion/editor/htmlContentAssist,orion/editor/jsTemplateContentAssist,orion/editor/AsyncStyler,orion/editor/mirror,orion/editor/textMateStyler,orion/editor/htmlGrammar,orion/editor/textStyler,orion/editor/stylers/application_javascript/syntax,orion/editor/stylers/text_css/syntax,orion/editor/stylers/text_html/syntax".split(","),function(k,
+m,n,i,c,d,f,g,h,b,a,e,l,o,q,r,p,t,v,s,u,j,w,x,D,y,K){function O(a){var b=a.firstChild;if(b&&b.tagName==="TEXTAREA")return b.value;var c=a.ownerDocument,d=c.defaultView||c.parentWindow,e;if(!(e=!d.getSelection)){if(!(b=a.childNodes.length===1&&b.nodeType===Node.TEXT_NODE)){for(var f,b=a;b&&b!==c&&f!=="none";)f=d.getComputedStyle?d.getComputedStyle(b,null).getPropertyValue("display"):b.currentStyle.display,b=b.parentNode;b=f==="none"}e=b}if(e)return a.innerText||a.textContent;c=c.createRange();c.selectNode(a);
+a=d.getSelection();d=[];for(f=0;f<a.rangeCount;f++)d.push(a.getRangeAt(f));a.removeAllRanges();a.addRange(c);c=a.toString();a.removeAllRanges();for(f=0;f<d.length;f++)a.addRange(d[f]);return c}function P(a){if(a.substring(0,12)==="data-editor-")return a=a.substring(12),a=a.replace(/-([a-z])/ig,function(a,b){return b.toUpperCase()})}function M(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function Q(a,b){var c={};M(c,b);for(var d,e=0,f=a.attributes,g=f.length;e<g;e++){d=f.item(e);var h=P(d.nodeName);
+if(h){d=d.nodeValue;if(d==="true"||d==="false")d=d==="true";c[h]=d}}return c}function R(a,b){if(a.getElementsByClassName)return a.getElementsByClassName(b);b=b.replace(/ *$/,"");return a.querySelectorAll?a.querySelectorAll((" "+b).replace(/ +/g,".")):null}function B(a){var b=a.document||document,e=a.parent;e||(e="editor");typeof e==="string"&&(e=b.getElementById(e));if(!e&&a.className&&(b=R(b,a.className))){a.className=void 0;if(b.length>1&&a.noFocus===void 0)a.noFocus=!0;for(var f=[],g=b.length-
+1;g>=0;g--)a.parent=b[g],f.push(B(a));return f}if(!e)throw"no parent";a=Q(e,a);if(typeof a.theme==="string"){var b=c.TextTheme.getTheme(a.theme),g=a.theme.lastIndexOf("/"),h=a.theme;g!==-1&&(h=h.substring(g+1));h.substring(h.length-4)===".css"&&(h=h.substring(0,h.length-4));b.setThemeClass(h,{href:a.theme});a.theme=b}var j;a.readonly||(f={createContentAssistMode:function(a){j=new r.ContentAssist(a.getTextView());a=new r.ContentAssistWidget(j);a=new r.ContentAssistMode(j,a);j.setMode(a);return a}});
+var l=new o.Editor({textViewFactory:function(){return new n.TextView({parent:e,model:new d.ProjectionTextModel(a.model?a.model:new i.TextModel("")),tabSize:a.tabSize?a.tabSize:4,readonly:a.readonly,fullSelection:a.fullSelection,tabMode:a.tabMode,expandTab:a.expandTab,singleMode:a.singleMode,themeClass:a.themeClass,theme:a.theme,wrapMode:a.wrapMode,wrappable:a.wrappable})},undoStackFactory:new q.UndoFactory,annotationFactory:new q.AnnotationFactory,lineNumberRulerFactory:new q.LineNumberRulerFactory,
+foldingRulerFactory:new q.FoldingRulerFactory,textDNDFactory:new q.TextDNDFactory,contentAssistFactory:f,keyBindingFactory:new q.KeyBindingsFactory,statusReporter:a.statusReporter,domNode:e});l.addEventListener("TextViewInstalled",function(){var b=l.getLineNumberRuler();b&&a.firstLineIndex!==void 0&&b.setFirstLine(a.firstLineIndex);if(b=l.getSourceCodeActions())b.setAutoPairParentheses(a.autoPairParentheses),b.setAutoPairBraces(a.autoPairBraces),b.setAutoPairSquareBrackets(a.autoPairSquareBrackets),
+b.setAutoPairAngleBrackets(a.autoPairAngleBrackets),b.setAutoPairQuotations(a.autoPairQuotations),b.setAutoCompleteComments(a.autoCompleteComments),b.setSmartIndentation(a.smartIndentation)});f=a.contents;f===void 0&&(f=O(e));f||(f="");l.installTextView();l.setLineNumberRulerVisible(a.showLinesRuler===void 0||a.showLinesRuler);l.setAnnotationRulerVisible(a.showAnnotationRuler===void 0||a.showFoldingRuler);l.setOverviewRulerVisible(a.showOverviewRuler===void 0||a.showOverviewRuler);l.setFoldingRulerVisible(a.showFoldingRuler===
+void 0||a.showFoldingRuler);l.setInput(a.title,null,f,!1,a.noFocus);({styler:null,highlight:function(b,c){this.styler&&this.styler.destroy&&this.styler.destroy();this.styler=null;b==="js"?b="application/javascript":b==="css"?b="text/css":b==="html"?b="text/html":b==="java"&&(b="text/x-java-source");var d=c.getTextView(),e=c.getAnnotationModel();b&&(b=b.replace(/[*|:/".<>?+]/g,"_"),k(["./stylers/"+b+"/syntax"],function(a){this.styler=new x.TextStyler(d,e,a.grammars,a.id)}));b==="text/css"&&c.setFoldingRulerVisible(a.showFoldingRuler===
+void 0||a.showFoldingRuler)}}).highlight(a.contentType||a.lang,l);if(j){var m=new p.CssContentAssistProvider,s=new t.HTMLContentAssistProvider,u=new v.JSTemplateContentAssistProvider;j.addEventListener("Activating",function(){/css$/.test(a.lang)?j.setProviders([m]):/js$/.test(a.lang)?j.setProviders([u]):/html$/.test(a.lang)&&j.setProviders([s])})}if(e.clientHeight<=50)f=l.getTextView().computeSize().height,e.style.height=f+"px";return l}var E=this.orion?this.orion.editor:void 0;if(E)for(var G=0;G<
+arguments.length;G++)M(E,arguments[G]);return B});var orion=this.orion||(this.orion={}),editor=orion.editor||(orion.editor={});editor.edit=require("orion/editor/edit");
\ No newline at end of file
diff --git a/dgbuilder/public/pw_maze_white.png b/dgbuilder/public/pw_maze_white.png
new file mode 100644 (file)
index 0000000..6646483
Binary files /dev/null and b/dgbuilder/public/pw_maze_white.png differ
diff --git a/dgbuilder/public/red/comms.js b/dgbuilder/public/red/comms.js
new file mode 100644 (file)
index 0000000..6491247
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.comms = (function() {
+    
+    var errornotification = null;
+    var subscriptions = {};
+    var ws;
+    function connectWS() {
+        var path = location.hostname+":"+location.port+document.location.pathname;
+        path = path+(path.slice(-1) == "/"?"":"/")+"comms";
+        path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
+        ws = new WebSocket(path);
+        ws.onopen = function() {
+            if (errornotification) {
+                errornotification.close();
+                errornotification = null;
+            }
+            for (var t in subscriptions) {
+                if (subscriptions.hasOwnProperty(t)) {
+                    ws.send(JSON.stringify({subscribe:t}));
+                }
+            }
+        }
+        ws.onmessage = function(event) {
+            var msg = JSON.parse(event.data);
+            if (msg.topic) {
+                for (var t in subscriptions) {
+                    if (subscriptions.hasOwnProperty(t)) {
+                        var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
+                        if (re.test(msg.topic)) {
+                            var subscribers = subscriptions[t];
+                            if (subscribers) {
+                                for (var i=0;i<subscribers.length;i++) {
+                                    subscribers[i](msg.topic,msg.data);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        };
+        ws.onclose = function() {
+            if (errornotification == null) {
+                errornotification = RED.notify("<b>Error</b>: Lost connection to server","error",true);
+            }
+            setTimeout(connectWS,1000);
+        }
+    }
+    
+    function subscribe(topic,callback) {
+        if (subscriptions[topic] == null) {
+            subscriptions[topic] = [];
+        }
+        subscriptions[topic].push(callback);
+        if (ws && ws.readyState == 1) {
+            ws.send(JSON.stringify({subscribe:topic}));
+        }
+    }
+    
+    function unsubscribe(topic,callback) {
+        if (subscriptions.topic) {
+            for (var i=0;i<subscriptions.topic.length;i++) {
+                if (subscriptions.topic[i] === callback) {
+                    subscriptions.topic.splice(i,1);
+                    break;
+                }
+            }
+            if (subscriptions.topic.length === 0) {
+                delete subscriptions.topic;
+            }
+        }
+    }
+    
+    return {
+        connect: connectWS,
+        subscribe: subscribe,
+        unsubscribe:unsubscribe
+    }
+})();
diff --git a/dgbuilder/public/red/history.js b/dgbuilder/public/red/history.js
new file mode 100644 (file)
index 0000000..3a6d551
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.history = (function() {
+    var undo_history = [];
+    
+    return {
+        //TODO: this function is a placeholder until there is a 'save' event that can be listened to
+        markAllDirty: function() {
+            for (var i=0;i<undo_history.length;i++) {
+                undo_history[i].dirty = true;
+            }
+        },
+        depth: function() {
+            return undo_history.length;
+        },
+        push: function(ev) {
+            undo_history.push(ev);
+        },
+        pop: function() {
+            var ev = undo_history.pop();
+            var i;
+            if (ev) {
+                if (ev.t == 'add') {
+                    if (ev.nodes) {
+                        for (i=0;i<ev.nodes.length;i++) {
+                            RED.nodes.remove(ev.nodes[i]);
+                        }
+                    }
+                    if (ev.links) {
+                        for (i=0;i<ev.links.length;i++) {
+                            RED.nodes.removeLink(ev.links[i]);
+                        }
+                    }
+                    if (ev.workspaces) {
+                        for (i=0;i<ev.workspaces.length;i++) {
+                            RED.nodes.removeWorkspace(ev.workspaces[i].id);
+                            RED.view.removeWorkspace(ev.workspaces[i]);
+                        }
+                    }
+                } else if (ev.t == "delete") {
+                    if (ev.workspaces) {
+                        for (i=0;i<ev.workspaces.length;i++) {
+                            RED.nodes.addWorkspace(ev.workspaces[i]);
+                            RED.view.addWorkspace(ev.workspaces[i]);
+                        }
+                    }
+                    if (ev.nodes) {
+                        for (i=0;i<ev.nodes.length;i++) {
+                            RED.nodes.add(ev.nodes[i]);
+                        }
+                    }
+                    if (ev.links) {
+                        for (i=0;i<ev.links.length;i++) {
+                            RED.nodes.addLink(ev.links[i]);
+                        }
+                    }
+                } else if (ev.t == "move") {
+                    for (i=0;i<ev.nodes.length;i++) {
+                        var n = ev.nodes[i];
+                        n.n.x = n.ox;
+                        n.n.y = n.oy;
+                        n.n.dirty = true;
+                    }
+                } else if (ev.t == "edit") {
+                    for (i in ev.changes) {
+                        if (ev.changes.hasOwnProperty(i)) {
+                            ev.node[i] = ev.changes[i];
+                        }
+                    }
+                    RED.editor.updateNodeProperties(ev.node);
+                    if (ev.links) {
+                        for (i=0;i<ev.links.length;i++) {
+                            RED.nodes.addLink(ev.links[i]);
+                        }
+                    }
+                    RED.editor.validateNode(ev.node);
+                    ev.node.dirty = true;
+                    ev.node.changed = ev.changed;
+                }
+                RED.view.dirty(ev.dirty);
+                RED.view.redraw();
+            }
+        }
+    }
+
+})();
diff --git a/dgbuilder/public/red/main.js b/dgbuilder/public/red/main.js
new file mode 100644 (file)
index 0000000..27032a2
--- /dev/null
@@ -0,0 +1,1620 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var RED = (function() {
+
+    function hideDropTarget() {
+        $("#dropTarget").hide();
+        RED.keyboard.remove(/* ESCAPE */ 27);
+    }
+
+    $('#chart').on("dragenter",function(event) {
+        if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
+            $("#dropTarget").css({display:'table'});
+            RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
+        }
+    });
+
+    $('#dropTarget').on("dragover",function(event) {
+        if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
+            event.preventDefault();
+        }
+    })
+    .on("dragleave",function(event) {
+        hideDropTarget();
+    })
+    .on("drop",function(event) {
+        var data = event.originalEvent.dataTransfer.getData("text/plain");
+        hideDropTarget();
+        RED.view.importNodes(data);
+        event.preventDefault();
+    });
+
+
+    function save(force) {
+        if (RED.view.dirty()) {
+            //$("#debug-tab-clear").click();  // uncomment this to auto clear debug on deploy
+
+            if (!force) {
+                var invalid = false;
+                var unknownNodes = [];
+                RED.nodes.eachNode(function(node) {
+                    invalid = invalid || !node.valid;
+                    if (node.type === "unknown") {
+                        if (unknownNodes.indexOf(node.name) == -1) {
+                            unknownNodes.push(node.name);
+                        }
+                        invalid = true;
+                    }
+                });
+                if (invalid) {
+                    if (unknownNodes.length > 0) {
+                        $( "#node-dialog-confirm-deploy-config" ).hide();
+                        $( "#node-dialog-confirm-deploy-unknown" ).show();
+                        var list = "<li>"+unknownNodes.join("</li><li>")+"</li>";
+                        $( "#node-dialog-confirm-deploy-unknown-list" ).html(list);
+                    } else {
+                        $( "#node-dialog-confirm-deploy-config" ).show();
+                        $( "#node-dialog-confirm-deploy-unknown" ).hide();
+                    }
+                    $( "#node-dialog-confirm-deploy" ).dialog( "open" );
+                    return;
+                }
+            }
+            var nns = RED.nodes.createCompleteNodeSet();
+           /****************************************/
+           /*added new code to save the Tabs order */
+           /****************************************/ 
+           //console.log("nns before changes.");
+           //console.dir(nns);
+            var allTabsObj={};
+            var allTabsList=[];
+            var nnsTabIdsArr = [];
+            var guiTabIdsArr = [];
+            nns.forEach(function(n) {
+                       if(n.type == 'tab'){
+                               allTabsObj[n.id] = n;
+                               allTabsList.push(n);
+                               nnsTabIdsArr.push(n.id);
+                       }
+           });
+           var idx =0; 
+           $("#workspace-tabs li a").each(function(){
+               var href = $(this).prop("href");
+               var indexOfHash = href.indexOf("#");
+               var idVal = href.slice(indexOfHash+1);
+               guiTabIdsArr.push(idVal);
+               nns.splice(idx,1,allTabsObj[idVal]);;
+               idx++;
+           }); 
+           //console.log(nnsTabIdsArr.join(","));      
+           //console.log(guiTabIdsArr.join(","));      
+           //console.log("nns after changes.");
+           //console.dir(nns);
+           /****************************/ 
+            $("#btn-icn-deploy").removeClass('fa-download');
+            $("#btn-icn-deploy").addClass('spinner');
+            RED.view.dirty(false);
+
+            $.ajax({
+                url:"flows",
+                type: "POST",
+                data: JSON.stringify(nns),
+                contentType: "application/json; charset=utf-8"
+            }).done(function(data,textStatus,xhr) {
+                RED.notify("Successfully saved","success");
+                RED.nodes.eachNode(function(node) {
+                    if (node.changed) {
+                        node.dirty = true;
+                        node.changed = false;
+                    }
+                    if(node.credentials) {
+                        delete node.credentials;
+                    }
+                });
+                RED.nodes.eachConfig(function (confNode) {
+                    if (confNode.credentials) {
+                        delete confNode.credentials;
+                    }
+                });
+                // Once deployed, cannot undo back to a clean state
+                RED.history.markAllDirty();
+                RED.view.redraw();
+            }).fail(function(xhr,textStatus,err) {
+                RED.view.dirty(true);
+                if (xhr.responseText) {
+                    RED.notify("<strong>Error</strong>: "+xhr.responseText,"error");
+                } else {
+                    RED.notify("<strong>Error</strong>: no response from server","error");
+                }
+            }).always(function() {
+                $("#btn-icn-deploy").removeClass('spinner');
+                $("#btn-icn-deploy").addClass('fa-download');
+            });
+        }
+    }
+
+    $('#btn-deploy').click(function() { save(); });
+
+    $( "#node-dialog-confirm-deploy" ).dialog({
+            title: "Confirm deploy",
+            modal: true,
+            autoOpen: false,
+            width: 530,
+            height: 230,
+            buttons: [
+                {
+                    text: "Confirm deploy",
+                    click: function() {
+                        save(true);
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ]
+    });
+
+    function loadSettings() {
+        $.get('settings', function(data) {
+            RED.settings = data;
+            console.log("Node-RED: "+data.version);
+            loadNodeList();
+        });
+    }
+
+    function loadNodeList() {
+        $.ajax({
+            headers: {
+                "Accept":"application/json"
+            },
+            cache: false,
+            url: 'nodes',
+            success: function(data) {
+                RED.nodes.setNodeList(data);
+                loadNodes();
+            }
+        });
+    }
+
+    function loadNodes() {
+        $.ajax({
+            headers: {
+                "Accept":"text/html"
+            },
+            cache: false,
+            url: 'nodes',
+            success: function(data) {
+                $("body").append(data);
+                $(".palette-spinner").hide();
+                $(".palette-scroll").show();
+                $("#palette-search").show();
+                loadFlows();
+            }
+        });
+    }
+
+    function loadFlows() {
+        $.ajax({
+            headers: {
+                "Accept":"application/json"
+            },
+            cache: false,
+            url: 'flows',
+            success: function(nodes) {
+                RED.nodes.import(nodes);
+                RED.view.dirty(false);
+                RED.view.redraw();
+                RED.comms.subscribe("status/#",function(topic,msg) {
+                    var parts = topic.split("/");
+                    var node = RED.nodes.node(parts[1]);
+                    if (node) {
+                        node.status = msg;
+                        if (statusEnabled) {
+                            node.dirty = true;
+                            RED.view.redraw();
+                        }
+                    }
+                });
+                RED.comms.subscribe("node/#",function(topic,msg) {
+                    var i,m;
+                    var typeList;
+                    var info;
+                    
+                    if (topic == "node/added") {
+                        var addedTypes = [];
+                        for (i=0;i<msg.length;i++) {
+                            m = msg[i];
+                            var id = m.id;
+                            RED.nodes.addNodeSet(m);
+                            if (m.loaded) {
+                                addedTypes = addedTypes.concat(m.types);
+                                $.get('nodes/'+id, function(data) {
+                                    $("body").append(data);
+                                });
+                            }
+                        }
+                        if (addedTypes.length) {
+                            typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
+                            RED.notify("Node"+(addedTypes.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
+                        }
+                    } else if (topic == "node/removed") {
+                        for (i=0;i<msg.length;i++) {
+                            m = msg[i];
+                            info = RED.nodes.removeNodeSet(m.id);
+                            if (info.added) {
+                                typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
+                                RED.notify("Node"+(m.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
+                            }
+                        }
+                    } else if (topic == "node/enabled") {
+                        if (msg.types) {
+                            info = RED.nodes.getNodeSet(msg.id);
+                            if (info.added) {
+                                RED.nodes.enableNodeSet(msg.id);
+                                typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                                RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" enabled:"+typeList,"success");
+                            } else {
+                                $.get('nodes/'+msg.id, function(data) {
+                                    $("body").append(data);
+                                    typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                                    RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
+                                });
+                            } 
+                        }
+                    } else if (topic == "node/disabled") {
+                        if (msg.types) {
+                            RED.nodes.disableNodeSet(msg.id);
+                            typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                            RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" disabled:"+typeList,"success");
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    var statusEnabled = false;
+    function toggleStatus(state) {
+        statusEnabled = state;
+        RED.view.status(statusEnabled);
+    }
+
+    function performLoopDetection(state) {
+        loopDetectionEnabled = state;
+       console.log("loopDetectionEnabled:" + loopDetectionEnabled);
+    }
+
+    var dgNumberEnabled = false;
+    function toggleDgNumberDisplay(state) {
+        dgNumberEnabled = state;
+        RED.view.showNumbers(dgNumberEnabled);
+    }
+
+    var nodePaletteDisplay = false;
+    function toggleNodePaletteDisplay(state) {
+        nodePaletteDisplay = state;
+        RED.view.showNodePalette(nodePaletteDisplay);
+    }
+    function displayAllDGs(state) {
+               //defined showSLa() in dgstart.html 
+               showSLA();
+    }
+
+
+    function showHelp() {
+
+        var dialog = $('#node-help');
+
+        //$("#node-help").draggable({
+        //        handle: ".modal-header"
+        //});
+
+        dialog.on('show',function() {
+            RED.keyboard.disable();
+        });
+        dialog.on('hidden',function() {
+            RED.keyboard.enable();
+        });
+
+        dialog.modal();
+    }
+
+
+//Custom Functions Added here
+       function  showCodeCloudFlows(){
+               codeCloudFlowFiles=[];
+               var divStyle="<style>#codecloud-data-container a { color: #067ab4; font-size: 0.75em;} #codecloud-data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get( "/getCodeCloudFlows")
+                               .done(function( data ) {
+                                       
+                                       var header="<div class='header'>List of DG Flows in Code Cloud</div><div><input id='flowFilterBoxId' type='text' onkeyup='filterFlows(this.value)'></div>";
+                                       var html=  divStyle + header +  "<div id='codecloud-data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var files=data.files;
+                                               codeCloudFlowFiles=files;
+                                               //console.dir(files);
+                                               files.sort(function (a,b){
+                                                       if(a > b){
+                                                               return 1;
+                                                       }else if(a <  b){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;files != null && i<files.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"getCommits('" + files[i] + "')\">" + files[i] + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#codecloud-browser-dialog" ).dialog({
+                                       title: "Code Cloud DG Flow Browser",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 830,
+                                       height: 630,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $( this ).dialog( "close" );
+                                                       }
+                                               }
+                                               ],
+                                       close: function(ev,ui){
+                                               $(this).dialog("destroy");
+                                       }
+                                       }).html(html);
+                                       $("#codecloud-browser-dialog").show();
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get users.");
+                                })
+                                 .always(function() {
+                               });
+       }
+       /*      
+       function  listYangFiles(){
+               yangFilesList=[];
+               var divStyle="<style>#list-yang-data-container a { color: #067ab4; font-size: 0.75em;} #list-yang-data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get( "/getYangFiles")
+                               .done(function( data ) {
+                                       
+                                       var header="<div class='header'>List of Yang Files </div><div><input id='flowFilterBoxId' type='text' onkeyup='filterYangFiles(this.value)'></div>";
+                                       var html=  divStyle + header +  "<div id='list-yang-data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var files=data.files;
+                                               yangFilesList=files;
+                                               //console.dir(files);
+                                               files.sort(function (a,b){
+                                                       if(a > b){
+                                                               return 1;
+                                                       }else if(a <  b){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;files != null && i<files.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"getYangFile('" + files[i] + "')\">" + files[i] + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#list-yang-browser-dialog" ).dialog({
+                                       title: "List Yang Files",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 830,
+                                       height: 630,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $( this ).dialog( "close" );
+                                                       }
+                                               }
+                                               ],
+                                       close: function(ev,ui){
+                                               $(this).dialog("destroy");
+                                       }
+                                       }).html(html);
+                                       $("#list-yang-browser-dialog").show();
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get yang files.");
+                                })
+                                 .always(function() {
+                               });
+       }
+       */
+
+       function  listYangFiles(){
+               yangFilesList=[];
+       
+               var divStyle="<style>#yang-files-data-container a { color: #067ab4; font-size: 0.75em;} #yang-files-data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } table#yang-file-list-table { width:100%; } table#yang-file-list-table th,table#yang-file-list-table td { border: 1px solid black; border-collapse: collapse; } table#yang-file-list-table th,table#yang-file-list-table td { padding: 5px; text-align: left; } table#yang-file-list-table tr:nth-child(even) { background-color: #eee; } table#yang-file-list-table tr:nth-child(odd) { background-color:#fff; } table#yang-file-list-table th    { background-color: #65a9d7; color: white; } table#yang-file-list-table a { color: #337ab7; } table#yang-file-list-table a:link { color: #65a9d7; } table#yang-file-list-table a:visited { color: #636; } table#yang-file-list-table a:hover { color: #3366CC; cursor: pointer } table#yang-file-list-table a:active { color: #65a9d7 }</style>";
+               $.get( "/getYangFiles")
+                               .done(function( data ) {
+                                       
+                                       var header="<div class='header'>List of Yang Files </div><div><input id='flowFilterBoxId' type='text' onkeyup='filterYangFiles(this.value)'></div>";
+                                       var html=  divStyle + header +  "<div id='yang-files-data-container'>";
+                                       html+="<table id='yang-file-list-table'  border=1>";
+                                       html+="<tr>";
+                                       html+="<th>File</th>";
+                                       html+="<th>Delete</th>";
+                                       html+="</tr>";
+                                       if(data != null){
+                                               var files=data.files;
+                                               yangFilesList=files;
+                                               //console.dir(files);
+                                               files.sort(function (a,b){
+                                                       if(a > b){
+                                                               return 1;
+                                                       }else if(a <  b){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;files != null && i<files.length;i++){
+                                                       html+="<tr><td><a href=\"#\" onclick=\"getYangFile('" + files[i] + "')\">" + files[i] + "</a></td><td>" + "<input type='button'  onclick='deleteYangFile(\"" + files[i]  + "\")' value='Delete'></td></td></td></tr>";
+                                               }
+                                       }
+                                       html+="</table>";
+                                       html+="</div>";
+                                       $( "#list-yang-browser-dialog" ).dialog({
+                                       title: "List Yang Files",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 830,
+                                       height: 630,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $( this ).dialog( "close" );
+                                                       }
+                                               }
+                                               ],
+                                       close: function(ev,ui){
+                                               $(this).dialog("destroy");
+                                       }
+                                       }).html(html);
+                                       $("#list-yang-browser-dialog").show();
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get yang files.");
+                                })
+                                 .always(function() {
+                               });
+       }
+               
+
+       function showGitPullDialog(){
+               $.get( "/getCurrentGitBranch")
+                               .done(function( data ) {
+                                       if(data != null){ 
+                                               if(data.output == "GIT_LOCAL_REPOSITORY_NOT_SET" ){
+                                                       RED.notify("Git Local Repository path is not set. Please set it by choosing Configuration from the menu.");
+                                                       return;
+                                               }       
+
+                                               var html= "<div id='gitcheckout-container'>";
+                                               html+="<table>";
+                                               html+="<tr>";
+                                               html+="<td>Branch</td>";
+                                               html+="<td>" +  data.output + "</td>";
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               html+="<td><input id='gitPullBtnId' type='button' value='Pull' onclick='performGitPull()'></td>";
+                                               html+="<td>&nbsp;&nbsp;</td>"
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               //html+="<td colspan=3><textarea readonly='1' rows='5' cols='200'  id='responseId'></textarea></td>";
+                                               html+="</tr>";
+                                               html+="</table>";
+                                               html+="<br><div id='responseId'></div>";
+                                               html+="</div>";
+                                               $( "#gitcommands-dialog" ).dialog({
+                                                       title: "Git Pull",
+                                                       modal: true,
+                                                       autoOpen: true,
+                                                       width: 630,
+                                                       height: 500,
+                                                       buttons: [
+                                                       {
+                                                               text: "Close",
+                                                               click: function() {
+                                                                       $( this ).dialog( "close" );
+                                                               }
+                                                       }
+                                                       ],
+                                                       close: function(ev,ui){
+                                                               $(this).dialog("destroy");
+                                                       }
+                                               }).html(html);
+                                         $("#responseId").css({width:'550',height:'275px', border: '2px solid lightgrey',overflow:'scroll', padding: '20px' });
+                                         $("#responseId").hide();
+                                       $("#gitcommands-dialog").show();
+                               }
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get gitBranch.");
+                                })
+                                 .always(function() {
+                               });
+       }
+
+       function showGitStatusDialog(){
+               $.get( "/getCurrentGitBranch")
+                               .done(function( data ) {
+                                       if(data != null){ 
+                                               if(data.output == "GIT_LOCAL_REPOSITORY_NOT_SET" ){
+                                                       RED.notify("Git Local Repository path is not set. Please set it by choosing Configuration from the menu.");
+                                                       return;
+                                               }       
+
+                                               var html= "<div id='gitcheckout-container'>";
+                                               html+="<table>";
+                                               html+="<tr>";
+                                               html+="<td>Branch</td>";
+                                               html+="<td>" + data.output + "</td>";
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               html+="<td><input id='gitStatusBtnId' type='button' value='Status' onclick='performGitStatus()'></td>";
+                                               html+="<td>&nbsp;&nbsp;</td>"
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               //html+="<td colspan=3><textarea readonly='1' rows='5' cols='200'  id='responseId'></textarea></td>";
+                                               html+="</tr>";
+                                               html+="</table>";
+                                               html+="<br><div id='responseId'></div>";
+                                               html+="</div>";
+                                               $( "#gitcommands-dialog" ).dialog({
+                                                       title: "Git Status",
+                                                       modal: true,
+                                                       autoOpen: true,
+                                                       width: 630,
+                                                       height: 500,
+                                                       buttons: [
+                                                       {
+                                                               text: "Close",
+                                                               click: function() {
+                                                                       $( this ).dialog( "close" );
+                                                               }
+                                                       }
+                                                       ],
+                                                       close: function(ev,ui){
+                                                               $(this).dialog("destroy");
+                                                       }
+                                               }).html(html);
+                                         //$("#responseId").css({width:'600px',height:'100px','border-radius' : '25px', border: '2px solid lightgrey', padding: '20px' });
+                                         $("#responseId").css({width:'550px',height:'100px', border: '2px solid lightgrey',overflow:'scroll', padding: '20px' });
+                                         $("#responseId").hide();
+                                       $("#gitcommands-dialog").show();
+                               }
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get gitBranch.");
+                                })
+                                 .always(function() {
+                               });
+       }
+
+       function showGitCheckoutDialog(){
+               $.get( "/getCurrentGitBranch")
+                               .done(function( data ) {
+                                       if(data != null){ 
+                                               if(data.output == "GIT_LOCAL_REPOSITORY_NOT_SET" ){
+                                                       RED.notify("Git Local Repository path is not set. Please set it by choosing Configuration from the menu.");
+                                                       return;
+                                               }       
+
+                                               var html= "<div id='gitcheckout-container'>";
+                                               html+="<table>";
+                                               html+="<tr>";
+                                               html+="<td>Branch</td>";
+                                               html+="<td><input id='branchId' type='text' value='" + data.output + "'></td>";
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               html+="<td><input id='checkoutBtnId' type='button' value='Checkout' onclick='performGitCheckout()'></td>";
+                                               html+="<td>&nbsp;&nbsp;</td>"
+                                               html+="</tr>";
+                                               html+="<tr>";
+                                               //html+="<td colspan=3><textarea readonly='1' rows='5' cols='200'  id='responseId'></textarea></td>";
+                                               html+="</tr>";
+                                               html+="</table>";
+                                               html+="<br><div id='responseId'></div>";
+                                               html+="</div>";
+                                               $( "#gitcommands-dialog" ).dialog({
+                                                       title: "Git Checkout",
+                                                       modal: true,
+                                                       autoOpen: true,
+                                                       width: 430,
+                                                       height: 350,
+                                                       buttons: [
+                                                       {
+                                                               text: "Close",
+                                                               click: function() {
+                                                                       $( this ).dialog( "close" );
+                                                               }
+                                                       }
+                                                       ],
+                                                       close: function(ev,ui){
+                                                               $(this).dialog("destroy");
+                                                       }
+                                               }).html(html);
+                                         $("#responseId").css({width:'300',height:'100px', border: '2px solid lightgrey',overflow:'scroll', padding: '20px' });
+                                         $("#responseId").hide();
+                                       $("#gitcommands-dialog").show();
+                               }
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get gitBranch.");
+                                })
+                                 .always(function() {
+                               });
+       }
+
+       function  showGitLocalFlows(){
+               giLocalFlowFiles=[];
+               var divStyle="<style>#gitlocal-data-container a { color: #067ab4; font-size: 0.75em;} #gitlocal-data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get( "/getGitLocalFlows")
+                               .done(function( data ) {
+                                       if(data != null && data.files != null && data.files.length == 1){
+                                               if(data.files[0] == "GIT_LOCAL_REPOSITORY_NOT_SET" ){
+                                                       RED.notify("Git Local Repository path is not set. Please set it by choosing Configuration from the menu.");
+                                                       return;
+                                               }       
+                                       }
+                                       //console.log("got response from server.");
+                                       
+                                       var header="<div class='header'>List of DG Flows  from  Git Local Repository </div><div><input id='flowFilterBoxId' type='text' onkeyup='filterGitLocalFlows(this.value)'></div>";
+                                       var html=  divStyle + header +  "<div id='gitlocal-data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var files=data.files;
+                                               gitLocalFlowFiles=files;
+                                               //console.dir(files);
+                                               files.sort(function (a,b){
+                                                       if(a > b){
+                                                               return 1;
+                                                       }else if(a <  b){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;files != null && i<files.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"importGitLocalFlow('" + files[i] + "')\">" + files[i] + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#gitlocal-browser-dialog" ).dialog({
+                                       title: "Git Local Repository DG Flow Browser",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 830,
+                                       height: 630,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $(this).dialog("close");
+                                                       }
+                                               }
+                                               ]
+                                       }).html(html);
+                                       $("#gitlocal-browser-dialog").show();
+                                       /*
+                                       if ($("#gitlocal-browser-dialog").dialog( "isOpen" )===true) {
+                                               console.log("gitlocal dialog box is open");     
+                                               //true
+                                       } else {
+                                               console.log("gitlocal dialog box is not open"); 
+                                       //      $( "#gitlocal-browser-dialog" ).dialog("destroy").remove();
+                                               console.log($("#gitlocal-browser-dialog").dialog( "widget" ));
+                                               $("#gitlocal-browser-dialog").dialog( "open" );
+                                               if ($("#gitlocal-browser-dialog").dialog( "isOpen" )===true) {
+                                                       console.log("gitlocal dialog box is now open"); 
+                                               }
+                                               $("#gitlocal-browser-dialog").show();
+                                               //false
+                                       }
+                                       */
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get flows.");
+                                })
+                                 .always(function() {
+                                       console.log("Done displaying");
+                               });
+       }
+
+       function  showFlowShareUsers(){
+               var divStyle="<style>#data-container a { color: #067ab4; font-size: 0.75em;} #data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get("/flowShareUsers")
+                       .done(function (data){
+                                       
+                                       var header="<div class='header'>List of Downloaded DG Flows</div>";
+                                       var html=  divStyle + header +  "<div id='data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var users=data.flowShareUsers;
+                                               users.sort(function (a,b){
+                                                       if(a.name > b.name){
+                                                               return 1;
+                                                       }else if(a.name <  b.name){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;users != null && i<users.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"showFlowFiles('" + users[i].rootDir + "')\">" + users[i].name + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#dgflow-browser-dialog" ).dialog({
+                                       title: "Downloaded DG Flows Browser",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 530,
+                                       height: 530,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $( this ).dialog( "close" );
+                                                               //$(this).dialog('destroy').remove();
+                                                       }
+                                               }
+                                               ]
+                                       }).html(html);
+                                       $("#dgflow-browser-dialog").show();
+                                       /*
+                                       if ($("#dgflow-browser-dialog").dialog( "isOpen" )===true) {
+                                               console.log("dgflow dialog box is open");       
+                                               //true
+                                       } else {
+                                               console.log("dgflow dialog box is not open");   
+                                               $("#dgflow-browser-dialog").dialog( "open" );
+                                               $("#dgflow-browser-dialog").show();
+                                               //false
+                                       }
+                                       */
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get users.");
+                                })
+                                 .always(function() {
+                               });
+       }
+
+/*     function  showFlowShareUsers(){
+               var divStyle="<style>#data-container a { color: #067ab4; font-size: 0.75em;} #data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get( "/flowShareUsers")
+                               .done(function( data ) {
+                                       
+                                       var header="<div class='header'>List of Downloaded DG Flows</div>";
+                                       var html=  divStyle + header +  "<div id='data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var users=data.flowShareUsers;
+                                               users.sort(function (a,b){
+                                                       if(a.name > b.name){
+                                                               return 1;
+                                                       }else if(a.name <  b.name){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               for(var i=0;users != null && i<users.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"showFlowFiles('" + users[i].rootDir + "')\">" + users[i].name + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#dgflow-browser-dialog" ).dialog({
+                                       title: "Downloaded DG Flows Browser",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 530,
+                                       height: 530,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               //$( this ).dialog( "close" );
+                                                               $(this).dialog('destroy').remove();
+                                                       }
+                                               }
+                                               ]
+                                       }).html(html);
+                                       //$("#dgflow-browser-dialog").show();
+                                       $( "#dgflow-browser-dialog" ).dialog( "open" );
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get users.");
+                                })
+                                 .always(function() {
+                               });
+       }
+       */
+
+
+function detectLoopInFlow(){
+               var errList = [];
+               var activeWorkspace=RED.view.getWorkspace();
+               var nSet=[];
+               
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               nSet.push({n:n});
+                       }
+               });
+
+               var nodeSet = RED.nodes.createExportableNodeSet(nSet);
+
+               var isLoopDetected = false;     
+               var dgStartNode = getDgStartNode(nodeSet);
+               if(dgStartNode == null || dgStartNode == undefined) {
+                       console.log("dgstart node not linked.");
+                       return null;
+               }
+
+               var wires = dgStartNode.wires;
+               var nodesInPath = {};
+               var dgStartNodeId = dgStartNode.id;
+               if(wires != null && wires != undefined && wires[0] != undefined){
+                       for(var k=0;k<wires[0].length;k++){
+                               var val = wires[0][k];
+                               nodesInPath[dgStartNodeId + "->" + val] = "";
+                       }
+               }else{
+                               nodesInPath[dgStartNodeId + "->" + ""] = "";
+               }
+                       
+               var loopDetectedObj = {};
+               /* the nodes will not be in order so will need to loop thru again */
+       for(var m=0;nodeSet != null && m<nodeSet.length;m++){
+               for(var i=0;nodeSet != null && i<nodeSet.length;i++){
+                       var link=nodeSet[i].id;
+                       //console.log("NAME:" + nodeSet[i].name + ":" + link);
+                       if(link == dgStartNodeId) continue;
+                       var wires = nodeSet[i].wires;
+                       //console.log("link:" + link);
+                       var delKeys = [];
+                       if(wires != null && wires != undefined && wires[0] != undefined){
+                               for(var k=0;k<wires[0].length;k++){
+                                       var val = (wires[0])[k];
+                                       var keys = Object.keys(nodesInPath);
+                                       //console.log("keys:" + keys);
+                                       for (var j=0;j<keys.length;j++){
+                                               //console.log("key:" + keys[j]);
+                                               //console.log("val:" + val);
+                                               var index = keys[j].indexOf("->" + link);
+                                               var lastIndex = keys[j].lastIndexOf("->");
+                                               if(index != -1 && index == lastIndex){
+                                                       //delete nodesInPath[key];
+                                                       var previousNodeId = keys[j].substr(lastIndex +2);
+                                                       var indexOfArrow = -1;
+                                                       if(previousNodeId != ""){
+                                                               indexOfArrow = previousNodeId.indexOf("->");
+                                                       }
+                                                       if(previousNodeId != null && indexOfArrow != -1){
+                                                               previousNodeId = previousNodeId.substr(0,indexOfArrow);
+                                                       }       
+                                                       nodesInPath[keys[j] + "->" + val] = "";
+                                                       //console.log("keys[j]:" + keys[j]);
+                                                       delKeys.push(keys[j]);
+                                                       var prevNodeIdIndex = keys[j].indexOf("->" + previousNodeId);
+                                                       var priorOccurence = keys[j].indexOf(val + "->");
+                                                       if(priorOccurence != -1 && priorOccurence<prevNodeIdIndex){
+                                                               //console.log("previousNodeId:" + previousNodeId);
+                                                               //console.log("val:" + val);
+                                                               var n1 = getNode(nodeSet,previousNodeId);
+                                                               var n2 = getNode(nodeSet,val);
+                                                               //console.log("loop detected for node " + n1.name + " and " + n2.name); 
+                                                               loopDetectedObj[n1.name + "->" + n2.name] ="looped";
+                                                               console.dir(loopDetectedObj);
+                                                               errList.push("Loop detected between " + n1.name + " and " + n2.name);
+                                                               isLoopDetected = true;
+                                                       }               
+                                               } 
+                                       }
+                               }
+                       }
+                       for(var l=0;delKeys != null && l<delKeys.length;l++){
+                               delete nodesInPath[delKeys[l]];
+                       }
+               }
+
+
+       }       
+       /*
+       if(loopDetectedObj != null ){ 
+               var msg = "";
+               for(var key in loopDetectedObj){
+                       if(loopDetectedObj.hasOwnProperty(key)) {
+                               console.log("Loop detected  " + key);
+                               msg += "<strong>Loop detected for:" + key + "</strong><br>";
+                       }
+               }
+               if(msg != ""){
+                       isLoopDetected = true;
+                       //RED.notify(msg);
+               }
+       }       
+       */
+       //images/page-loading.gif
+               return errList;
+}
+
+function showLoopDetectionBox(){
+       $(function() {
+       var htmlStr="<div id='loop-box-div' style='width:375;height:225'><p>Loop detection in Progress ...</p><img src='images/page-loading.gif'></div>"
+       $("#loop-detection-dialog").dialog({
+               modal:true,     
+               autoOpen :true,
+               title: "DG Flow Loop Detection",
+               width: 400,
+               height: 250,
+                minWidth : 400, 
+                minHeight :200, 
+               }).html(htmlStr);
+               if($("#loop-detection-dialog").dialog("isOpen") == true){
+                       var errList = detectLoopInFlow();
+                       var errList=[];
+                       if(errList == null){
+                               $("#loop-detection-dialog").dialog("close");
+                       }
+                       var msgHtml = "";
+                       for(var i=0;errList != null && i<errList.length;i++){
+                               msgHtml += "<p>" + errList[i] + "</p>";
+                       }
+                       if(msgHtml == ""){
+                               $("loop-box-div").html("<p>SUCCESS. No Loop detected.</p>");
+                       }else{
+                               $("loop-box-div").html(msgHtml);
+                       }
+               }
+       });
+       
+}
+
+function showSelectedTabs(){
+        var tabSheets = [];
+       var beforeTabsOrder=[];
+        $(".red-ui-tabs li a").each(function(i){
+               var id=$(this).attr("href").replace('#','');
+               var title=$(this).attr("title");
+               var isVisible = $(this).parent().is(":visible"); 
+               if(title != 'info'){
+                       tabSheets.push({"id" : id ,"title":title,"module":"NOT_SET","version" : "NOT_SET","rpc":"NOT_SET","isVisible":isVisible});
+                       beforeTabsOrder.push(id);
+               }
+       });
+
+        RED.nodes.eachNode(function(n) {
+                if(n.type == 'service-logic'){
+                       var id = n.z;
+                       var module = n.module;
+                       tabSheets.forEach(function(tab){
+                               if(tab.id == id){
+                                       tab.module=module;
+                                       tab.version=n.version;
+                               }       
+                       });
+                }else if(n.type == 'method'){
+                       var id = n.z;
+                       tabSheets.forEach(function(tab){
+                               if(tab.id == id){
+                                       var rpc=getAttributeValue(n.xml,"rpc");
+                                       tab.rpc=rpc;
+                               }       
+                       });
+               }
+        });
+       //console.dir(tabSheets);
+       var htmlStr = getHtmlStr(tabSheets);
+       $("#filter-tabs-dialog").dialog({
+               modal:true,     
+               title: "DG Builder Tabs",
+               width: 1200,
+               height: 750,
+                minWidth : 600, 
+                minHeight :450, 
+               }).html(htmlStr);
+/* This code allows for the drag-drop of the rows in the table */
+       var fixHelperModified = function(e, tr) {
+               var $originals = tr.children();
+               var $helper = tr.clone();
+               $helper.children().each(function(index) {
+               $(this).width($originals.eq(index).width())
+       });
+       return $helper;
+       },
+       updateIndex = function(e, ui) {
+               var afterTabsOrder=[];
+               $('td.index', ui.item.parent()).each(function (i) {
+                       $(this).html(i + 1);
+               });
+               //RE-ARRANGE the tabs
+               var ul = $("#workspace-tabs");
+               $("#ftab02 tr td:nth-child(1)").each(function(i){
+                       var idStr = $(this).prop("id").replace("tab-td_","");
+                       afterTabsOrder.push(idStr);
+                       link = ul.find("a[href='#"+ idStr+"']");
+                       li = link.parent();
+                       //li.remove();
+                       firstTab = $("#workspace-tabs li:first-child");
+                       lastTab = $("#workspace-tabs li:last-child");
+                       li.insertAfter(lastTab);
+                       //console.log( idStr);
+               });
+               var beforeTabsStr = beforeTabsOrder.join(",");
+               var afterTabsStr = afterTabsOrder.join(",");
+               //console.log("beforeTabsStr:" +beforeTabsStr);
+               //console.log("afterTabsStr:" +afterTabsStr);
+               if(beforeTabsStr !== afterTabsStr){
+                       //activate only when order has changed
+                       //activate the deploy button
+                       RED.view.dirty(true);
+                       $("#btn-deploy").removeClass("disabled");
+               }
+       };
+
+       $("#ftab02 tbody").sortable({
+       helper: fixHelperModified,
+       stop: updateIndex
+       }).disableSelection();
+
+}
+
+function getHtmlStr(rows){
+       var styleStr = "<style> " + 
+                       "table#ftab02 { width:100%; } \n" +
+                               "table#ftab02 th,table#ftab02 td { border: 1px solid black; border-collapse: collapse; } \n" +
+                               /*"table, th, td { border: 1px solid #65a9d7; border-collapse: collapse; } \n" +*/
+                               "table#ftab02 th,table#ftab02 td { padding: 5px; text-align: left; } \n" +
+                               "table#ftab02 tr:nth-child(even) { background-color: #eee; }\n" +
+                               "table#ftab02 tr:nth-child(odd) { background-color:#fff; }\n" +
+                               "table#ftab02 th        { background-color: #65a9d7; color: white; }\n" +
+                               "table#ftab02 a { color: #337ab7; }\n" +
+                               "table#ftab02 a:link { color: #65a9d7; }\n" +
+                               "table#ftab02 a:visited { color: #636; }\n" + 
+                               "table#ftab02 a:hover { color: #3366CC; cursor: pointer }\n" + 
+                               "table#ftab02 a:active { color: #65a9d7 }\n" +
+                               "</style>";
+                       if(rows != null && rows != undefined){
+                               //var alertDialog = '<div id="confdialog"></div>';
+                               //htmlStr= alertDialog +  "<div style='width:1050;height:650'>" + styleStr;
+                               var alertDialog = '<div id="tabAlertDialog"></div>';
+                               htmlStr= alertDialog +  "<div id='tabs-div' style='width:1050;height:650'>" + styleStr;
+                               htmlStr += "<table id='ftab02' >";
+                               htmlStr += "<tr>";
+                               htmlStr += "<th class='index'>No.</th>" ;
+                               htmlStr += "<th>Tab Title</th>" ;
+                               htmlStr += "<th>Module</th>" ;
+                               htmlStr += "<th>RPC</th>" ;
+                               htmlStr += "<th>Version</th>" ;
+                               htmlStr += "<th>Rename</th>" ;
+                               htmlStr += "<th>Delete</th>" ;
+                               htmlStr += "</tr>";
+                               htmlStr += "<tbody>";
+                               if(rows != null && rows.length == 0){
+                                       htmlStr += "<tr>";
+                                       htmlStr += "<td><b>No rows found</b></td>";
+                                       htmlStr += "</tr></table></div>";
+                                       return htmlStr;
+                               }
+                               for(var i=0;i<rows.length;i++){
+                                       var row = rows[i];
+                                       var title = row.title;
+                                       var _module = row.module;
+                                       var version = row.version;
+                                       var rpc = row.rpc;
+                                       var idVal = row.id;
+                                       var isVisible = row.isVisible;
+                                       htmlStr += "<tr id='tab-tr_" + idVal + "'>";
+                                       //htmlStr += "<td id=" + "'tab-td_" + idVal  + "' ><a href='javascript:activateClickedTab(\"" + idVal + "\")'>" + (i+1) + "</a></td>";
+                                       htmlStr += "<td class='index' id=" + "'tab-td_" + idVal  + "' >" + (i+1) + "</td>";
+                                       htmlStr += "<td><a href='javascript:activateClickedTab(\"" + idVal + "\")'>" + title + "</a></td>";
+                                       htmlStr += "<td>" + _module + "</td>";
+                                       htmlStr += "<td>" + rpc + "</td>";
+                                       htmlStr += "<td>" + version + "</td>";
+                                       //htmlStr += "<td><a href='javascript:deleteOrRenameTab(\"" + idVal + "\")'>Delete/Rename</a></td>";
+                                       htmlStr += "<td><input type='button' onclick='renameSelectedTab(\"" + idVal + "\",\"" + title + "\",\"" +  _module + "\",\"" + rpc + "\",\"" + version + "\")' value='Rename'></td>";
+                                       if(rows.length == 1){
+                                               htmlStr += "<td><input type='button' disabled='1' onclick='deleteSelectedTab(\"" + idVal + "\",\"" + title + "\",\"" +  _module + "\",\"" + rpc + "\",\"" + version + "\")' value='Delete'></td>";
+                                       }else{
+                                               htmlStr += "<td><input type='button'  onclick='deleteSelectedTab(\"" + idVal + "\",\"" + title + "\",\"" +  _module + "\",\"" + rpc + "\",\"" + version + "\")' value='Delete'></td>";
+                                       }
+                                       /*
+                                       if(isVisible){
+                                               htmlStr += "<td><input type='checkbox' onclick=\"showOrHideTab(this,'" + idVal + "')\" checked='true'></td>";
+                                       }else{
+                                               htmlStr += "<td><input type='checkbox' onclick=\"showOrHideTab(this,'" + idVal + "')\"></td>";
+                                       }
+                                       */
+                                       htmlStr += "</tr>";
+                               }
+                               htmlStr += "</tbody>";
+                               htmlStr += "</table>";
+                               htmlStr += "</div>";
+                       }
+       return htmlStr;
+}
+/*
+Added this logic because , when the configuration item is choosen in the menu the other dialog boxes were not poping up
+*/
+(function(){
+       //var msecs1= Date.now();
+               $( "#gitlocal-browser-dialog" ).dialog();
+               $( "#gitlocal-browser-dialog" ).dialog("close");
+               $( "#dgflow-browser-dialog" ).dialog();
+               $( "#dgflow-browser-dialog" ).dialog("close");
+               $( "#update-password-dialog" ).dialog();
+               $( "#update-password-dialog" ).dialog("close");
+               $( "#codecloud-browser-dialog" ).dialog();
+               $( "#codecloud-browser-dialog" ).dialog("close");
+               $( "#update-configuration-dialog" ).dialog();
+               $( "#update-configuration-dialog" ).dialog("close");
+               $( "#gitcommands-dialog" ).dialog();
+               $( "#gitcommands-dialog" ).dialog("close");
+               $("#filter-tabs-dialog").dialog();
+               $("#filter-tabs-dialog").dialog("close");
+               $("#loop-detection-dialog").dialog();
+               $("#loop-detection-dialog").dialog("close");
+               $("#dgstart-generate-xml-dialog").dialog();
+               $("#dgstart-generate-xml-dialog").dialog("close");
+               $("#xmldialog").dialog();
+               $("#xmldialog").dialog("close");
+               $("#upload-xml-status-dialog").dialog();
+               $("#upload-xml-status-dialog").dialog("close");
+               $("#flow-design-err-dialog").dialog();
+               $("#flow-design-err-dialog").dialog("close");
+               $("#sli-values-dialog").dialog();
+               $("#sli-values-dialog").dialog("close");
+               $("#comments-dialog").dialog();
+               $("#comments-dialog").dialog("close");
+               $("#show-errors-dialog").dialog();
+               $("#show-errors-dialog").dialog("close");
+               $("#dgnumber-find-dialog").dialog();
+               $("#dgnumber-find-dialog").dialog("close");
+               $("#search-text-dialog").dialog();
+               $("#search-text-dialog").dialog("close");
+               $("#yang-upload-dialog").dialog();
+               $("#yang-upload-dialog").dialog("close");
+               $("#yang-modules-browser-dialog").dialog();
+               $("#yang-modules-browser-dialog").dialog("close");
+               $("#list-yang-browser-dialog").dialog();
+               $("#list-yang-browser-dialog").dialog("close");
+               $("#request-input-dialog").dialog();
+               $("#request-input-dialog").dialog("close");
+                //var msecs2= Date.now();
+                //console.log("Time taken for dialog boxes:" + (msecs2 - msecs1));
+})();
+
+       function updateConfiguration(){
+               //console.log("in updateConfiguration");
+               $.get("/getCurrentSettings",function (data){
+               var dbHost = data.dbHost;
+               var dbPort = data.dbPort;
+               var dbName = data.dbName;
+               var dbUser = data.dbUser;
+               var dbPassword = data.dbPassword;
+               var gitLocalRepository = data.gitLocalRepository;
+               var performGitPull = data.performGitPull;
+
+               if(dbHost == undefined) dbHost="";
+               if(dbPort == undefined) dbPort="";
+               if(dbName == undefined) dbName="";
+               if(dbUser == undefined) dbUser="";
+               if(dbPassword == undefined) dbPassword="";
+               if(gitLocalRepository == undefined) gitLocalRepository="";
+               if(performGitPull  == undefined || performGitPull == null) performGitPull="N";
+
+               var divStyle="border: 1px solid #a1a1a1; padding: 10px 40px; background: #dddddd; width: 500px; border-radius: 25px;";
+               //var divStyle="border: 2px solid #a1a1a1; padding: 10px 40px; background: #99CCFF; width: 400px; border-radius: 25px;";
+       
+
+                  var  html = "<div>";
+                       html += "<script>function changeType(obj,targetId){if( obj.checked== true){$('#' + targetId).prop('type','password');}else{$('#'+ targetId).prop('type','text');}} function changeTitle(){ document.getElementById(\"gitLocalRepository\").title=document.getElementById(\"gitLocalRepository\").value;}</script>";
+                       html += "<div style='" + divStyle + "' >";
+                       html += "<table border='0' cellpadding='5' >";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>DB Host IP</b></td>";
+                       html += "<td><input  style='align:center;font-size:11px;font-weight:bold' id='dbhost' name='dbhost' type='text' value='" + dbHost + "'></td>";
+                       html += "</tr>";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>DB Port</b></td>";
+                       html += "<td><input style='align:center;font-size:11px;font-weight:bold' id='dbport' name='dbport' type='text' value='" + dbPort + "'></td>";
+                       html += "</tr>";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>DB Name</b></td>";
+                       html += "<td><input style='align:center;font-size:11px;font-weight:bold' id='dbname' name='dbname' type='text' value='" + dbName + "'></td>";
+                       html += "</tr>";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>DB UserName</b></td>";
+                       html += "<td><input style='align:center;font-size:11px;font-weight:bold' id='dbuser' name='dbuser' type='password' value='" + dbUser + "'></td>";
+                       html += "<td><input style='background:background:white;width:20px;height:20px' type='checkbox' checked value='1' onclick=\"changeType(this,'dbuser')\">Hide</td>";
+                       html += "</tr>";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>DB Password</b></td>";
+                       html += "<td><input style='align:center;font-size:11px;font-weight:bold' id='dbpassword' name='dbpassword' type='password' value='" + dbPassword + "'></td>";
+                       html += "<td><input style='background:background:white;width:20px;height:20px' type='checkbox' checked value='1' onclick=\"changeType(this,'dbpassword')\">Hide</td>";
+                       html += "</tr>";
+                       html += "</table>";
+                       html += "</div>";
+                       html += "<div style='fill:both;clear:both'></div><br>";
+       
+                       html += "<div style='" + divStyle + "' >";
+                       html += "<table border='0' cellpadding='5' >";
+                       html += "<tr>";
+                       html += "<td style='font-size:12px;align:center'><b>Git Local Repository Path</b></td>";
+                       html += "<td><textarea style='align:center;font-size:14px;' cols='50' rows='4' id='gitLocalRepository' name='gitLocalRepository' onkeyup='changeTitle()' title='" + gitLocalRepository + "'>" + gitLocalRepository + "</textarea></td>";
+                       html += "</tr>";
+                       html += "</table>";
+                       html += "<table border='0' cellpadding='5' >";
+                       html += "<tr>";
+                       if(performGitPull == "N"){
+                               html += "<td style='align:center;'><input style='color:blue;width:20px;height:20px;' id='performGitPull' type='checkbox' value='Y'>Perform Git Pull in Local Git Repository prior to import</td>";
+                       }else{
+                               html += "<td style='align:center;'><input style='color:blue;width:20px;height:20px;' id='performGitPull' type='checkbox' value='Y' checked>Perform Git Pull in Local Git Repository prior to import</td>";
+                       }
+                       html += "</tr>";
+                       html += "</table>";
+                       html += "</div>";
+                       html += "</div>";
+                       //console.log("html:" + html);
+               $( "#update-configuration-dialog" ).dialog({
+                       title: "Configuration",
+                       modal: true,
+                       autoOpen: true,
+                       width: 630,
+                       height: 630,
+                       buttons: [
+                               {
+                               text: "Save",
+                               click: function() {
+                                       var newDBHost = $("#dbhost").val().trim();
+                                       var newDBPort = $("#dbport").val().trim();
+                                       var newDBName = $("#dbname").val().trim();
+                                       var newDBUser = $("#dbuser").val().trim();
+                                       var newDBPassword = $("#dbpassword").val().trim();
+                                       var newGitLocalRepository = $("#gitLocalRepository").val().trim();
+                                       var isPerformGitPullChecked = $('#performGitPull').is(':checked');
+                                       var newPerformGitPull = "N";
+                                       if(isPerformGitPullChecked){
+                                               newPerformGitPull = "Y";
+                                       }
+                                       if(newDBHost == ""){
+                                               RED.notify("Error: DB Host is required.");              
+                                               $("#dbhost").focus();
+                                               return;
+                                       }else if(newDBPort == ""){
+                                               RED.notify("Error: DB Port is required.");              
+                                               $("#dbport").focus();
+                                               return;
+                                       }else if(newDBName == ""){
+                                               RED.notify("Error: DB Name is required.");              
+                                               $("#dbname").focus();
+                                               return;
+                                       }else if(newDBUser == ""){
+                                               RED.notify("Error: DB User is required.");              
+                                               $("#dbuser").focus();
+                                               return;
+                                       }else if(newDBPassword == ""){
+                                               RED.notify("Error: DB Password is required.");          
+                                               $("#dbpassword").focus();
+                                               return;
+                                       }else{ 
+                                               console.log("newGitLocalRepository:" + newGitLocalRepository);
+                                               var reqData= {"dbHost":newDBHost,
+                                                               "dbPort" : newDBPort,
+                                                               "dbName" : newDBName,
+                                                               "dbUser" : newDBUser,
+                                                               "dbPassword" : newDBPassword,
+                                                               "gitLocalRepository" : newGitLocalRepository, 
+                                                               "performGitPull" : newPerformGitPull 
+                                                            };
+                                                $.post( "/updateConfiguration",reqData )
+                                               .done(function( data ) {
+                                                        RED.notify("Configuration updated successfully"); 
+                                                       //loadSettings();
+                                                       //RED.comms.connect();
+                                                       //$( "#update-configuration-dialog" ).dialog('close');
+                                                       $("#update-configuration-dialog").dialog("close");
+                                                       //location.reload();
+                                                               
+                                               })
+                                               .fail(function(err) {
+                                                       console.log( "error" + err );
+                                                       RED.notify("Failed to update the Configuration.");
+                                               })
+                                               .always(function() {
+                                               });
+                                       }
+                                  }
+                               },
+                               {
+                                       text: "Cancel",
+                                       click: function() {
+                                               $( this ).dialog( "close" );
+                                       }
+                               }
+                       ]
+               }).html(html);
+               //$("#update-configuration-dialog").show();
+               $("#gitLocalRepository").css({"width" : 300});
+
+               });
+       }
+
+       function updatePassword(){
+               var html="<div>";
+                       html += "<div><span><b>New Password</b></span><br>";
+                       html += "<input id='passwd1' name='passwd1' type='password' value=''>";
+                       html += "</div>";
+                       html += "<div><span><b>Confirm Password</b></span><br>";
+                       html += "<input id='passwd2' name='passwd2' type='password' value=''>";
+                       html += "</div>";
+               $( "#update-password-dialog" ).dialog({
+                       title: "Update Password",
+                       modal: true,
+                       autoOpen: true,
+                       width: 530,
+                       height: 230,
+                       buttons: [
+                               {
+                               text: "Update Password",
+                               click: function() {
+                                       var passwd1 = $("#passwd1").val().trim();
+                                       var passwd2 = $("#passwd2").val().trim();
+                                       if((passwd1 != passwd2) || (passwd1 == "" || passwd2 == "")){
+                                               RED.notify("Error:Passwords entered must be same and must be populated.");              
+                                               return;
+                                       }else{ 
+                                               var reqData= {"password":passwd1};
+                                                $.post( "/updatePassword",reqData )
+                                               .done(function( data ) {
+                                                        RED.notify("Password updated successfully"); 
+                                                       //loadSettings();
+                                                       $( "#update-password-dialog" ).dialog('close');
+                                               })
+                                               .fail(function(err) {
+                                                       console.log( "error" + err );
+                                                       RED.notify("Failed to update the password.");
+                                               })
+                                               .always(function() {
+                                               });
+                                       }
+                                  }
+                               },
+                               {
+                                       text: "Cancel",
+                                       click: function() {
+                                               $( this ).dialog( "close" );
+                                       }
+                               }
+                       ]
+               }).html(html);
+               $("#update-password-dialog").show();
+
+       }
+
+       function  showAvailableYangModules(){
+               availableYangModules=[];
+               var divStyle="<style>#yang-modules-data-container a { color: #067ab4; font-size: 0.75em;} #yang-modules-data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } table#yang-list-table { width:100%; } table#yang-list-table th,table#yang-list-table td { border: 1px solid black; border-collapse: collapse; } table#yang-list-table th,table#yang-list-table td { padding: 5px; text-align: left; } table#yang-list-table tr:nth-child(even) { background-color: #eee; } table#yang-list-table tr:nth-child(odd) { background-color:#fff; } table#yang-list-table th        { background-color: #65a9d7; color: white; } table#yang-list-table a { color: #337ab7; } table#yang-list-table a:link { color: #65a9d7; } table#yang-list-table a:visited { color: #636; } table#yang-list-table a:hover { color: #3366CC; cursor: pointer } table#yang-list-table a:active { color: #65a9d7 }</style>";
+               $.get( "/listAvailableModules")
+                               .done(function( data ) {
+                                       var header="<div class='header'>List of Available Yang Modules</div>";
+                                       header += "<div><p><i>Check the modules that you want to load and click on the Load button.</i></p></div>";     
+                                       //header += "<div><input id='yangModuleFilterBoxId' type='text' onkeyup='filterYangModules(this.value)'></div>";
+                                       var html=  divStyle + header +  "<div id='yang-modules-data-container'>";
+                                       html+="<table id='yang-list-table'  border=1>";
+                                       html+="<tr>";
+                                       html+="<th>#</th>";
+                                       html+="<th>Load</th>";
+                                       html+="<th>Module</th>";
+                                       html+="</tr>";
+                                       if(data != null){
+                                               var files=data.files;
+                                               availableYangModules=files;
+                                               //console.dir(files);
+                                               files.sort(function (a,b){
+                                                       if(a > b){
+                                                               return 1;
+                                                       }else if(a <  b){
+                                                               return -1;
+                                                       }else{  
+                                                               return 0;
+                                                       }
+                                               });
+                                               var count=1;
+                                               for(var i=0;files != null && i<files.length;i++){
+                                                       var val = files[i].replace(/:.*/,"");
+                                                       if(files[i].indexOf(":checked") != -1){
+                                                               html+="<tr><td>" + count + "</td><td><input type='checkbox' checked value='" + val + "'></td><td>" + val + "</td></tr>";
+                                                       }else{
+                                                               html+="<tr><td>" + count + "</td><td><input type='checkbox' value='" + val + "'></td><td>" + val + "</td></tr>";
+                                                       }
+                                                       count++;
+                                               }
+                                       }
+                                       html+="</table>";
+                                       html+="</div>";
+                                       $( "#yang-modules-browser-dialog" ).dialog({
+                                       title: "Available Yang Modules",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 830,
+                                       height: 630,
+                                       buttons: [
+                                               {
+                                                       text: "Load",
+                                                       click: function() {
+                                                               var allVals = [];
+                                                               function getValuesForSelected() {         
+                                                                       $('#yang-modules-data-container :checked').each(function() {
+                                                                                       allVals.push($(this).val());
+                                                                       });
+                                                                       return allVals;
+                                                               }
+                                                               var selectedModules = getValuesForSelected().toString();
+                                                               console.log(selectedModules);
+                                                               $.ajax({
+                                                                       type: 'GET',
+                                                                       /*contentType: "application/x-www-form-urlencoded",*/
+                                                                       url: '/loadSelectedModules?selectedModules=' + selectedModules,
+                                                                       success: function(data) {
+                                                                               RED.notify("Modules Loaded successfully"); 
+                                                                               //emptying existing g;obal variables
+                                                                               sliValuesObj = {};
+                                                                               rpcValues = {};
+                                                                               reqInputValues = {};
+
+                                                                               if(data != undefined && data != null){
+                                                                                       for(var i=0;i<data.sliValuesObj.length;i++){
+                                                                                               var moduleName = data.sliValuesObj[i].moduleName;
+                                                                                               sliValuesObj[moduleName] = data.sliValuesObj[i][moduleName + '_PROPS'];
+                                                                                               rpcValues[moduleName] = data.sliValuesObj[i][ moduleName +'_RPCS'];
+                                                                                               for(var k=0;rpcValues[moduleName] != undefined && k<rpcValues[moduleName].length;k++){
+                                                                                                       var rpcName = rpcValues[moduleName][k];
+                                                                                                       reqInputValues[moduleName + "_" + rpcName] = data.sliValuesObj[i][rpcName +"-input"];
+                                                                                                       //console.dir(reqInputValues);
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                               $( "#yang-modules-browser-dialog" ).dialog('close');
+                                                                               console.log('success');
+                                                                               //console.log(JSON.stringify(data));                               
+                                                                       },
+                                                                       error: function(error) {
+                                                                               RED.notify("Failed to load modules.");
+                                                                               console.log("some error in fetching the notifications");
+                                                                       }
+                                                               });     
+                                                       }
+                                               },
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $(this).dialog("close");
+                                                       }
+                                               }
+                                               ]
+                                       }).html(html);
+                                       $("#yang-modules-browser-dialog").show();
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get yang modules.");
+                                })
+                                 .always(function() {
+                                       console.log("Done displaying");
+                               });
+       }
+
+
+    $(function() {
+        RED.menu.init({id:"btn-sidemenu",
+            options: [
+                {id:"btn-sidebar",icon:"fa fa-columns",label:"Sidebar   (Ctrl+Space)",toggle:true,onselect:RED.sidebar.toggleSidebar},
+                null,
+                {id:"btn-manage-yang-modules-menu",icon:"fa fa-sign-in",label:"Manage Yang Modules",options:[
+                    {id:"btn-yang-upload",icon:"fa fa-clipboard",label:"Upload Yang File",onselect:RED.view.showYangUploadDialog},
+                    {id:"btn-available-yang-modules",icon:"fa fa-clipboard",label:"Available Yang Modules",onselect:showAvailableYangModules},
+                    {id:"btn-list-yang-files",icon:"fa fa-clipboard",label:"List Yang Files",onselect:listYangFiles},
+                ]},
+                null,
+                {id:"btn-configure-upload",icon:"fa fa-book",label:"Configuration",toggle:false,onselect:updateConfiguration},
+                null,
+                {id:"btn-manage-tabs",icon:"fa fa-info",label:"Manage Tabs",toggle:false,onselect:showSelectedTabs},
+                null,
+                {id:"btn-search-text",icon:"fa fa-info",label:"Search Text (Ctrl+[)",toggle:false,onselect:RED.view.showSearchTextDialog},
+                null,
+                {id:"btn-find-dgnumber",icon:"fa fa-info",label:"Find Node (Ctrl+B)",toggle:false,onselect:RED.view.showDgNumberDialog},
+                null,
+               {id:"btn-request-input",icon:"fa fa-info",label:"RPC Input (Ctrl+O)",toggle:false,onselect:RED.view.showRequestTemplateDialog},
+                null,
+                {id:"btn-node-status",icon:"fa fa-info",label:"Node Status",toggle:true,onselect:toggleStatus},
+                null,
+                {id:"btn-node-dgnumber",icon:"fa fa-info",label:"Show Node Numbers",toggle:true,onselect:toggleDgNumberDisplay},
+                null,
+                {id:"btn-node-panel",icon:"fa fa-columns",label:"Node Palette (Ctrl+M)",toggle:true,onselect:toggleNodePaletteDisplay},
+                null,
+                {id:"btn-node-viewdgs",icon:"fa fa-info",label:"View All DG List",toggle:false,onselect:displayAllDGs},
+                null,
+               /*
+                {id:"btn-node-gitmenu",icon:"fa fa-info",label:"Git Commands",options: [
+                    {id:"btn-node-gitcheckout",icon:"fa fa-info",label:"Git Checkout",onselect:showGitCheckoutDialog},
+                    {id:"btn-node-gitpull",icon:"fa fa-info",label:"Git Pull",onselect:showGitPullDialog},
+                    {id:"btn-node-gitstatus",icon:"fa fa-info",label:"Git Status",onselect:showGitStatusDialog}
+                ]},
+                null,
+               */
+                {id:"btn-import-menu",icon:"fa fa-sign-in",label:"Import...",options:[
+                    /*{id:"btn-import-codecloud",icon:"fa fa-clipboard",label:"Code Cloud",onselect:showCodeCloudFlows},
+                       */
+                    {id:"btn-import-codecloud",icon:"fa fa-clipboard",label:"Git Local Repository",onselect:showGitLocalFlows},
+                    {id:"btn-import-userflows",icon:"fa fa-clipboard",label:"Downloaded DG Flows...",onselect:showFlowShareUsers},
+                    {id:"btn-import-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",onselect:RED.view.showImportNodesDialog},
+                    {id:"btn-import-library",icon:"fa fa-book",label:"Library",options:[]}
+                ]},
+                {id:"btn-export-menu",icon:"fa fa-sign-out",label:"Export...",disabled:true,options:[
+                    {id:"btn-export-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",disabled:true,onselect:RED.view.showExportNodesDialog},
+                    {id:"btn-export-library",icon:"fa fa-book",label:"Library...",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
+                ]},
+                null,
+                {id:"btn-change-password",icon:"fa fa-columns",label:"Change Password",toggle:false,onselect:updatePassword},
+                null,
+                /*{id:"btn-config-nodes",icon:"fa fa-th-list",label:"Configuration nodes...",onselect:RED.sidebar.config.show},
+                null,*/
+                {id:"btn-workspace-menu",icon:"fa fa-th-large",label:"Workspaces",options:[
+                    {id:"btn-workspace-add",icon:"fa fa-plus",label:"Add"},
+                    {id:"btn-workspace-edit",icon:"fa fa-pencil",label:"Rename"},
+                    {id:"btn-workspace-delete",icon:"fa fa-minus",label:"Delete"},
+                    null
+                ]},
+                null,
+                {id:"btn-keyboard-shortcuts",icon:"fa fa-keyboard-o",label:"Keyboard Shortcuts",onselect:showHelp}
+                /*{id:"btn-help",icon:"fa fa-question",label:"Help...", href:"http://nodered.org/docs"}*/
+            ]
+        });
+
+       //Making default loop detection on and display check mark in the menu
+       //$("#btn-loop-detection").addClass("active");
+
+        RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();});
+        loadSettings();
+        RED.comms.connect();
+    });
+
+    return {
+    };
+})();
diff --git a/dgbuilder/public/red/main.js.orig b/dgbuilder/public/red/main.js.orig
new file mode 100644 (file)
index 0000000..a47e995
--- /dev/null
@@ -0,0 +1,323 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var RED = (function() {
+
+    function hideDropTarget() {
+        $("#dropTarget").hide();
+        RED.keyboard.remove(/* ESCAPE */ 27);
+    }
+
+    $('#chart').on("dragenter",function(event) {
+        if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
+            $("#dropTarget").css({display:'table'});
+            RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
+        }
+    });
+
+    $('#dropTarget').on("dragover",function(event) {
+        if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
+            event.preventDefault();
+        }
+    })
+    .on("dragleave",function(event) {
+        hideDropTarget();
+    })
+    .on("drop",function(event) {
+        var data = event.originalEvent.dataTransfer.getData("text/plain");
+        hideDropTarget();
+        RED.view.importNodes(data);
+        event.preventDefault();
+    });
+
+    function save(force) {
+        if (RED.view.dirty()) {
+            //$("#debug-tab-clear").click();  // uncomment this to auto clear debug on deploy
+
+            if (!force) {
+                var invalid = false;
+                var unknownNodes = [];
+                RED.nodes.eachNode(function(node) {
+                    invalid = invalid || !node.valid;
+                    if (node.type === "unknown") {
+                        if (unknownNodes.indexOf(node.name) == -1) {
+                            unknownNodes.push(node.name);
+                        }
+                        invalid = true;
+                    }
+                });
+                if (invalid) {
+                    if (unknownNodes.length > 0) {
+                        $( "#node-dialog-confirm-deploy-config" ).hide();
+                        $( "#node-dialog-confirm-deploy-unknown" ).show();
+                        var list = "<li>"+unknownNodes.join("</li><li>")+"</li>";
+                        $( "#node-dialog-confirm-deploy-unknown-list" ).html(list);
+                    } else {
+                        $( "#node-dialog-confirm-deploy-config" ).show();
+                        $( "#node-dialog-confirm-deploy-unknown" ).hide();
+                    }
+                    $( "#node-dialog-confirm-deploy" ).dialog( "open" );
+                    return;
+                }
+            }
+            var nns = RED.nodes.createCompleteNodeSet();
+
+            $("#btn-icn-deploy").removeClass('fa-download');
+            $("#btn-icn-deploy").addClass('spinner');
+            RED.view.dirty(false);
+
+            $.ajax({
+                url:"flows",
+                type: "POST",
+                data: JSON.stringify(nns),
+                contentType: "application/json; charset=utf-8"
+            }).done(function(data,textStatus,xhr) {
+                RED.notify("Successfully deployed","success");
+                RED.nodes.eachNode(function(node) {
+                    if (node.changed) {
+                        node.dirty = true;
+                        node.changed = false;
+                    }
+                    if(node.credentials) {
+                        delete node.credentials;
+                    }
+                });
+                RED.nodes.eachConfig(function (confNode) {
+                    if (confNode.credentials) {
+                        delete confNode.credentials;
+                    }
+                });
+                // Once deployed, cannot undo back to a clean state
+                RED.history.markAllDirty();
+                RED.view.redraw();
+            }).fail(function(xhr,textStatus,err) {
+                RED.view.dirty(true);
+                if (xhr.responseText) {
+                    RED.notify("<strong>Error</strong>: "+xhr.responseText,"error");
+                } else {
+                    RED.notify("<strong>Error</strong>: no response from server","error");
+                }
+            }).always(function() {
+                $("#btn-icn-deploy").removeClass('spinner');
+                $("#btn-icn-deploy").addClass('fa-download');
+            });
+        }
+    }
+
+    $('#btn-deploy').click(function() { save(); });
+
+    $( "#node-dialog-confirm-deploy" ).dialog({
+            title: "Confirm deploy",
+            modal: true,
+            autoOpen: false,
+            width: 530,
+            height: 230,
+            buttons: [
+                {
+                    text: "Confirm deploy",
+                    click: function() {
+                        save(true);
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ]
+    });
+
+    function loadSettings() {
+        $.get('settings', function(data) {
+            RED.settings = data;
+            console.log("Node-RED: "+data.version);
+            loadNodeList();
+        });
+    }
+    function loadNodeList() {
+        $.ajax({
+            headers: {
+                "Accept":"application/json"
+            },
+            cache: false,
+            url: 'nodes',
+            success: function(data) {
+                RED.nodes.setNodeList(data);
+                loadNodes();
+            }
+        });
+    }
+
+    function loadNodes() {
+        $.ajax({
+            headers: {
+                "Accept":"text/html"
+            },
+            cache: false,
+            url: 'nodes',
+            success: function(data) {
+                $("body").append(data);
+                $(".palette-spinner").hide();
+                $(".palette-scroll").show();
+                $("#palette-search").show();
+                loadFlows();
+            }
+        });
+    }
+
+    function loadFlows() {
+        $.ajax({
+            headers: {
+                "Accept":"application/json"
+            },
+            cache: false,
+            url: 'flows',
+            success: function(nodes) {
+                RED.nodes.import(nodes);
+                RED.view.dirty(false);
+                RED.view.redraw();
+                RED.comms.subscribe("status/#",function(topic,msg) {
+                    var parts = topic.split("/");
+                    var node = RED.nodes.node(parts[1]);
+                    if (node) {
+                        node.status = msg;
+                        if (statusEnabled) {
+                            node.dirty = true;
+                            RED.view.redraw();
+                        }
+                    }
+                });
+                RED.comms.subscribe("node/#",function(topic,msg) {
+                    var i,m;
+                    var typeList;
+                    var info;
+                    
+                    if (topic == "node/added") {
+                        var addedTypes = [];
+                        for (i=0;i<msg.length;i++) {
+                            m = msg[i];
+                            var id = m.id;
+                            RED.nodes.addNodeSet(m);
+                            if (m.loaded) {
+                                addedTypes = addedTypes.concat(m.types);
+                                $.get('nodes/'+id, function(data) {
+                                    $("body").append(data);
+                                });
+                            }
+                        }
+                        if (addedTypes.length) {
+                            typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
+                            RED.notify("Node"+(addedTypes.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
+                        }
+                    } else if (topic == "node/removed") {
+                        for (i=0;i<msg.length;i++) {
+                            m = msg[i];
+                            info = RED.nodes.removeNodeSet(m.id);
+                            if (info.added) {
+                                typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
+                                RED.notify("Node"+(m.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
+                            }
+                        }
+                    } else if (topic == "node/enabled") {
+                        if (msg.types) {
+                            info = RED.nodes.getNodeSet(msg.id);
+                            if (info.added) {
+                                RED.nodes.enableNodeSet(msg.id);
+                                typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                                RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" enabled:"+typeList,"success");
+                            } else {
+                                $.get('nodes/'+msg.id, function(data) {
+                                    $("body").append(data);
+                                    typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                                    RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
+                                });
+                            } 
+                        }
+                    } else if (topic == "node/disabled") {
+                        if (msg.types) {
+                            RED.nodes.disableNodeSet(msg.id);
+                            typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
+                            RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" disabled:"+typeList,"success");
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+    var statusEnabled = false;
+    function toggleStatus(state) {
+        statusEnabled = state;
+        RED.view.status(statusEnabled);
+    }
+
+    function showHelp() {
+
+        var dialog = $('#node-help');
+
+        //$("#node-help").draggable({
+        //        handle: ".modal-header"
+        //});
+
+        dialog.on('show',function() {
+            RED.keyboard.disable();
+        });
+        dialog.on('hidden',function() {
+            RED.keyboard.enable();
+        });
+
+        dialog.modal();
+    }
+
+    $(function() {
+        RED.menu.init({id:"btn-sidemenu",
+            options: [
+                {id:"btn-sidebar",icon:"fa fa-columns",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar},
+                null,
+                {id:"btn-node-status",icon:"fa fa-info",label:"Node Status",toggle:true,onselect:toggleStatus},
+                null,
+                {id:"btn-import-menu",icon:"fa fa-sign-in",label:"Import...",options:[
+                    {id:"btn-import-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",onselect:RED.view.showImportNodesDialog},
+                    {id:"btn-import-library",icon:"fa fa-book",label:"Library",options:[]}
+                ]},
+                {id:"btn-export-menu",icon:"fa fa-sign-out",label:"Export...",disabled:true,options:[
+                    {id:"btn-export-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",disabled:true,onselect:RED.view.showExportNodesDialog},
+                    {id:"btn-export-library",icon:"fa fa-book",label:"Library...",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
+                ]},
+                null,
+                {id:"btn-config-nodes",icon:"fa fa-th-list",label:"Configuration nodes...",onselect:RED.sidebar.config.show},
+                null,
+                {id:"btn-workspace-menu",icon:"fa fa-th-large",label:"Workspaces",options:[
+                    {id:"btn-workspace-add",icon:"fa fa-plus",label:"Add"},
+                    {id:"btn-workspace-edit",icon:"fa fa-pencil",label:"Rename"},
+                    {id:"btn-workspace-delete",icon:"fa fa-minus",label:"Delete"},
+                    null
+                ]},
+                null,
+                {id:"btn-keyboard-shortcuts",icon:"fa fa-keyboard-o",label:"Keyboard Shortcuts",onselect:showHelp},
+                {id:"btn-help",icon:"fa fa-question",label:"Help...", href:"http://nodered.org/docs"}
+            ]
+        });
+
+        RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();});
+        loadSettings();
+        RED.comms.connect();
+    });
+
+    return {
+    };
+})();
diff --git a/dgbuilder/public/red/nodes.js b/dgbuilder/public/red/nodes.js
new file mode 100644 (file)
index 0000000..dc0827a
--- /dev/null
@@ -0,0 +1,553 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.nodes = (function() {
+
+    var node_defs = {};
+    var nodes = [];
+    var configNodes = {};
+    var links = [];
+    var defaultWorkspace;
+    var workspaces = {};
+    
+    var registry = (function() {
+        var nodeList = [];
+        var nodeSets = {};
+        var typeToId = {};
+        var nodeDefinitions = {};
+        
+        var exports = {
+            getNodeList: function() {
+                return nodeList;
+            },
+            setNodeList: function(list) {
+                nodeList = [];
+                for(var i=0;i<list.length;i++) {
+                    var ns = list[i];
+                    exports.addNodeSet(ns);
+                }
+            },
+            addNodeSet: function(ns) {
+                ns.added = false;
+                nodeSets[ns.id] = ns;
+                for (var j=0;j<ns.types.length;j++) {
+                    typeToId[ns.types[j]] = ns.id;
+                }
+                nodeList.push(ns);
+            },
+            removeNodeSet: function(id) {
+                var ns = nodeSets[id];
+                for (var j=0;j<ns.types.length;j++) {
+                    if (ns.added) {
+                        // TODO: too tightly coupled into palette UI
+                        RED.palette.remove(ns.types[j]);
+                        var def = nodeDefinitions[ns.types[j]];
+                        if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
+                            def.onpaletteremove.call(def);
+                        }
+                    }
+                    delete typeToId[ns.types[j]];
+                }
+                delete nodeSets[id];
+                for (var i=0;i<nodeList.length;i++) {
+                    if (nodeList[i].id == id) {
+                        nodeList.splice(i,1);
+                        break;
+                    }
+                }
+                return ns;
+            },
+            getNodeSet: function(id) {
+                return nodeSets[id];
+            },
+            enableNodeSet: function(id) {
+                var ns = nodeSets[id];
+                ns.enabled = true;
+                for (var j=0;j<ns.types.length;j++) {
+                    // TODO: too tightly coupled into palette UI
+                    RED.palette.show(ns.types[j]);
+                    var def = nodeDefinitions[ns.types[j]];
+                    if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
+                        def.onpaletteadd.call(def);
+                    }
+                }
+            },
+            disableNodeSet: function(id) {
+                var ns = nodeSets[id];
+                ns.enabled = false;
+                for (var j=0;j<ns.types.length;j++) {
+                    // TODO: too tightly coupled into palette UI
+                    RED.palette.hide(ns.types[j]);
+                    var def = nodeDefinitions[ns.types[j]];
+                    if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
+                        def.onpaletteremove.call(def);
+                    }
+                }
+            },
+            registerNodeType: function(nt,def) {
+                nodeDefinitions[nt] = def;
+                nodeSets[typeToId[nt]].added = true;
+                // TODO: too tightly coupled into palette UI
+                RED.palette.add(nt,def);
+                if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
+                    def.onpaletteadd.call(def);
+                }
+            },
+            getNodeType: function(nt) {
+                return nodeDefinitions[nt];
+            }
+        };
+        return exports;
+    })();
+    
+    function getID() {
+        return (1+Math.random()*4294967295).toString(16);
+    }
+
+    function addNode(n) {
+        if (n._def.category == "config") {
+            configNodes[n.id] = n;
+            RED.sidebar.config.refresh();
+        } else {
+            n.dirty = true;
+            nodes.push(n);
+            var updatedConfigNode = false;
+            for (var d in n._def.defaults) {
+                if (n._def.defaults.hasOwnProperty(d)) {
+                    var property = n._def.defaults[d];
+                    if (property.type) {
+                        var type = registry.getNodeType(property.type);
+                        if (type && type.category == "config") {
+                            var configNode = configNodes[n[d]];
+                            if (configNode) {
+                                updatedConfigNode = true;
+                                configNode.users.push(n);
+                            }
+                        }
+                    }
+                }
+            }
+            if (updatedConfigNode) {
+                RED.sidebar.config.refresh();
+            }
+        }
+    }
+    function addLink(l) {
+        links.push(l);
+    }
+    function addConfig(c) {
+        configNodes[c.id] = c;
+    }
+
+    function getNode(id) {
+        if (id in configNodes) {
+            return configNodes[id];
+        } else {
+            for (var n in nodes) {
+                if (nodes[n].id == id) {
+                    return nodes[n];
+                }
+            }
+        }
+        return null;
+    }
+
+    function removeNode(id) {
+        var removedLinks = [];
+        if (id in configNodes) {
+            delete configNodes[id];
+            RED.sidebar.config.refresh();
+        } else {
+            var node = getNode(id);
+            if (node) {
+                nodes.splice(nodes.indexOf(node),1);
+                removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
+                removedLinks.map(function(l) {links.splice(links.indexOf(l), 1); });
+            }
+            var updatedConfigNode = false;
+            for (var d in node._def.defaults) {
+                if (node._def.defaults.hasOwnProperty(d)) {
+                    var property = node._def.defaults[d];
+                    if (property.type) {
+                        var type = registry.getNodeType(property.type);
+                        if (type && type.category == "config") {
+                            var configNode = configNodes[node[d]];
+                            if (configNode) {
+                                updatedConfigNode = true;
+                                var users = configNode.users;
+                                users.splice(users.indexOf(node),1);
+                            }
+                        }
+                    }
+                }
+            }
+            if (updatedConfigNode) {
+                RED.sidebar.config.refresh();
+            }
+        }
+        return removedLinks;
+    }
+
+    function removeLink(l) {
+        var index = links.indexOf(l);
+        if (index != -1) {
+            links.splice(index,1);
+        }
+    }
+
+    function refreshValidation() {
+        for (var n=0;n<nodes.length;n++) {
+            RED.editor.validateNode(nodes[n]);
+        }
+    }
+
+    function addWorkspace(ws) {
+        workspaces[ws.id] = ws;
+    }
+    function getWorkspace(id) {
+        return workspaces[id];
+    }
+    function removeWorkspace(id) {
+        delete workspaces[id];
+        var removedNodes = [];
+        var removedLinks = [];
+        var n;
+        for (n=0;n<nodes.length;n++) {
+            var node = nodes[n];
+            if (node.z == id) {
+                removedNodes.push(node);
+            }
+        }
+        for (n=0;n<removedNodes.length;n++) {
+            var rmlinks = removeNode(removedNodes[n].id);
+            removedLinks = removedLinks.concat(rmlinks);
+        }
+        return {nodes:removedNodes,links:removedLinks};
+    }
+
+    function getAllFlowNodes(node) {
+        var visited = {};
+        visited[node.id] = true;
+        var nns = [node];
+        var stack = [node];
+        while(stack.length !== 0) {
+            var n = stack.shift();
+            var childLinks = links.filter(function(d) { return (d.source === n) || (d.target === n);});
+            for (var i=0;i<childLinks.length;i++) {
+                var child = (childLinks[i].source === n)?childLinks[i].target:childLinks[i].source;
+                if (!visited[child.id]) {
+                    visited[child.id] = true;
+                    nns.push(child);
+                    stack.push(child);
+                }
+            }
+        }
+        return nns;
+    }
+
+    /**
+     * Converts a node to an exportable JSON Object
+     **/
+    function convertNode(n, exportCreds) {
+        exportCreds = exportCreds || false;
+        var node = {};
+        node.id = n.id;
+        node.type = n.type;
+        for (var d in n._def.defaults) {
+            if (n._def.defaults.hasOwnProperty(d)) {
+                node[d] = n[d];
+            }
+        }
+        if(exportCreds && n.credentials) {
+            node.credentials = {};
+            for (var cred in n._def.credentials) {
+                if (n._def.credentials.hasOwnProperty(cred)) {
+                    if (n.credentials[cred] != null) {
+                        node.credentials[cred] = n.credentials[cred];
+                    }
+                }
+            }
+        }
+        if (n._def.category != "config") {
+            node.x = n.x;
+            node.y = n.y;
+            node.z = n.z;
+            node.wires = [];
+            for(var i=0;i<n.outputs;i++) {
+                node.wires.push([]);
+            }
+            var wires = links.filter(function(d){return d.source === n;});
+            for (var j=0;j<wires.length;j++) {
+                var w = wires[j];
+                node.wires[w.sourcePort].push(w.target.id);
+            }
+        }
+        return node;
+    }
+
+    /**
+     * Converts the current node selection to an exportable JSON Object
+     **/
+    function createExportableNodeSet(set) {
+        var nns = [];
+        var exportedConfigNodes = {};
+        for (var n=0;n<set.length;n++) {
+            var node = set[n].n;
+            var convertedNode = RED.nodes.convertNode(node);
+            for (var d in node._def.defaults) {
+                if (node._def.defaults[d].type && node[d] in configNodes) {
+                    var confNode = configNodes[node[d]];
+                    var exportable = registry.getNodeType(node._def.defaults[d].type).exportable;
+                    if ((exportable == null || exportable)) {
+                        if (!(node[d] in exportedConfigNodes)) {
+                            exportedConfigNodes[node[d]] = true;
+                            nns.unshift(RED.nodes.convertNode(confNode));
+                        }
+                    } else {
+                        convertedNode[d] = "";
+                    }
+                }
+            }
+
+            nns.push(convertedNode);
+        }
+        return nns;
+    }
+
+    //TODO: rename this (createCompleteNodeSet)
+    function createCompleteNodeSet() {
+        var nns = [];
+        var i;
+        for (i in workspaces) {
+            if (workspaces.hasOwnProperty(i)) {
+                nns.push(workspaces[i]);
+            }
+        }
+        for (i in configNodes) {
+            if (configNodes.hasOwnProperty(i)) {
+                nns.push(convertNode(configNodes[i], true));
+            }
+        }
+        for (i=0;i<nodes.length;i++) {
+            var node = nodes[i];
+            nns.push(convertNode(node, true));
+        }
+        return nns;
+    }
+
+    function importNodes(newNodesObj,createNewIds) {
+        try {
+            var i;
+            var n;
+            var newNodes;
+            if (typeof newNodesObj === "string") {
+                if (newNodesObj === "") {
+                    return;
+                }
+                newNodes = JSON.parse(newNodesObj);
+            } else {
+                newNodes = newNodesObj;
+            }
+
+            if (!$.isArray(newNodes)) {
+                newNodes = [newNodes];
+            }
+            var unknownTypes = [];
+            for (i=0;i<newNodes.length;i++) {
+                n = newNodes[i];
+                // TODO: remove workspace in next release+1
+                if (n.type != "workspace" && n.type != "tab" && !registry.getNodeType(n.type)) {
+                    // TODO: get this UI thing out of here! (see below as well)
+                    n.name = n.type;
+                    n.type = "unknown";
+                    if (unknownTypes.indexOf(n.name)==-1) {
+                        unknownTypes.push(n.name);
+                    }
+                    if (n.x == null && n.y == null) {
+                        // config node - remove it
+                        newNodes.splice(i,1);
+                        i--;
+                    }
+                }
+            }
+            if (unknownTypes.length > 0) {
+                var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
+                var type = "type"+(unknownTypes.length > 1?"s":"");
+                RED.notify("<strong>Imported unrecognised "+type+":</strong>"+typeList,"error",false,10000);
+                //"DO NOT DEPLOY while in this state.<br/>Either, add missing types to Node-RED, restart and then reload page,<br/>or delete unknown "+n.name+", rewire as required, and then deploy.","error");
+            }
+
+            var new_workspaces = [];
+            var workspace_map = {};
+            
+            for (i=0;i<newNodes.length;i++) {
+                n = newNodes[i];
+                // TODO: remove workspace in next release+1
+                if (n.type === "workspace" || n.type === "tab") {
+                    if (n.type === "workspace") {
+                        n.type = "tab";
+                    }
+                    if (defaultWorkspace == null) {
+                        defaultWorkspace = n;
+                    }
+                    if (createNewIds) {
+                        var nid = getID();
+                        workspace_map[n.id] = nid;
+                        n.id = nid;
+                    }
+                    addWorkspace(n);
+                    RED.view.addWorkspace(n);
+                    new_workspaces.push(n);
+                }
+            }
+            if (defaultWorkspace == null) {
+                defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
+                addWorkspace(defaultWorkspace);
+                RED.view.addWorkspace(defaultWorkspace);
+                new_workspaces.push(defaultWorkspace);
+            }
+
+            var node_map = {};
+            var new_nodes = [];
+            var new_links = [];
+
+            for (i=0;i<newNodes.length;i++) {
+                n = newNodes[i];
+                // TODO: remove workspace in next release+1
+                if (n.type !== "workspace" && n.type !== "tab") {
+                    var def = registry.getNodeType(n.type);
+                    if (def && def.category == "config") {
+                        if (!RED.nodes.node(n.id)) {
+                            var configNode = {id:n.id,type:n.type,users:[]};
+                            for (var d in def.defaults) {
+                                if (def.defaults.hasOwnProperty(d)) {
+                                    configNode[d] = n[d];
+                                }
+                            }
+                            configNode.label = def.label;
+                            configNode._def = def;
+                            RED.nodes.add(configNode);
+                        }
+                    } else {
+                        var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
+                        if (createNewIds) {
+                            node.z = workspace_map[node.z];
+                            if (!workspaces[node.z]) {
+                                node.z = RED.view.getWorkspace();
+                            }
+                            node.id = getID();
+                        } else {
+                            node.id = n.id;
+                            if (node.z == null || !workspaces[node.z]) {
+                                node.z = RED.view.getWorkspace();
+                            }
+                        }
+                        node.type = n.type;
+                        node._def = def;
+                        if (!node._def) {
+                            node._def = {
+                                color:"#fee",
+                                defaults: {},
+                                label: "unknown: "+n.type,
+                                labelStyle: "node_label_italic",
+                                outputs: n.outputs||n.wires.length
+                            }
+                        }
+                        node.outputs = n.outputs||node._def.outputs;
+
+                        for (var d2 in node._def.defaults) {
+                            if (node._def.defaults.hasOwnProperty(d2)) {
+                                node[d2] = n[d2];
+                            }
+                        }
+
+                        addNode(node);
+                        RED.editor.validateNode(node);
+                        node_map[n.id] = node;
+                        new_nodes.push(node);
+                    }
+                }
+            }
+            for (i=0;i<new_nodes.length;i++) {
+                n = new_nodes[i];
+                for (var w1=0;w1<n.wires.length;w1++) {
+                    var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
+                    for (var w2=0;w2<wires.length;w2++) {
+                        if (wires[w2] in node_map) {
+                            var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
+                            addLink(link);
+                            new_links.push(link);
+                        }
+                    }
+                }
+                delete n.wires;
+            }
+            return [new_nodes,new_links,new_workspaces];
+        } catch(error) {
+            //TODO: get this UI thing out of here! (see above as well)
+            RED.notify("<strong>Error</strong>: "+error,"error");
+            return null;
+        }
+
+    }
+
+    return {
+        registry:registry,
+        setNodeList: registry.setNodeList,
+        
+        getNodeSet: registry.getNodeSet,
+        addNodeSet: registry.addNodeSet,
+        removeNodeSet: registry.removeNodeSet,
+        enableNodeSet: registry.enableNodeSet,
+        disableNodeSet: registry.disableNodeSet,
+        
+        registerType: registry.registerNodeType,
+        getType: registry.getNodeType,
+        convertNode: convertNode,
+        add: addNode,
+        addLink: addLink,
+        remove: removeNode,
+        removeLink: removeLink,
+        addWorkspace: addWorkspace,
+        removeWorkspace: removeWorkspace,
+        workspace: getWorkspace,
+        eachNode: function(cb) {
+            for (var n=0;n<nodes.length;n++) {
+                cb(nodes[n]);
+            }
+        },
+        eachLink: function(cb) {
+            for (var l=0;l<links.length;l++) {
+                cb(links[l]);
+            }
+        },
+        eachConfig: function(cb) {
+            for (var id in configNodes) {
+                if (configNodes.hasOwnProperty(id)) {
+                    cb(configNodes[id]);
+                }
+            }
+        },
+        node: getNode,
+        import: importNodes,
+        refreshValidation: refreshValidation,
+        getAllFlowNodes: getAllFlowNodes,
+        createExportableNodeSet: createExportableNodeSet,
+        createCompleteNodeSet: createCompleteNodeSet,
+        id: getID,
+        nodes: nodes, // TODO: exposed for d3 vis
+        links: links  // TODO: exposed for d3 vis
+    };
+})();
diff --git a/dgbuilder/public/red/ui/editor.js b/dgbuilder/public/red/ui/editor.js
new file mode 100644 (file)
index 0000000..c5f7986
--- /dev/null
@@ -0,0 +1,665 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.editor = (function() {
+    var editing_node = null;
+    // TODO: should IMPORT/EXPORT get their own dialogs?
+
+    function getCredentialsURL(nodeType, nodeID) {
+        var dashedType = nodeType.replace(/\s+/g, '-');
+        return  'credentials/' + dashedType + "/" + nodeID;
+    }
+
+    /**
+     * Validate a node 
+     * @param node - the node being validated
+     * @returns {boolean} whether the node is valid. Sets node.dirty if needed
+     */
+    function validateNode(node) {
+        var oldValue = node.valid;
+        node.valid = validateNodeProperties(node, node._def.defaults, node);
+        if (node._def._creds) {
+            node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds);
+        }
+        if (oldValue != node.valid) {
+            node.dirty = true;
+        }
+    }
+    
+    /**
+     * Validate a node's properties for the given set of property definitions
+     * @param node - the node being validated
+     * @param definition - the node property definitions (either def.defaults or def.creds)
+     * @param properties - the node property values to validate
+     * @returns {boolean} whether the node's properties are valid
+     */
+    function validateNodeProperties(node, definition, properties) {
+        var isValid = true;
+        for (var prop in definition) {
+            if (definition.hasOwnProperty(prop)) {
+                if (!validateNodeProperty(node, definition, prop, properties[prop])) {
+                    isValid = false;
+                }
+            }
+        }
+        return isValid;
+    }
+
+    /**
+     * Validate a individual node property
+     * @param node - the node being validated
+     * @param definition - the node property definitions (either def.defaults or def.creds)
+     * @param property - the property name being validated
+     * @param value - the property value being validated
+     * @returns {boolean} whether the node proprty is valid
+     */
+    function validateNodeProperty(node,definition,property,value) {
+        var valid = true;
+        if ("required" in definition[property] && definition[property].required) {
+            valid = value !== "";
+        }
+        if (valid && "validate" in definition[property]) {
+            valid = definition[property].validate.call(node,value);
+        }
+        if (valid && definition[property].type && RED.nodes.getType(definition[property].type) && !("validate" in definition[property])) {
+            if (!value || value == "_ADD_") {
+                valid = false;
+            } else {
+                var v = RED.nodes.node(value).valid;
+                valid = (v==null || v);
+            }
+        }
+        return valid;
+    }
+
+    /**
+     * Called when the node's properties have changed.
+     * Marks the node as dirty and needing a size check.
+     * Removes any links to non-existant outputs.
+     * @param node - the node that has been updated
+     * @returns {array} the links that were removed due to this update
+     */
+    function updateNodeProperties(node) {
+        node.resize = true;
+        node.dirty = true;
+        var removedLinks = [];
+        if (node.outputs < node.ports.length) {
+            while (node.outputs < node.ports.length) {
+                node.ports.pop();
+            }
+            RED.nodes.eachLink(function(l) {
+                    if (l.source === node && l.sourcePort >= node.outputs) {
+                        removedLinks.push(l);
+                    }
+            });
+            for (var l=0;l<removedLinks.length;l++) {
+                RED.nodes.removeLink(removedLinks[l]);
+            }
+        } else if (node.outputs > node.ports.length) {
+            while (node.outputs > node.ports.length) {
+                node.ports.push(node.ports.length);
+            }
+        }
+        return removedLinks;
+    }
+
+
+
+    $( "#dialog" ).dialog({
+            modal: true,
+            autoOpen: false,
+            closeOnEscape: false,
+            width: 500,
+            buttons: [
+                {
+                    id: "node-dialog-ok",
+                    text: "Ok",
+                    click: function() {
+                        if (editing_node) {
+                            var changes = {};
+                            var changed = false;
+                            var wasDirty = RED.view.dirty();
+                            var d;
+
+                            if (editing_node._def.oneditsave) {
+                                var oldValues = {};
+                                for (d in editing_node._def.defaults) {
+                                    if (editing_node._def.defaults.hasOwnProperty(d)) {
+                                        if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
+                                            oldValues[d] = editing_node[d];
+                                        } else {
+                                            oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
+                                        }
+                                    }
+                                }
+                                var rc = editing_node._def.oneditsave.call(editing_node);
+                                if (rc === true) {
+                                    changed = true;
+                                }
+
+                                for (d in editing_node._def.defaults) {
+                                    if (editing_node._def.defaults.hasOwnProperty(d)) {
+                                        if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
+                                            if (oldValues[d] !== editing_node[d]) {
+                                                changes[d] = oldValues[d];
+                                                changed = true;
+                                            }
+                                        } else {
+                                            if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
+                                                changes[d] = oldValues[d];
+                                                changed = true;
+                                            }
+                                        }
+                                    }
+                                }
+
+
+                            }
+
+                            if (editing_node._def.defaults) {
+                                for (d in editing_node._def.defaults) {
+                                    if (editing_node._def.defaults.hasOwnProperty(d)) {
+                                        var input = $("#node-input-"+d);
+                                        var newValue;
+                                        if (input.attr('type') === "checkbox") {
+                                            newValue = input.prop('checked');
+                                        } else {
+                                            newValue = input.val();
+                                        }
+                                        if (newValue != null) {
+                                            if (editing_node[d] != newValue) {
+                                                if (editing_node._def.defaults[d].type) {
+                                                    if (newValue == "_ADD_") {
+                                                        newValue = "";
+                                                    }
+                                                    // Change to a related config node
+                                                    var configNode = RED.nodes.node(editing_node[d]);
+                                                    if (configNode) {
+                                                        var users = configNode.users;
+                                                        users.splice(users.indexOf(editing_node),1);
+                                                    }
+                                                    configNode = RED.nodes.node(newValue);
+                                                    if (configNode) {
+                                                        configNode.users.push(editing_node);
+                                                    }
+                                                }
+    
+                                                changes[d] = editing_node[d];
+                                                editing_node[d] = newValue;
+                                                changed = true;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                            if (editing_node._def.credentials) {
+                                var prefix = 'node-input';
+                                var credDefinition = editing_node._def.credentials;
+                                var credsChanged = updateNodeCredentials(editing_node,credDefinition,prefix);
+                                changed = changed || credsChanged;
+                            }
+
+
+                            var removedLinks = updateNodeProperties(editing_node);
+                            if (changed) {
+                                var wasChanged = editing_node.changed;
+                                editing_node.changed = true;
+                                RED.view.dirty(true);
+                                RED.history.push({t:'edit',node:editing_node,changes:changes,links:removedLinks,dirty:wasDirty,changed:wasChanged});
+                            }
+                            editing_node.dirty = true;
+                            validateNode(editing_node);
+                            RED.view.redraw();
+                        } else if (RED.view.state() == RED.state.EXPORT) {
+                            if (/library/.test($( "#dialog" ).dialog("option","title"))) {
+                                //TODO: move this to RED.library
+                                var flowName = $("#node-input-filename").val();
+                                if (!/^\s*$/.test(flowName)) {
+                                    $.post('library/flows/'+flowName,$("#node-input-filename").attr('nodes'),function() {
+                                            RED.library.loadFlowLibrary();
+                                            RED.notify("Saved nodes","success");
+                                    });
+                                }
+                            }
+                        } else if (RED.view.state() == RED.state.IMPORT) {
+                            RED.view.importNodes($("#node-input-import").val());
+                        }
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    id: "node-dialog-cancel",
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ],
+            resize: function(e,ui) {
+                if (editing_node) {
+                    $(this).dialog('option',"sizeCache-"+editing_node.type,ui.size);
+                }
+            },
+            open: function(e) {
+                RED.keyboard.disable();
+                if (editing_node) {
+                    var size = $(this).dialog('option','sizeCache-'+editing_node.type);
+                    if (size) {
+                        $(this).dialog('option','width',size.width);
+                        $(this).dialog('option','height',size.height);
+                    }
+                }
+            },
+            close: function(e) {
+                RED.keyboard.enable();
+
+                if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
+                    RED.view.state(RED.state.DEFAULT);
+                }
+                $( this ).dialog('option','height','auto');
+                $( this ).dialog('option','width','500');
+                if (editing_node) {
+                    RED.sidebar.info.refresh(editing_node);
+                }
+                RED.sidebar.config.refresh();
+                editing_node = null;
+            }
+    });
+
+    /**
+     * Create a config-node select box for this property
+     * @param node - the node being edited
+     * @param property - the name of the field
+     * @param type - the type of the config-node
+     */
+    function prepareConfigNodeSelect(node,property,type) {
+        var input = $("#node-input-"+property);
+        var node_def = RED.nodes.getType(type);
+
+        input.replaceWith('<select style="width: 60%;" id="node-input-'+property+'"></select>');
+        updateConfigNodeSelect(property,type,node[property]);
+        var select = $("#node-input-"+property);
+        select.after(' <a id="node-input-lookup-'+property+'" class="btn"><i class="fa fa-pencil"></i></a>');
+        $('#node-input-lookup-'+property).click(function(e) {
+            showEditConfigNodeDialog(property,type,select.find(":selected").val());
+            e.preventDefault();
+        });
+        var label = "";
+        var configNode = RED.nodes.node(node[property]);
+        if (configNode && node_def.label) {
+            if (typeof node_def.label == "function") {
+                label = node_def.label.call(configNode);
+            } else {
+                label = node_def.label;
+            }
+        }
+        input.val(label);
+    }
+
+    /**
+     * Populate the editor dialog input field for this property
+     * @param node - the node being edited
+     * @param property - the name of the field
+     * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
+     */
+    function preparePropertyEditor(node,property,prefix) {
+        var input = $("#"+prefix+"-"+property);
+        if (input.attr('type') === "checkbox") {
+            input.prop('checked',node[property]);
+        } else {
+            var val = node[property];
+            if (val == null) {
+                val = "";
+            }
+            input.val(val);
+        }
+    }
+
+    /**
+     * Add an on-change handler to revalidate a node field
+     * @param node - the node being edited
+     * @param definition - the definition of the node
+     * @param property - the name of the field
+     * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
+     */
+    function attachPropertyChangeHandler(node,definition,property,prefix) {
+        $("#"+prefix+"-"+property).change(function() {
+            if (!validateNodeProperty(node, definition, property,this.value)) {
+                $(this).addClass("input-error");
+            } else {
+                $(this).removeClass("input-error");
+            }
+        });
+    }
+
+    /**
+     * Assign the value to each credential field
+     * @param node
+     * @param credDef
+     * @param credData
+     * @param prefix
+     */
+    function populateCredentialsInputs(node, credDef, credData, prefix) {
+        var cred;
+        for (cred in credDef) {
+            if (credDef.hasOwnProperty(cred)) {
+                if (credDef[cred].type == 'password') {
+                    if (credData[cred]) {
+                        $('#' + prefix + '-' + cred).val(credData[cred]);
+                    } else if (credData['has_' + cred]) {
+                        $('#' + prefix + '-' + cred).val('__PWRD__');
+                    }
+                    else {
+                        $('#' + prefix + '-' + cred).val('');
+                    }
+                } else {
+                    preparePropertyEditor(credData, cred, prefix);
+                }
+                attachPropertyChangeHandler(node, credDef, cred, prefix);
+            }
+        }
+        for (cred in credDef) {
+            if (credDef.hasOwnProperty(cred)) {
+                $("#" + prefix + "-" + cred).change();
+            }
+        }
+    }
+    
+    /**
+     * Update the node credentials from the edit form
+     * @param node - the node containing the credentials
+     * @param credDefinition - definition of the credentials
+     * @param prefix - prefix of the input fields
+     * @return {boolean} whether anything has changed
+     */
+    function updateNodeCredentials(node, credDefinition, prefix) {
+        var changed = false;
+        if(!node.credentials) {
+            node.credentials = {_:{}};
+        }
+
+        for (var cred in credDefinition) {
+            if (credDefinition.hasOwnProperty(cred)) {
+                var input = $("#" + prefix + '-' + cred);
+                var value = input.val();
+                if (credDefinition[cred].type == 'password') {
+                    node.credentials['has_' + cred] = (value !== "");
+                    if (value == '__PWRD__') {
+                        continue;
+                    }
+                    changed = true;
+                    
+                }
+                node.credentials[cred] = value;
+                if (value != node.credentials._[cred]) {
+                    changed = true;
+                }
+            }
+        }
+        return changed;
+    }
+
+    /**
+     * Prepare all of the editor dialog fields
+     * @param node - the node being edited
+     * @param definition - the node definition
+     * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
+     */
+    function prepareEditDialog(node,definition,prefix) {
+        for (var d in definition.defaults) {
+            if (definition.defaults.hasOwnProperty(d)) {
+                if (definition.defaults[d].type) {
+                    prepareConfigNodeSelect(node,d,definition.defaults[d].type);
+                } else {
+                    preparePropertyEditor(node,d,prefix);
+                }
+                attachPropertyChangeHandler(node,definition.defaults,d,prefix);
+            }
+        }
+        var completePrepare = function() {
+            if (definition.oneditprepare) {
+                definition.oneditprepare.call(node);
+            }
+            for (var d in definition.defaults) {
+                if (definition.defaults.hasOwnProperty(d)) {
+                    $("#"+prefix+"-"+d).change();
+                }
+            }
+        }
+        
+        if (definition.credentials) {
+            if (node.credentials) {
+                populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
+                completePrepare();
+            } else {
+                $.getJSON(getCredentialsURL(node.type, node.id), function (data) {
+                    node.credentials = data;
+                    node.credentials._ = $.extend(true,{},data);
+                    populateCredentialsInputs(node, definition.credentials, node.credentials, prefix);
+                    completePrepare();
+                });
+            }
+        } else {
+            completePrepare();
+        }
+    }
+
+    function showEditDialog(node) {
+        editing_node = node;
+        RED.view.state(RED.state.EDITING);
+        $("#dialog-form").html($("script[data-template-name='"+node.type+"']").html());
+        $('<input type="text" style="display: none;" />').appendTo("#dialog-form");
+        prepareEditDialog(node,node._def,"node-input");
+        $( "#dialog" ).dialog("option","title","Edit "+node.type+" node").dialog( "open" );
+    }
+
+    function showEditConfigNodeDialog(name,type,id) {
+        var adding = (id == "_ADD_");
+        var node_def = RED.nodes.getType(type);
+
+        var configNode = RED.nodes.node(id);
+        if (configNode == null) {
+            configNode = {
+                id: (1+Math.random()*4294967295).toString(16),
+                _def: node_def,
+                type: type
+            }
+            for (var d in node_def.defaults) {
+                if (node_def.defaults[d].value) {
+                    configNode[d] = node_def.defaults[d].value;
+                }
+            }
+        }
+
+        $("#dialog-config-form").html($("script[data-template-name='"+type+"']").html());
+        prepareEditDialog(configNode,node_def,"node-config-input");
+
+        var buttons = $( "#node-config-dialog" ).dialog("option","buttons");
+        if (adding) {
+            if (buttons.length == 3) {
+                buttons = buttons.splice(1);
+            }
+            buttons[0].text = "Add";
+            $("#node-config-dialog-user-count").html("").hide();
+        } else {
+            if (buttons.length == 2) {
+                buttons.unshift({
+                        class: 'leftButton',
+                        text: "Delete",
+                        click: function() {
+                            var configProperty = $(this).dialog('option','node-property');
+                            var configId = $(this).dialog('option','node-id');
+                            var configType = $(this).dialog('option','node-type');
+                            var configNode = RED.nodes.node(configId);
+                            var configTypeDef = RED.nodes.getType(configType);
+
+                            if (configTypeDef.ondelete) {
+                                configTypeDef.ondelete.call(RED.nodes.node(configId));
+                            }
+                            RED.nodes.remove(configId);
+                            for (var i=0;i<configNode.users.length;i++) {
+                                var user = configNode.users[i];
+                                for (var d in user._def.defaults) {
+                                    if (user._def.defaults.hasOwnProperty(d) && user[d] == configId) {
+                                        user[d] = "";
+                                    }
+                                }
+                                validateNode(user);
+                            }
+                            updateConfigNodeSelect(configProperty,configType,"");
+                            RED.view.dirty(true);
+                            $( this ).dialog( "close" );
+                            RED.view.redraw();
+                        }
+                });
+            }
+            buttons[1].text = "Update";
+            $("#node-config-dialog-user-count").html(configNode.users.length+" node"+(configNode.users.length==1?" uses":"s use")+" this config").show();
+        }
+        $( "#node-config-dialog" ).dialog("option","buttons",buttons);
+
+        $( "#node-config-dialog" )
+            .dialog("option","node-adding",adding)
+            .dialog("option","node-property",name)
+            .dialog("option","node-id",configNode.id)
+            .dialog("option","node-type",type)
+            .dialog("option","title",(adding?"Add new ":"Edit ")+type+" config node")
+            .dialog( "open" );
+    }
+
+    function updateConfigNodeSelect(name,type,value) {
+        var select = $("#node-input-"+name);
+        var node_def = RED.nodes.getType(type);
+        select.children().remove();
+        RED.nodes.eachConfig(function(config) {
+            if (config.type == type) {
+                var label = "";
+                if (typeof node_def.label == "function") {
+                    label = node_def.label.call(config);
+                } else {
+                    label = node_def.label;
+                }
+                select.append('<option value="'+config.id+'"'+(value==config.id?" selected":"")+'>'+label+'</option>');
+            }
+        });
+
+        select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>Add new '+type+'...</option>');
+        window.setTimeout(function() { select.change();},50);
+    }
+
+    $( "#node-config-dialog" ).dialog({
+            modal: true,
+            autoOpen: false,
+            width: 500,
+            closeOnEscape: false,
+            buttons: [
+                {
+                    id: "node-config-dialog-ok",
+                    text: "Ok",
+                    click: function() {
+                        var configProperty = $(this).dialog('option','node-property');
+                        var configId = $(this).dialog('option','node-id');
+                        var configType = $(this).dialog('option','node-type');
+                        var configAdding = $(this).dialog('option','node-adding');
+                        var configTypeDef = RED.nodes.getType(configType);
+                        var configNode;
+                        var d;
+                        
+                        if (configAdding) {
+                            configNode = {type:configType,id:configId,users:[]};
+                            for (d in configTypeDef.defaults) {
+                                if (configTypeDef.defaults.hasOwnProperty(d)) {
+                                    configNode[d] = $("#node-config-input-"+d).val();
+                                }
+                            }
+                            configNode.label = configTypeDef.label;
+                            configNode._def = configTypeDef;
+                            RED.nodes.add(configNode);
+                            updateConfigNodeSelect(configProperty,configType,configNode.id);
+                        } else {
+                            configNode = RED.nodes.node(configId);
+                            for (d in configTypeDef.defaults) {
+                                if (configTypeDef.defaults.hasOwnProperty(d)) {
+                                    var input = $("#node-config-input-"+d);
+                                    if (input.attr('type') === "checkbox") {
+                                      configNode[d] = input.prop('checked');
+                                    } else {
+                                      configNode[d] = input.val();
+                                    }
+                                }
+                            }
+                            updateConfigNodeSelect(configProperty,configType,configId);
+                        }
+                        if (configTypeDef.credentials) {
+                            updateNodeCredentials(configNode,configTypeDef.credentials,"node-config-input");
+                        }
+                        if (configTypeDef.oneditsave) {
+                            configTypeDef.oneditsave.call(RED.nodes.node(configId));
+                        }
+                        validateNode(configNode);
+
+                        RED.view.dirty(true);
+                        $(this).dialog("close");
+
+                    }
+                },
+                {
+                    id: "node-config-dialog-cancel",
+                    text: "Cancel",
+                    click: function() {
+                        var configType = $(this).dialog('option','node-type');
+                        var configId = $(this).dialog('option','node-id');
+                        var configAdding = $(this).dialog('option','node-adding');
+                        var configTypeDef = RED.nodes.getType(configType);
+
+                        if (configTypeDef.oneditcancel) {
+                            // TODO: what to pass as this to call
+                            if (configTypeDef.oneditcancel) {
+                                var cn = RED.nodes.node(configId);
+                                if (cn) {
+                                    configTypeDef.oneditcancel.call(cn,false);
+                                } else {
+                                    configTypeDef.oneditcancel.call({id:configId},true);
+                                }
+                            }
+                        }
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ],
+            resize: function(e,ui) {
+            },
+            open: function(e) {
+                if (RED.view.state() != RED.state.EDITING) {
+                    RED.keyboard.disable();
+                }
+            },
+            close: function(e) {
+                $("#dialog-config-form").html("");
+                if (RED.view.state() != RED.state.EDITING) {
+                    RED.keyboard.enable();
+                }
+                RED.sidebar.config.refresh();
+            }
+    });
+
+
+    return {
+        edit: showEditDialog,
+        editConfig: showEditConfigNodeDialog,
+        validateNode: validateNode,
+        updateNodeProperties: updateNodeProperties // TODO: only exposed for edit-undo
+    }
+})();
diff --git a/dgbuilder/public/red/ui/keyboard.js b/dgbuilder/public/red/ui/keyboard.js
new file mode 100644 (file)
index 0000000..3bc28c4
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.keyboard = (function() {
+
+    var active = true;
+    var handlers = {};
+
+    d3.select(window).on("keydown",function() {
+        if (!active) { return; }
+        var handler = handlers[d3.event.keyCode];
+        if (handler && handler.ondown) {
+            if (!handler.modifiers ||
+                ((!handler.modifiers.shift || d3.event.shiftKey) &&
+                 (!handler.modifiers.ctrl  || d3.event.ctrlKey ) &&
+                 (!handler.modifiers.alt   || d3.event.altKey  ) )) {
+                handler.ondown();
+            }
+        }
+    });
+    d3.select(window).on("keyup",function() {
+        if (!active) { return; }
+        var handler = handlers[d3.event.keyCode];
+        if (handler && handler.onup) {
+            if (!handler.modifiers ||
+                ((!handler.modifiers.shift || d3.event.shiftKey) &&
+                 (!handler.modifiers.ctrl  || d3.event.ctrlKey ) &&
+                 (!handler.modifiers.alt   || d3.event.altKey  ) )) {
+                handler.onup();
+            }
+        }
+    });
+    function addHandler(key,modifiers,ondown,onup) {
+        var mod = modifiers;
+        var cbdown = ondown;
+        var cbup = onup;
+
+        if (typeof modifiers == "function") {
+            mod = {};
+            cbdown = modifiers;
+            cbup = ondown;
+        }
+        handlers[key] = {modifiers:mod, ondown:cbdown, onup:cbup};
+    }
+    function removeHandler(key) {
+        delete handlers[key];
+    }
+
+    return {
+        add: addHandler,
+        remove: removeHandler,
+        disable: function(){ active = false;},
+        enable: function(){ active = true; }
+    }
+
+})();
diff --git a/dgbuilder/public/red/ui/library.js b/dgbuilder/public/red/ui/library.js
new file mode 100644 (file)
index 0000000..0c803bf
--- /dev/null
@@ -0,0 +1,370 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.library = (function() {
+    
+    
+    function loadFlowLibrary() {
+        $.getJSON("library/flows",function(data) {
+            //console.log(data);
+
+            var buildMenu = function(data,root) {
+                var i;
+                var li;
+                var a;
+                var ul = document.createElement("ul");
+                ul.id = "btn-import-library-submenu";
+                ul.className = "dropdown-menu";
+                if (data.d) {
+                    for (i in data.d) {
+                        if (data.d.hasOwnProperty(i)) {
+                            li = document.createElement("li");
+                            li.className = "dropdown-submenu pull-left";
+                            a = document.createElement("a");
+                            a.href="#";
+                            a.innerHTML = i;
+                            li.appendChild(a);
+                            li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i));
+                            ul.appendChild(li);
+                        }
+                    }
+                }
+                if (data.f) {
+                    for (i in data.f) {
+                        if (data.f.hasOwnProperty(i)) {
+                            li = document.createElement("li");
+                            a = document.createElement("a");
+                            a.href="#";
+                            a.innerHTML = data.f[i];
+                            a.flowName = root+(root!==""?"/":"")+data.f[i];
+                            a.onclick = function() {
+                                $.get('library/flows/'+this.flowName, function(data) {
+                                        RED.view.importNodes(data);
+                                });
+                            };
+                            li.appendChild(a);
+                            ul.appendChild(li);
+                        }
+                    }
+                }
+                return ul;
+            };
+            var menu = buildMenu(data,"");
+            //TODO: need an api in RED.menu for this
+            $("#btn-import-library-submenu").replaceWith(menu);
+        });
+    }
+    loadFlowLibrary();
+
+
+    
+    function createUI(options) {
+        var libraryData = {};
+        var selectedLibraryItem = null;
+        var libraryEditor = null;
+        
+        function buildFileListItem(item) {
+            var li = document.createElement("li");
+            li.onmouseover = function(e) { $(this).addClass("list-hover"); };
+            li.onmouseout = function(e) { $(this).removeClass("list-hover"); };
+            return li;
+        }
+        
+        function buildFileList(root,data) {
+            var ul = document.createElement("ul");
+            var li;
+            for (var i=0;i<data.length;i++) {
+                var v = data[i];
+                if (typeof v === "string") {
+                    // directory
+                    li = buildFileListItem(v);
+                    li.onclick = (function () {
+                        var dirName = v;
+                        return function(e) {
+                            var bcli = $('<li class="active"><span class="divider">/</span> <a href="#">'+dirName+'</a></li>');
+                            $("a",bcli).click(function(e) { 
+                                $(this).parent().nextAll().remove();
+                                $.getJSON("library/"+options.url+root+dirName,function(data) {
+                                    $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
+                                });
+                                e.stopPropagation();
+                            });
+                            var bc = $("#node-dialog-library-breadcrumbs");
+                            $(".active",bc).removeClass("active");
+                            bc.append(bcli);
+                            $.getJSON("library/"+options.url+root+dirName,function(data) {
+                                    $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
+                            });
+                        }
+                    })();
+                    li.innerHTML = '<i class="fa fa-folder"></i> '+v+"</i>";
+                    ul.appendChild(li);
+                } else {
+                    // file
+                   li = buildFileListItem(v);
+                   li.innerHTML = v.name;
+                   li.onclick = (function() {
+                       var item = v;
+                       return function(e) {
+                           $(".list-selected",ul).removeClass("list-selected");
+                           $(this).addClass("list-selected");
+                           $.get("library/"+options.url+root+item.fn, function(data) {
+                                   selectedLibraryItem = item;
+                                   libraryEditor.setText(data);
+                           });
+                       }
+                   })();
+                   ul.appendChild(li);
+                }
+            }
+            return ul;
+        }
+    
+/*
+//Commented this portion as is not used by the DGBuilder application
+        $('#node-input-name').addClass('input-append-left').css("width","65%").after(
+            '<div class="btn-group" style="margin-left: 0px;">'+
+            '<button id="node-input-'+options.type+'-lookup" class="btn input-append-right" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></button>'+
+            '<ul class="dropdown-menu pull-right" role="menu">'+
+            '<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">Open Library...</a></li>'+
+            '<li><a id="node-input-'+options.type+'-menu-save-library" tabindex="-1" href="#">Save to Library...</a></li>'+
+            '</ul></div>'
+        );
+    
+        
+        
+        $('#node-input-'+options.type+'-menu-open-library').click(function(e) {
+            $("#node-select-library").children().remove();
+            var bc = $("#node-dialog-library-breadcrumbs");
+            bc.children().first().nextAll().remove();
+            libraryEditor.setText('');
+            
+            $.getJSON("library/"+options.url,function(data) {
+                $("#node-select-library").append(buildFileList("/",data));
+                $("#node-dialog-library-breadcrumbs a").click(function(e) {
+                    $(this).parent().nextAll().remove();
+                    $("#node-select-library").children().first().replaceWith(buildFileList("/",data));
+                    e.stopPropagation();
+                });
+                $( "#node-dialog-library-lookup" ).dialog( "open" );
+            });
+            
+            e.preventDefault();
+        });
+    
+        $('#node-input-'+options.type+'-menu-save-library').click(function(e) {
+            //var found = false;
+            var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
+
+            //var buildPathList = function(data,root) {
+            //    var paths = [];
+            //    if (data.d) {
+            //        for (var i in data.d) {
+            //            var dn = root+(root==""?"":"/")+i;
+            //            var d = {
+            //                label:dn,
+            //                files:[]
+            //            };
+            //            for (var f in data.d[i].f) {
+            //                d.files.push(data.d[i].f[f].fn.split("/").slice(-1)[0]);
+            //            }
+            //            paths.push(d);
+            //            paths = paths.concat(buildPathList(data.d[i],root+(root==""?"":"/")+i));
+            //        }
+            //    }
+            //    return paths;
+            //};
+            $("#node-dialog-library-save-folder").attr("value","");
+
+            var filename = name.replace(/[^\w-]/g,"-");
+            if (filename === "") {
+                filename = "unnamed-"+options.type;
+            }
+            $("#node-dialog-library-save-filename").attr("value",filename+".js");
+
+            //var paths = buildPathList(libraryData,"");
+            //$("#node-dialog-library-save-folder").autocomplete({
+            //        minLength: 0,
+            //        source: paths,
+            //        select: function( event, ui ) {
+            //            $("#node-dialog-library-save-filename").autocomplete({
+            //                    minLength: 0,
+            //                    source: ui.item.files
+            //            });
+            //        }
+            //});
+
+            $( "#node-dialog-library-save" ).dialog( "open" );
+            e.preventDefault();
+        });
+        require(["orion/editor/edit"], function(edit) {
+            libraryEditor = edit({
+                parent:document.getElementById('node-select-library-text'),
+                lang:"js",
+                readonly: true
+            });
+        });
+    
+        
+        $( "#node-dialog-library-lookup" ).dialog({
+            title: options.type+" library",
+            modal: true,
+            autoOpen: false,
+            width: 800,
+            height: 450,
+            buttons: [
+                {
+                    text: "Ok",
+                    click: function() {
+                        if (selectedLibraryItem) {
+                            for (var i=0;i<options.fields.length;i++) {
+                                var field = options.fields[i];
+                                $("#node-input-"+field).val(selectedLibraryItem[field]);
+                            }
+                            options.editor.setText(libraryEditor.getText());
+                        }
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ],
+            open: function(e) {
+                var form = $("form",this);
+                form.height(form.parent().height()-30);
+                $("#node-select-library-text").height("100%");
+                $(".form-row:last-child",form).children().height(form.height()-60);
+            },
+            resize: function(e) {
+                var form = $("form",this);
+                form.height(form.parent().height()-30);
+                $(".form-row:last-child",form).children().height(form.height()-60);
+            }
+        });
+        
+   */ 
+        function saveToLibrary(overwrite) {
+            var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
+            if (name === "") {
+                name = "Unnamed "+options.type;
+            }
+            var filename = $("#node-dialog-library-save-filename").val().replace(/(^\s*)|(\s*$)/g,"");
+            var pathname = $("#node-dialog-library-save-folder").val().replace(/(^\s*)|(\s*$)/g,"");
+            if (filename === "" || !/.+\.js$/.test(filename)) {
+                RED.notify("Invalid filename","warning");
+                return;
+            }
+            var fullpath = pathname+(pathname===""?"":"/")+filename;
+            if (!overwrite) {
+                //var pathnameParts = pathname.split("/");
+                //var exists = false;
+                //var ds = libraryData;
+                //for (var pnp in pathnameParts) {
+                //    if (ds.d && pathnameParts[pnp] in ds.d) {
+                //        ds = ds.d[pathnameParts[pnp]];
+                //    } else {
+                //        ds = null;
+                //        break;
+                //    }
+                //}
+                //if (ds && ds.f) {
+                //    for (var f in ds.f) {
+                //        if (ds.f[f].fn == fullpath) {
+                //            exists = true;
+                //            break;
+                //        }
+                //    }
+                //}
+                //if (exists) {
+                //    $("#node-dialog-library-save-type").html(options.type);
+                //    $("#node-dialog-library-save-name").html(fullpath);
+                //    $("#node-dialog-library-save-confirm").dialog( "open" );
+                //    return;
+                //}
+            }
+            var queryArgs = [];
+            for (var i=0;i<options.fields.length;i++) {
+                var field = options.fields[i];
+                if (field == "name") {
+                    queryArgs.push("name="+encodeURIComponent(name));
+                } else {
+                    queryArgs.push(encodeURIComponent(field)+"="+encodeURIComponent($("#node-input-"+field).val()));
+                }
+            }
+            var queryString = queryArgs.join("&");
+            
+            var text = options.editor.getText();
+            $.post("library/"+options.url+'/'+fullpath+"?"+queryString,text,function() {
+                    RED.notify("Saved "+options.type,"success");
+            });
+        }
+        $( "#node-dialog-library-save-confirm" ).dialog({
+            title: "Save to library",
+            modal: true,
+            autoOpen: false,
+            width: 530,
+            height: 230,
+            buttons: [
+                {
+                    text: "Ok",
+                    click: function() {
+                        saveToLibrary(true);
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ]
+        });
+        $( "#node-dialog-library-save" ).dialog({
+            title: "Save to library",
+            modal: true,
+            autoOpen: false,
+            width: 530,
+            height: 230,
+            buttons: [
+                {
+                    text: "Ok",
+                    click: function() {
+                        saveToLibrary(false);
+                        $( this ).dialog( "close" );
+                    }
+                },
+                {
+                    text: "Cancel",
+                    click: function() {
+                        $( this ).dialog( "close" );
+                    }
+                }
+            ]
+        });
+
+    }
+    
+    return {
+        create: createUI,
+        loadFlowLibrary: loadFlowLibrary
+    }
+})();
+
+
diff --git a/dgbuilder/public/red/ui/menu.js b/dgbuilder/public/red/ui/menu.js
new file mode 100644 (file)
index 0000000..07ea5fd
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+
+RED.menu = (function() {
+    
+    var menuItems = {};
+    
+    function createMenuItem(opt) {
+        var item;
+        if (opt === null) {
+            item = $('<li class="divider"></li>');
+        } else {
+            item = $('<li></li>');
+            var link = $('<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">'+
+                (opt.toggle?'<i class="fa fa-check pull-right"></i>':'')+
+                (opt.icon?'<i class="'+opt.icon+'"></i> ':'')+
+                opt.label+
+                '</a>').appendTo(item);
+                
+            menuItems[opt.id] = opt;
+            
+            if (opt.onselect) {
+                link.click(function() {
+                        if ($(this).parent().hasClass("disabled")) {
+                            return;
+                        }
+                        if (opt.toggle) {
+                            setSelected(opt.id,!isSelected(opt.id));
+                        } else {
+                            opt.onselect.call(opt);
+                        }
+                })
+            } else if (opt.href) {
+                link.attr("target","_blank").attr("href",opt.href);
+            }
+            if (opt.options) {
+                item.addClass("dropdown-submenu pull-left");
+                var submenu = $('<ul id="'+opt.id+'-submenu" class="dropdown-menu"></ul>').appendTo(item);
+                
+                for (var i=0;i<opt.options.length;i++) {
+                    createMenuItem(opt.options[i]).appendTo(submenu);
+                }
+            }
+            if (opt.disabled) {
+                item.addClass("disabled");
+            }
+        }
+        
+        
+        return item;
+        
+    }
+    function createMenu(options) {
+        
+        var button = $("#"+options.id);
+        
+        var topMenu = $("<ul/>",{class:"dropdown-menu"}).insertAfter(button);
+        
+        for (var i=0;i<options.options.length;i++) {
+            var opt = options.options[i];
+            createMenuItem(opt).appendTo(topMenu);
+        }
+    }
+    
+    function isSelected(id) {
+        return $("#"+id).hasClass("active");
+    }
+    function setSelected(id,state) {
+        if (isSelected(id) == state) {
+            return;
+        }
+        var opt = menuItems[id];
+        if (state) {
+            $("#"+id).addClass("active");
+        } else {
+            $("#"+id).removeClass("active");
+        }
+        if (opt.onselect) {
+            opt.onselect.call(opt,state);
+        }
+    }
+    
+    function setDisabled(id,state) {
+        if (state) {
+            $("#"+id).parent().addClass("disabled");
+        } else {
+            $("#"+id).parent().removeClass("disabled");
+        }
+    }
+    
+    function addItem(id,opt) {
+        createMenuItem(opt).appendTo("#"+id+"-submenu");
+    }
+    function removeItem(id) {
+        $("#"+id).parent().remove();
+    }
+    
+    return {
+        init: createMenu,
+        setSelected: setSelected,
+        isSelected: isSelected,
+        setDisabled: setDisabled,
+        addItem: addItem,
+        removeItem: removeItem
+        //TODO: add an api for replacing a submenu - see library.js:loadFlowLibrary
+    }
+})();
diff --git a/dgbuilder/public/red/ui/notifications.js b/dgbuilder/public/red/ui/notifications.js
new file mode 100644 (file)
index 0000000..c9436c6
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.notify = (function() {
+    var currentNotifications = [];
+    var c = 0;
+    return function(msg,type,fixed,timeout) {
+        if (currentNotifications.length > 4) {
+            var ll = currentNotifications.length;
+            for (var i = 0;ll > 4 && i<currentNotifications.length;i+=1) {
+                var notifiction = currentNotifications[i];
+                if (!notifiction.fixed) {
+                    window.clearTimeout(notifiction.timeoutid);
+                    notifiction.close();
+                    ll -= 1;
+                }
+            }
+        }
+        var n = document.createElement("div");
+        n.id="red-notification-"+c;
+        n.className = "alert";
+        n.fixed = fixed;
+        if (type) {
+            n.className = "alert alert-"+type;
+        }
+        n.style.display = "none";
+        n.innerHTML = msg;
+        $("#notifications").append(n);
+        $(n).slideDown(300);
+        n.close = (function() {
+            var nn = n;
+            return function() {
+                currentNotifications.splice(currentNotifications.indexOf(nn),1);
+                $(nn).slideUp(300, function() {
+                        nn.parentNode.removeChild(nn);
+                });
+            };
+        })();
+        if (!fixed) {
+            n.timeoutid = window.setTimeout(n.close,timeout||3000);
+        }
+        currentNotifications.push(n);
+        c+=1;
+        return n;
+    }
+})();
+
diff --git a/dgbuilder/public/red/ui/palette.js b/dgbuilder/public/red/ui/palette.js
new file mode 100644 (file)
index 0000000..f0524e5
--- /dev/null
@@ -0,0 +1,230 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+RED.palette = (function() {
+
+    var exclusion = ['config','unknown','deprecated'];
+    //var core = ['input', 'output', 'function', 'social', 'storage', 'analysis', 'advanced'];
+    var core = ['DGEmain','DGEoutcome','DGEreturn','DGElogic'];
+    function createCategoryContainer(category){
+        var escapedCategory = category.replace(" ","_");
+        $("#palette-container").append('<div class="palette-category">'+
+            '<div id="header-'+category+'" class="palette-header"><i class="expanded fa fa-caret-down"></i><span>'+category.replace("_"," ")+'</span></div>'+
+            '<div class="palette-content" id="palette-base-category-'+category+'">'+
+            '<div id="palette-'+category+'-input"></div>'+
+            '<div id="palette-'+category+'-output"></div>'+
+            '<div id="palette-'+category+'-function"></div>'+
+            '</div>'+
+            '</div>');
+
+        $("#header-"+category).on('click', function(e) {
+            $(this).next().slideToggle();
+            $(this).children("i").toggleClass("expanded");
+        });
+    }
+
+    core.forEach(createCategoryContainer);
+
+    function addNodeType(nt,def) {
+
+        var nodeTypeId = nt.replace(" ","_");
+
+        if ($("#palette_node_"+nodeTypeId).length) {
+            return;
+        }
+
+        if (exclusion.indexOf(def.category)===-1) {
+
+            var category = def.category.replace(" ","_");
+            var rootCategory = category.split("-")[0];
+
+            var d = document.createElement("div");
+            d.id = "palette_node_"+nodeTypeId;
+            d.type = nt;
+
+            // calculate width of label text
+            $.fn.textWidth = function(text, font) {
+                if (!$.fn.textWidth.fakeEl) {
+                    $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
+                }
+                $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
+                return $.fn.textWidth.fakeEl.width();
+            };
+
+            var label;
+                                
+            if (typeof def.paletteLabel === "undefined") {
+                label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
+            } else { 
+                label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
+            }
+                
+            var pixels = $.fn.textWidth(label, '13px helvetica');
+            var nodeWidth = 90;
+            var labelWidth = nodeWidth - 10;
+            var numLines = Math.ceil(pixels / nodeWidth);
+            var multiLine = numLines > 1;
+
+            // styles matching with style.css
+            var nodeHeight = 25;
+            var lineHeight = 16;
+            var portHeight = 10;
+            var multiLineNodeHeight = lineHeight * numLines + (nodeHeight - lineHeight);
+
+            d.innerHTML = '<div class="palette_label"'+
+                (multiLine ? 'style="line-height: '+
+                    lineHeight + 'px; margin-top: 5px"' : '')+
+                '>'+label+"</div>";
+            d.className="palette_node";
+            if (def.icon) {
+                d.style.backgroundImage = "url(icons/"+def.icon+")";
+                if (multiLine) {
+                    d.style.backgroundSize = "18px 27px";
+                }
+                if (def.align == "right") {
+                    d.style.backgroundPosition = "95% 50%";
+                } else if (def.inputs > 0) {
+                    d.style.backgroundPosition = "10% 50%";
+                }
+            }
+
+            d.style.backgroundColor = def.color;
+            d.style.height = multiLineNodeHeight + "px";
+
+            if (def.outputs > 0) {
+                var portOut = document.createElement("div");
+                portOut.className = "palette_port palette_port_output";
+                if (multiLine) {
+                    portOut.style.top = ((multiLineNodeHeight - portHeight) / 2) + "px";
+                }
+                d.appendChild(portOut);
+            }
+
+            if (def.inputs > 0) {
+                var portIn = document.createElement("div");
+                portIn.className = "palette_port";
+                if (multiLine) {
+                    portIn.style.top = ((multiLineNodeHeight - portHeight) / 2) + "px";
+                }
+                d.appendChild(portIn);
+            }
+
+            if ($("#palette-base-category-"+rootCategory).length === 0) {
+                createCategoryContainer(rootCategory);
+            }
+
+            if ($("#palette-"+category).length === 0) {
+                $("#palette-base-category-"+rootCategory).append('<div id="palette-'+category+'"></div>');
+            }
+
+            $("#palette-"+category).append(d);
+            d.onmousedown = function(e) { e.preventDefault(); };
+
+            var popOverContent;
+            try {
+                popOverContent = $("<p><b>"+label+"</b></p>"+($("script[data-help-name|='"+nt+"']").html().trim()||"<p>no information available</p>")).slice(0,2);
+            } catch(err) {
+                // Malformed HTML may cause errors. TODO: need to understand what can break
+                console.log("Error generating pop-over label for '"+nt+"'.");
+                console.log(err.toString());
+                popOverContent = "<p><b>"+label+"</b></p><p>no information available</p>";
+            }
+            $(d).popover({
+                title:d.type,
+                placement:"right",
+                trigger: "hover",
+                delay: { show: 750, hide: 50 },
+                html: true,
+                container:'body',
+                content: popOverContent
+            });
+            $(d).click(function() {
+                var help = '<div class="node-help">'+($("script[data-help-name|='"+d.type+"']").html()||"")+"</div>";
+                $("#tab-info").html(help);
+            });
+            $(d).draggable({
+                helper: 'clone',
+                appendTo: 'body',
+                revert: true,
+                revertDuration: 50
+            });
+        }
+    }
+
+    function removeNodeType(nt) {
+        var nodeTypeId = nt.replace(" ","_");
+        $("#palette_node_"+nodeTypeId).remove();
+    }
+    function hideNodeType(nt) {
+        var nodeTypeId = nt.replace(" ","_");
+        $("#palette_node_"+nodeTypeId).hide();
+    }
+
+    function showNodeType(nt) {
+        var nodeTypeId = nt.replace(" ","_");
+        $("#palette_node_"+nodeTypeId).show();
+    }
+
+    function filterChange() {
+        var val = $("#palette-search-input").val();
+        if (val === "") {
+            $("#palette-search-clear").hide();
+        } else {
+            $("#palette-search-clear").show();
+        }
+
+        var re = new RegExp(val);
+        $(".palette_node").each(function(i,el) {
+            if (val === "" || re.test(el.id)) {
+                $(this).show();
+            } else {
+                $(this).hide();
+            }
+        });
+    }
+
+    $("#palette-search-input").focus(function(e) {
+        RED.keyboard.disable();
+    });
+    $("#palette-search-input").blur(function(e) {
+        RED.keyboard.enable();
+    });
+
+    $("#palette-search-clear").on("click",function(e) {
+        e.preventDefault();
+        $("#palette-search-input").val("");
+        filterChange();
+        $("#palette-search-input").focus();
+    });
+
+    $("#palette-search-input").val("");
+    $("#palette-search-input").on("keyup",function() {
+        filterChange();
+    });
+
+    $("#palette-search-input").on("focus",function() {
+        $("body").one("mousedown",function() {
+            $("#palette-search-input").blur();
+        });
+    });
+
+    return {
+        add:addNodeType,
+        remove:removeNodeType,
+        hide:hideNodeType,
+        show:showNodeType
+    };
+})();
diff --git a/dgbuilder/public/red/ui/sidebar.js b/dgbuilder/public/red/ui/sidebar.js
new file mode 100644 (file)
index 0000000..f55e516
--- /dev/null
@@ -0,0 +1,154 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.sidebar = (function() {
+
+    //$('#sidebar').tabs();
+    var sidebar_tabs = RED.tabs.create({
+        id:"sidebar-tabs",
+        onchange:function(tab) {
+            $("#sidebar-content").children().hide();
+            $("#"+tab.id).show();
+        },
+        onremove: function(tab) {
+            $("#"+tab.id).remove();
+        }
+    });
+    function addTab(title,content,closeable) {
+        $("#sidebar-content").append(content);
+        $(content).hide();
+        sidebar_tabs.addTab({id:"tab-"+title,label:title,closeable:closeable});
+        //content.style.position = "absolute";
+        //$('#sidebar').tabs("refresh");
+    }
+
+    function removeTab(title) {
+        sidebar_tabs.removeTab("tab-"+title);
+    }
+    
+    var sidebarSeparator =  {};
+    $("#sidebar-separator").draggable({
+            axis: "x",
+            start:function(event,ui) {
+                sidebarSeparator.closing = false;
+                sidebarSeparator.opening = false;
+                var winWidth = $(window).width();
+                sidebarSeparator.start = ui.position.left;
+                sidebarSeparator.chartWidth = $("#workspace").width();
+                sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
+
+
+                if (!RED.menu.isSelected("btn-sidebar")) {
+                    sidebarSeparator.opening = true;
+                    var newChartRight = 15;
+                    $("#sidebar").addClass("closing");
+                    $("#workspace").css("right",newChartRight);
+                    $("#chart-zoom-controls").css("right",newChartRight+20);
+                    $("#sidebar").width(0);
+                    RED.menu.setSelected("btn-sidebar",true);
+                    RED.view.resize();
+                }
+
+                
+                sidebarSeparator.width = $("#sidebar").width();
+            },
+            drag: function(event,ui) {
+                var d = ui.position.left-sidebarSeparator.start;
+                var newSidebarWidth = sidebarSeparator.width-d;
+                if (sidebarSeparator.opening) {
+                    newSidebarWidth -= 13;
+                }
+                
+                if (newSidebarWidth > 150) {
+                    if (sidebarSeparator.chartWidth+d < 200) {
+                        ui.position.left = 200+sidebarSeparator.start-sidebarSeparator.chartWidth;
+                        d = ui.position.left-sidebarSeparator.start;
+                        newSidebarWidth = sidebarSeparator.width-d;
+                    }
+                }
+                    
+                if (newSidebarWidth < 150) {
+                    if (!sidebarSeparator.closing) {
+                        $("#sidebar").addClass("closing");
+                        sidebarSeparator.closing = true;
+                    }
+                    if (!sidebarSeparator.opening) {
+                        newSidebarWidth = 150;
+                        ui.position.left = sidebarSeparator.width-(150 - sidebarSeparator.start);
+                        d = ui.position.left-sidebarSeparator.start;
+                    }
+                } else if (newSidebarWidth > 150 && (sidebarSeparator.closing || sidebarSeparator.opening)) {
+                    sidebarSeparator.closing = false;
+                    $("#sidebar").removeClass("closing");
+                }
+
+                var newChartRight = sidebarSeparator.chartRight-d;
+                $("#workspace").css("right",newChartRight);
+                $("#chart-zoom-controls").css("right",newChartRight+20);
+                $("#sidebar").width(newSidebarWidth);
+
+                sidebar_tabs.resize();
+                RED.view.resize();
+                    
+            },
+            stop:function(event,ui) {
+                RED.view.resize();
+                if (sidebarSeparator.closing) {
+                    $("#sidebar").removeClass("closing");
+                    RED.menu.setSelected("btn-sidebar",false);
+                    if ($("#sidebar").width() < 180) {
+                        $("#sidebar").width(180);
+                        $("#workspace").css("right",208);
+                        $("#chart-zoom-controls").css("right",228);
+                    }
+                }
+                $("#sidebar-separator").css("left","auto");
+                $("#sidebar-separator").css("right",($("#sidebar").width()+13)+"px");
+            }
+    });
+    
+    function toggleSidebar(state) {
+        if (!state) {
+            $("#main-container").addClass("sidebar-closed");
+        } else {
+            $("#main-container").removeClass("sidebar-closed");
+        }
+    }
+    
+    function showSidebar(id) {
+        RED.menu.setSelected("btn-sidebar",true);
+        sidebar_tabs.activateTab("tab-"+id);
+    }
+    
+    function containsTab(id) {
+        return sidebar_tabs.contains("tab-"+id);
+    }
+    
+    
+    $(function() {
+        RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("btn-sidebar",!RED.menu.isSelected("btn-sidebar"));d3.event.preventDefault();});
+        showSidebar("info");
+    });
+
+    
+    return {
+        addTab: addTab,
+        removeTab: removeTab,
+        show: showSidebar,
+        containsTab: containsTab,
+        toggleSidebar: toggleSidebar
+    }
+    
+})();
diff --git a/dgbuilder/public/red/ui/state.js b/dgbuilder/public/red/ui/state.js
new file mode 100644 (file)
index 0000000..419b04b
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.state = {
+    DEFAULT: 0,
+    MOVING: 1,
+    JOINING: 2,
+    MOVING_ACTIVE: 3,
+    ADDING: 4,
+    EDITING: 5,
+    EXPORT: 6,
+    IMPORT: 7,
+    IMPORT_DRAGGING: 8
+}
diff --git a/dgbuilder/public/red/ui/tab-config.js b/dgbuilder/public/red/ui/tab-config.js
new file mode 100644 (file)
index 0000000..6ef6ba0
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.sidebar.config = (function() {
+    
+    var content = document.createElement("div");
+    content.id = "tab-config";
+    content.style.paddingTop = "4px";
+    content.style.paddingLeft = "4px";
+    content.style.paddingRight = "4px";
+    
+    var list = $("<ul>",{class:"tab-config-list"}).appendTo(content);
+    
+    function show() {
+        if (!RED.sidebar.containsTab("config")) {
+            RED.sidebar.addTab("config",content,true);
+        }
+        refresh();
+        RED.sidebar.show("config");
+    }
+    
+    function refresh() {
+        list.empty();
+        RED.nodes.eachConfig(function(node) {
+            var li = list.find("#tab-config-list-type-"+node.type);
+            if (li.length === 0) {
+                li = $("<li>",{id:"tab-config-list-type-"+node.type}).appendTo(list);
+                $('<div class="tab-config-list-type">'+node.type+'</div>').appendTo(li);
+            }
+            var label = "";
+            if (typeof node._def.label == "function") {
+                label = node._def.label.call(node);
+            } else {
+                label = node._def.label;
+            }
+            label = label || "&nbsp;";
+            
+            var entry = $('<div class="tab-config-list-entry"></div>').appendTo(li);
+            entry.on('dblclick',function(e) {
+                RED.editor.editConfig("", node.type, node.id);
+            });
+            
+            var userArray = node.users.map(function(n) { return n.id });
+            entry.on('mouseover',function(e) {
+                RED.nodes.eachNode(function(node) {
+                    if( userArray.indexOf(node.id) != -1) {
+                        node.highlighted = true;
+                        node.dirty = true;
+                    }
+                });
+                RED.view.redraw();
+            });
+
+            entry.on('mouseout',function(e) {
+                RED.nodes.eachNode(function(node) {
+                    if(node.highlighted) {
+                        node.highlighted = false;
+                        node.dirty = true;
+                    }
+                });
+                RED.view.redraw();
+            });
+            
+            $('<div class="tab-config-list-label">'+label+'</div>').appendTo(entry);
+            $('<div class="tab-config-list-users">'+node.users.length+'</div>').appendTo(entry);
+        });
+    }
+    return {
+        show:show,
+        refresh:refresh
+    }
+})();
diff --git a/dgbuilder/public/red/ui/tab-info.js b/dgbuilder/public/red/ui/tab-info.js
new file mode 100644 (file)
index 0000000..bb8eb04
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.sidebar.info = (function() {
+    
+    var content = document.createElement("div");
+    content.id = "tab-info";
+    content.style.paddingTop = "4px";
+    content.style.paddingLeft = "4px";
+    content.style.paddingRight = "4px";
+
+    RED.sidebar.addTab("info",content);
+    
+    function jsonFilter(key,value) {
+        if (key === "") {
+            return value;
+        }
+        var t = typeof value;
+        if ($.isArray(value)) {
+            return "[array:"+value.length+"]";
+        } else if (t === "object") {
+            return "[object]"
+        } else if (t === "string") {
+            if (value.length > 30) {
+                return value.substring(0,30)+" ...";
+            }
+        }
+        return value;
+    }
+    
+    function refresh(node) {
+        var table = '<table class="node-info"><tbody>';
+
+        table += '<tr class="blank"><td colspan="2">Node</td></tr>';
+        table += "<tr><td>Type</td><td>&nbsp;"+node.type+"</td></tr>";
+        table += "<tr><td>ID</td><td>&nbsp;"+node.id+"</td></tr>";
+        table += '<tr class="blank"><td colspan="2">Properties</td></tr>';
+        for (var n in node._def.defaults) {
+            if (node._def.defaults.hasOwnProperty(n)) {
+                var val = node[n]||"";
+                var type = typeof val;
+                if (type === "string") {
+                    if (val.length > 30) { 
+                        val = val.substring(0,30)+" ...";
+                    }
+                    val = val.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                } else if (type === "number") {
+                    val = val.toString();
+                } else if ($.isArray(val)) {
+                    val = "[<br/>";
+                    for (var i=0;i<Math.min(node[n].length,10);i++) {
+                        var vv = JSON.stringify(node[n][i],jsonFilter," ").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                        val += "&nbsp;"+i+": "+vv+"<br/>";
+                    }
+                    if (node[n].length > 10) {
+                        val += "&nbsp;... "+node[n].length+" items<br/>";
+                    }
+                    val += "]";
+                } else {
+                    val = JSON.stringify(val,jsonFilter," ");
+                    val = val.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+                }
+                
+                table += "<tr><td>&nbsp;"+n+"</td><td>"+val+"</td></tr>";
+            }
+        }
+        table += "</tbody></table><br/>";
+        table  += '<div class="node-help">'+($("script[data-help-name|='"+node.type+"']").html()||"")+"</div>";
+        $("#tab-info").html(table);
+    }
+    
+    return {
+        refresh:refresh,
+        clear: function() {
+            $("#tab-info").html("");
+        }
+    }
+})();
diff --git a/dgbuilder/public/red/ui/tabs.js b/dgbuilder/public/red/ui/tabs.js
new file mode 100644 (file)
index 0000000..aa20758
--- /dev/null
@@ -0,0 +1,127 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+
+RED.tabs = (function() {
+    
+    
+    function createTabs(options) {
+        var tabs = {};
+        
+        var ul = $("#"+options.id)
+        ul.addClass("red-ui-tabs");
+        ul.children().first().addClass("active");
+        ul.children().addClass("red-ui-tab");
+        
+        function onTabClick() {
+            activateTab($(this));
+            return false;
+        }
+        
+        function onTabDblClick() {
+            if (options.ondblclick) {
+                options.ondblclick(tabs[$(this).attr('href').slice(1)]);
+            }
+            return false;
+        }
+        
+        function activateTab(link) {
+            if (typeof link === "string") {
+                link = ul.find("a[href='#"+link+"']");
+            }
+            if (!link.parent().hasClass("active")) {
+                ul.children().removeClass("active");
+                link.parent().addClass("active");
+                if (options.onchange) {
+                    options.onchange(tabs[link.attr('href').slice(1)]);
+                }
+            }
+        }
+        
+        function updateTabWidths() {
+            var tabs = ul.find("li.red-ui-tab");
+            var width = ul.width();
+            var tabCount = tabs.size();
+            var tabWidth = (width-6-(tabCount*7))/tabCount;
+            var pct = 100*tabWidth/width;
+            tabs.css({width:pct+"%"});
+        }
+        
+        ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
+        updateTabWidths();
+        
+        
+        function removeTab(id) {
+            var li = ul.find("a[href='#"+id+"']").parent();
+            if (li.hasClass("active")) {
+                var tab = li.prev();
+                if (tab.size() === 0) {
+                    tab = li.next();
+                }
+                activateTab(tab.find("a"));
+            }
+            li.remove();
+            if (options.onremove) {
+                options.onremove(tabs[id]);
+            }
+            delete tabs[id];
+            updateTabWidths();
+        }
+        
+        return {
+            addTab: function(tab) {
+                tabs[tab.id] = tab;
+                var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
+                var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
+                link.html(tab.label);
+                
+                link.on("click",onTabClick);
+                link.on("dblclick",onTabDblClick);
+                if (tab.closeable) {
+                    var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
+                    closeLink.html('<i class="fa fa-times" />');
+                    
+                    closeLink.on("click",function(event) {
+                        removeTab(tab.id);
+                    });
+                }
+                updateTabWidths();
+                if (options.onadd) {
+                    options.onadd(tab);
+                }
+                link.attr("title",tab.label);
+                if (ul.find("li.red-ui-tab").size() == 1) {
+                    activateTab(link);
+                }
+            },
+            removeTab: removeTab,
+            activateTab: activateTab,
+            resize: updateTabWidths,
+            count: function() {
+                return ul.find("li.red-ui-tab").size();
+            },
+            contains: function(id) {
+                return ul.find("a[href='#"+id+"']").length > 0;
+            }
+
+        }
+    }
+    
+    return {
+        create: createTabs
+    }
+})();
diff --git a/dgbuilder/public/red/ui/touch/radialMenu.js b/dgbuilder/public/red/ui/touch/radialMenu.js
new file mode 100644 (file)
index 0000000..ffb6a71
--- /dev/null
@@ -0,0 +1,184 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+RED.touch = RED.touch||{};
+RED.touch.radialMenu = (function() {
+    
+    
+    var touchMenu = null;
+    var isActive = false;
+    var isOutside = false;
+    var activeOption = null;
+
+    
+    function createRadial(obj,pos,options) {
+        isActive = true;
+        try {
+            var w = $("body").width();
+            var h = $("body").height();
+            
+            touchMenu = d3.select("body").append("div")
+                .style({
+                        position:"absolute",
+                        top: 0,
+                        left:0,
+                        bottom:0,
+                        right:0,
+                        "z-index": 1000
+                })
+                .on('touchstart',function() {
+                    hide();
+                    d3.event.preventDefault();
+                });
+                    
+            
+
+    
+            var menu = touchMenu.append("div")
+                .style({
+                        position: "absolute",
+                        top: (pos[1]-80)+"px",
+                        left:(pos[0]-80)+"px",
+                        "border-radius": "80px",
+                        width: "160px",
+                        height: "160px",
+                        background: "rgba(255,255,255,0.6)",
+                        border: "1px solid #666"
+                });
+                
+            var menuOpts = [];
+            var createMenuOpt = function(x,y,opt) {
+                opt.el = menu.append("div")
+                    .style({
+                        position: "absolute",
+                        top: (y+80-25)+"px",
+                        left:(x+80-25)+"px",
+                        "border-radius": "20px",
+                        width: "50px",
+                        height: "50px",
+                        background: "#fff",
+                        border: "2px solid #666",
+                        "text-align": "center",
+                        "line-height":"50px"
+                    });
+                    
+                opt.el.html(opt.name);
+                
+                if (opt.disabled) {
+                    opt.el.style({"border-color":"#ccc",color:"#ccc"});
+                }
+                opt.x = x;
+                opt.y = y;
+                menuOpts.push(opt);
+                
+                opt.el.on('touchstart',function() {
+                    opt.el.style("background","#999");
+                    d3.event.preventDefault();
+                    d3.event.stopPropagation();
+                });
+                opt.el.on('touchend',function() {
+                    hide();
+                    opt.onselect();
+                    d3.event.preventDefault();
+                    d3.event.stopPropagation();
+                });
+            }
+            
+            var n = options.length;
+            var dang = Math.max(Math.PI/(n-1),Math.PI/4);
+            var ang = Math.PI;
+            for (var i=0;i<n;i++) {
+                var x = Math.floor(Math.cos(ang)*80);
+                var y = Math.floor(Math.sin(ang)*80);
+                if (options[i].name) {
+                    createMenuOpt(x,y,options[i]);
+                }
+                ang += dang;
+            }
+            
+
+            var hide = function() {
+                isActive = false;
+                activeOption = null;
+                touchMenu.remove();
+                touchMenu = null;
+            }
+                    
+            obj.on('touchend.radial',function() {
+                    obj.on('touchend.radial',null);
+                    obj.on('touchmenu.radial',null);
+                    
+                    if (activeOption) {
+                        try {
+                            activeOption.onselect();
+                        } catch(err) {
+                            RED._debug(err);
+                        }
+                        hide();
+                    } else if (isOutside) {
+                        hide();
+                    }
+            });
+
+
+            
+            obj.on('touchmove.radial',function() {
+            try {
+                var touch0 = d3.event.touches.item(0);
+                var p = [touch0.pageX - pos[0],touch0.pageY-pos[1]];
+                for (var i=0;i<menuOpts.length;i++) {
+                    var opt = menuOpts[i];
+                    if (!opt.disabled) {
+                        if (p[0]>opt.x-30 && p[0]<opt.x+30 && p[1]>opt.y-30 && p[1]<opt.y+30) {
+                            if (opt !== activeOption) {
+                                opt.el.style("background","#999");
+                                activeOption = opt;
+                            }
+                        } else if (opt === activeOption) {
+                            opt.el.style("background","#fff");
+                            activeOption = null;
+                        } else {
+                            opt.el.style("background","#fff");
+                        }
+                    }
+                }
+                if (!activeOption) {
+                    var d = Math.abs((p[0]*p[0])+(p[1]*p[1]));
+                    isOutside = (d > 80*80);
+                }
+                
+            } catch(err) {
+                RED._debug(err);
+            }
+
+                
+            });
+            
+        } catch(err) {
+            RED._debug(err);
+        }
+    }    
+
+    
+    return {
+        show: createRadial,
+        active: function() {
+            return isActive;
+        }
+    }
+
+})();
+
diff --git a/dgbuilder/public/red/ui/view.js b/dgbuilder/public/red/ui/view.js
new file mode 100644 (file)
index 0000000..707bde9
--- /dev/null
@@ -0,0 +1,2053 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+
+RED.view = (function() {
+       /* increasing the width and height from 5000 to 7500*/
+    var space_width = 7500,
+        space_height = 7500,
+        lineCurveScale = 0.75,
+        scaleFactor = 1,
+        node_width = 100,
+        node_height = 30;
+    
+    var touchLongPressTimeout = 1000,
+        startTouchDistance = 0,
+        startTouchCenter = [],
+        moveTouchCenter = [],
+        touchStartTime = 0;
+
+
+    var activeWorkspace = 0;
+    var workspaceScrollPositions = {};
+
+    var selected_link = null,
+        mousedown_link = null,
+        mousedown_node = null,
+        mousedown_port_type = null,
+        mousedown_port_index = 0,
+        mouseup_node = null,
+        mouse_offset = [0,0],
+        mouse_position = null,
+        mouse_mode = 0,
+        moving_set = [],
+        dirty = false,
+        lasso = null,
+        showStatus = false,
+        showNumbers = false,
+        showNodePalette = true,
+        lastClickNode = null,
+        dblClickPrimed = null,
+        clickTime = 0,
+        clickElapsed = 0;
+
+    var clipboard = "";
+
+    var status_colours = {
+        "red":    "#c00",
+        "green":  "#5a8",
+        "yellow": "#F9DF31",
+        "blue":   "#53A3F3",
+        "grey":   "#d3d3d3"
+    }
+
+    var outer = d3.select("#chart")
+        .append("svg:svg")
+        .attr("width", space_width)
+        .attr("height", space_height)
+        .attr("pointer-events", "all")
+        .style("cursor","crosshair");
+
+     var vis = outer
+        .append('svg:g')
+        .on("dblclick.zoom", null)
+        .append('svg:g')
+        .on("mousemove", canvasMouseMove)
+        .on("mousedown", canvasMouseDown)
+        .on("mouseup", canvasMouseUp)
+        .on("touchend", function() {
+            clearTimeout(touchStartTime);
+            touchStartTime = null;
+            if  (RED.touch.radialMenu.active()) {
+                return;
+            }
+            if (lasso) {
+                outer_background.attr("fill","#fff");
+            }
+            canvasMouseUp.call(this);
+        })
+        .on("touchcancel", canvasMouseUp)
+        .on("touchstart", function() {
+            var touch0;
+            if (d3.event.touches.length>1) {
+                clearTimeout(touchStartTime);
+                touchStartTime = null;
+                d3.event.preventDefault();
+                touch0 = d3.event.touches.item(0);
+                var touch1 = d3.event.touches.item(1);
+                var a = touch0['pageY']-touch1['pageY'];
+                var b = touch0['pageX']-touch1['pageX'];
+
+                var offset = $("#chart").offset();
+                var scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
+                startTouchCenter = [
+                    (touch1['pageX']+(b/2)-offset.left+scrollPos[0])/scaleFactor,
+                    (touch1['pageY']+(a/2)-offset.top+scrollPos[1])/scaleFactor
+                ];
+                moveTouchCenter = [
+                    touch1['pageX']+(b/2),
+                    touch1['pageY']+(a/2)
+                ]
+                startTouchDistance = Math.sqrt((a*a)+(b*b));
+            } else {
+                var obj = d3.select(document.body);
+                touch0 = d3.event.touches.item(0);
+                var pos = [touch0.pageX,touch0.pageY];
+                startTouchCenter = [touch0.pageX,touch0.pageY];
+                startTouchDistance = 0;
+                var point = d3.touches(this)[0];
+                touchStartTime = setTimeout(function() {
+                    touchStartTime = null;
+                    showTouchMenu(obj,pos);
+                    //lasso = vis.append('rect')
+                    //    .attr("ox",point[0])
+                    //    .attr("oy",point[1])
+                    //    .attr("rx",2)
+                    //    .attr("ry",2)
+                    //    .attr("x",point[0])
+                    //    .attr("y",point[1])
+                    //    .attr("width",0)
+                    //    .attr("height",0)
+                    //    .attr("class","lasso");
+                    //outer_background.attr("fill","#e3e3f3");
+                },touchLongPressTimeout);
+            }
+        })
+        .on("touchmove", function(){
+                if  (RED.touch.radialMenu.active()) {
+                    d3.event.preventDefault();
+                    return;
+                }
+                var touch0;
+                if (d3.event.touches.length<2) {
+                    if (touchStartTime) {
+                        touch0 = d3.event.touches.item(0);
+                        var dx = (touch0.pageX-startTouchCenter[0]);
+                        var dy = (touch0.pageY-startTouchCenter[1]);
+                        var d = Math.abs(dx*dx+dy*dy);
+                        if (d > 64) {
+                            clearTimeout(touchStartTime);
+                            touchStartTime = null;
+                        }
+                    } else if (lasso) {
+                        d3.event.preventDefault();
+                    }
+                    canvasMouseMove.call(this);
+                } else {
+                    touch0 = d3.event.touches.item(0);
+                    var touch1 = d3.event.touches.item(1);
+                    var a = touch0['pageY']-touch1['pageY'];
+                    var b = touch0['pageX']-touch1['pageX'];
+                    var offset = $("#chart").offset();
+                    var scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
+                    var moveTouchDistance = Math.sqrt((a*a)+(b*b));
+                    var touchCenter = [
+                        touch1['pageX']+(b/2),
+                        touch1['pageY']+(a/2)
+                    ];
+
+                    if (!isNaN(moveTouchDistance)) {
+                        oldScaleFactor = scaleFactor;
+                        scaleFactor = Math.min(2,Math.max(0.3, scaleFactor + (Math.floor(((moveTouchDistance*100)-(startTouchDistance*100)))/10000)));
+
+                        var deltaTouchCenter = [                             // Try to pan whilst zooming - not 100%
+                            startTouchCenter[0]*(scaleFactor-oldScaleFactor),//-(touchCenter[0]-moveTouchCenter[0]),
+                            startTouchCenter[1]*(scaleFactor-oldScaleFactor) //-(touchCenter[1]-moveTouchCenter[1])
+                        ];
+
+                        startTouchDistance = moveTouchDistance;
+                        moveTouchCenter = touchCenter;
+
+                        $("#chart").scrollLeft(scrollPos[0]+deltaTouchCenter[0]);
+                        $("#chart").scrollTop(scrollPos[1]+deltaTouchCenter[1]);
+                        redraw();
+                    }
+                }
+        });
+
+    var outer_background = vis.append('svg:rect')
+        .attr('width', space_width)
+        .attr('height', space_height)
+        .attr('fill','#fff');
+
+    //var gridScale = d3.scale.linear().range([0,2000]).domain([0,2000]);
+    //var grid = vis.append('g');
+    //
+    //grid.selectAll("line.horizontal").data(gridScale.ticks(100)).enter()
+    //    .append("line")
+    //        .attr(
+    //        {
+    //            "class":"horizontal",
+    //            "x1" : 0,
+    //            "x2" : 2000,
+    //            "y1" : function(d){ return gridScale(d);},
+    //            "y2" : function(d){ return gridScale(d);},
+    //            "fill" : "none",
+    //            "shape-rendering" : "crispEdges",
+    //            "stroke" : "#eee",
+    //            "stroke-width" : "1px"
+    //        });
+    //grid.selectAll("line.vertical").data(gridScale.ticks(100)).enter()
+    //    .append("line")
+    //        .attr(
+    //        {
+    //            "class":"vertical",
+    //            "y1" : 0,
+    //            "y2" : 2000,
+    //            "x1" : function(d){ return gridScale(d);},
+    //            "x2" : function(d){ return gridScale(d);},
+    //            "fill" : "none",
+    //            "shape-rendering" : "crispEdges",
+    //            "stroke" : "#eee",
+    //            "stroke-width" : "1px"
+    //        });
+
+
+    var drag_line = vis.append("svg:path").attr("class", "drag_line");
+
+    var workspace_tabs = RED.tabs.create({
+        id: "workspace-tabs",
+        onchange: function(tab) {
+            if (tab.type == "subflow") {
+                $("#workspace-toolbar").show();
+            } else {
+                $("#workspace-toolbar").hide();
+            }
+            var chart = $("#chart");
+            if (activeWorkspace !== 0) {
+                workspaceScrollPositions[activeWorkspace] = {
+                    left:chart.scrollLeft(),
+                    top:chart.scrollTop()
+                };
+            }
+            var scrollStartLeft = chart.scrollLeft();
+            var scrollStartTop = chart.scrollTop();
+
+            activeWorkspace = tab.id;
+            if (workspaceScrollPositions[activeWorkspace]) {
+                chart.scrollLeft(workspaceScrollPositions[activeWorkspace].left);
+                chart.scrollTop(workspaceScrollPositions[activeWorkspace].top);
+            } else {
+                chart.scrollLeft(0);
+                chart.scrollTop(0);
+            }
+            var scrollDeltaLeft = chart.scrollLeft() - scrollStartLeft;
+            var scrollDeltaTop = chart.scrollTop() - scrollStartTop;
+            if (mouse_position != null) {
+                mouse_position[0] += scrollDeltaLeft;
+                mouse_position[1] += scrollDeltaTop;
+            }
+
+            clearSelection();
+            RED.nodes.eachNode(function(n) {
+                    n.dirty = true;
+            });
+            redraw();
+        },
+        ondblclick: function(tab) {
+            showRenameWorkspaceDialog(tab.id);
+        },
+        onadd: function(tab) {
+            RED.menu.addItem("btn-workspace-menu",{
+                id:"btn-workspace-menu-"+tab.id.replace(".","-"),
+                label:tab.label,
+                onselect:function() {
+                    workspace_tabs.activateTab(tab.id);
+                }
+            });
+            RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
+        },
+        onremove: function(tab) {
+            RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
+            RED.menu.removeItem("btn-workspace-menu-"+tab.id.replace(".","-"));
+        }
+    });
+
+    var workspaceIndex = 0;
+
+    function addWorkspace() {
+        var tabId = RED.nodes.id();
+        do {
+            workspaceIndex += 1;
+        } while($("#workspace-tabs a[title='Sheet "+workspaceIndex+"']").size() !== 0);
+
+        var ws = {type:"tab",id:tabId,label:"Sheet "+workspaceIndex};
+        RED.nodes.addWorkspace(ws);
+        workspace_tabs.addTab(ws);
+        workspace_tabs.activateTab(tabId);
+        RED.history.push({t:'add',workspaces:[ws],dirty:dirty});
+        RED.view.dirty(true);
+    }
+    $(function() {
+        $('#btn-workspace-add-tab').on("click",addWorkspace);
+        $('#btn-workspace-add').on("click",addWorkspace);
+        $('#btn-workspace-edit').on("click",function() {
+            showRenameWorkspaceDialog(activeWorkspace);
+        });
+        $('#btn-workspace-delete').on("click",function() {
+            deleteWorkspace(activeWorkspace);
+        });
+    });
+
+    function deleteWorkspace(id) {
+        if (workspace_tabs.count() == 1) {
+            return;
+        }
+        var ws = RED.nodes.workspace(id);
+        $( "#node-dialog-delete-workspace" ).dialog('option','workspace',ws);
+        $( "#node-dialog-delete-workspace-name" ).text(ws.label);
+        $( "#node-dialog-delete-workspace" ).dialog('open');
+    }
+
+    function canvasMouseDown() {
+        if (!mousedown_node && !mousedown_link) {
+            selected_link = null;
+            updateSelection();
+        }
+        if (mouse_mode === 0) {
+            if (lasso) {
+                lasso.remove();
+                lasso = null;
+            }
+            
+            if (!touchStartTime) {
+                var point = d3.mouse(this);
+                lasso = vis.append('rect')
+                    .attr("ox",point[0])
+                    .attr("oy",point[1])
+                    .attr("rx",2)
+                    .attr("ry",2)
+                    .attr("x",point[0])
+                    .attr("y",point[1])
+                    .attr("width",0)
+                    .attr("height",0)
+                    .attr("class","lasso");
+                d3.event.preventDefault();
+            }
+        }
+    }
+
+    function canvasMouseMove() {
+        mouse_position = d3.touches(this)[0]||d3.mouse(this);
+
+        // Prevent touch scrolling...
+        //if (d3.touches(this)[0]) {
+        //    d3.event.preventDefault();
+        //}
+
+        // TODO: auto scroll the container
+        //var point = d3.mouse(this);
+        //if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; }
+        //console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop);
+
+        if (lasso) {
+            var ox = parseInt(lasso.attr("ox"));
+            var oy = parseInt(lasso.attr("oy"));
+            var x = parseInt(lasso.attr("x"));
+            var y = parseInt(lasso.attr("y"));
+            var w;
+            var h;
+            if (mouse_position[0] < ox) {
+                x = mouse_position[0];
+                w = ox-x;
+            } else {
+                w = mouse_position[0]-x;
+            }
+            if (mouse_position[1] < oy) {
+                y = mouse_position[1];
+                h = oy-y;
+            } else {
+                h = mouse_position[1]-y;
+            }
+            lasso
+                .attr("x",x)
+                .attr("y",y)
+                .attr("width",w)
+                .attr("height",h)
+            ;
+            return;
+        }
+
+        if (mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && selected_link == null) {
+            return;
+        }
+
+        var mousePos;
+        if (mouse_mode == RED.state.JOINING) {
+            // update drag line
+            drag_line.attr("class", "drag_line");
+            mousePos = mouse_position;
+            var numOutputs = (mousedown_port_type === 0)?(mousedown_node.outputs || 1):1;
+            var sourcePort = mousedown_port_index;
+            var portY = -((numOutputs-1)/2)*13 +13*sourcePort;
+
+            var sc = (mousedown_port_type === 0)?1:-1;
+
+            var dy = mousePos[1]-(mousedown_node.y+portY);
+            var dx = mousePos[0]-(mousedown_node.x+sc*mousedown_node.w/2);
+            var delta = Math.sqrt(dy*dy+dx*dx);
+            var scale = lineCurveScale;
+            var scaleY = 0;
+
+            if (delta < node_width) {
+                scale = 0.75-0.75*((node_width-delta)/node_width);
+            }
+            if (dx*sc < 0) {
+                scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
+                if (Math.abs(dy) < 3*node_height) {
+                    scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
+                }
+            }
+
+            drag_line.attr("d",
+                "M "+(mousedown_node.x+sc*mousedown_node.w/2)+" "+(mousedown_node.y+portY)+
+                " C "+(mousedown_node.x+sc*(mousedown_node.w/2+node_width*scale))+" "+(mousedown_node.y+portY+scaleY*node_height)+" "+
+                (mousePos[0]-sc*(scale)*node_width)+" "+(mousePos[1]-scaleY*node_height)+" "+
+                mousePos[0]+" "+mousePos[1]
+                );
+            d3.event.preventDefault();
+        } else if (mouse_mode == RED.state.MOVING) {
+               //console.log("node mouse moving");
+            mousePos = mouse_position;
+            var d = (mouse_offset[0]-mousePos[0])*(mouse_offset[0]-mousePos[0]) + (mouse_offset[1]-mousePos[1])*(mouse_offset[1]-mousePos[1]);
+            if (d > 2) {
+                mouse_mode = RED.state.MOVING_ACTIVE;
+                clickElapsed = 0;
+            }
+        } else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING) {
+               //console.log("node mouse moving active or IMPORT_DRAGGING");
+            mousePos = mouse_position;
+            var node;
+            var i;
+            var minX = 0;
+            var minY = 0;
+            for (var n = 0; n<moving_set.length; n++) {
+                node = moving_set[n];
+                if (d3.event.shiftKey) {
+                    node.n.ox = node.n.x;
+                    node.n.oy = node.n.y;
+                }
+                node.n.x = mousePos[0]+node.dx;
+                node.n.y = mousePos[1]+node.dy;
+                node.n.dirty = true;
+                minX = Math.min(node.n.x-node.n.w/2-5,minX);
+                minY = Math.min(node.n.y-node.n.h/2-5,minY);
+            }
+            if (minX !== 0 || minY !== 0) {
+                for (i = 0; i<moving_set.length; i++) {
+                    node = moving_set[i];
+                    node.n.x -= minX;
+                    node.n.y -= minY;
+                }
+            }
+            if (d3.event.shiftKey && moving_set.length > 0) {
+                var gridOffset =  [0,0];
+                node = moving_set[0];
+                gridOffset[0] = node.n.x-(20*Math.floor((node.n.x-node.n.w/2)/20)+node.n.w/2);
+                gridOffset[1] = node.n.y-(20*Math.floor(node.n.y/20));
+                if (gridOffset[0] !== 0 || gridOffset[1] !== 0) {
+                    for (i = 0; i<moving_set.length; i++) {
+                        node = moving_set[i];
+                        node.n.x -= gridOffset[0];
+                        node.n.y -= gridOffset[1];
+                        if (node.n.x == node.n.ox && node.n.y == node.n.oy) {
+                            node.dirty = false;
+                        }
+                    }
+                }
+            }
+        }
+        redraw();
+    }
+
+    function canvasMouseUp() {
+        if (mousedown_node && mouse_mode == RED.state.JOINING) {
+            drag_line.attr("class", "drag_line_hidden");
+        }
+        if (lasso) {
+            var x = parseInt(lasso.attr("x"));
+            var y = parseInt(lasso.attr("y"));
+            var x2 = x+parseInt(lasso.attr("width"));
+            var y2 = y+parseInt(lasso.attr("height"));
+            if (!d3.event.ctrlKey) {
+                clearSelection();
+            }
+            RED.nodes.eachNode(function(n) {
+                if (n.z == activeWorkspace && !n.selected) {
+                    n.selected = (n.x > x && n.x < x2 && n.y > y && n.y < y2);
+                    if (n.selected) {
+                        n.dirty = true;
+                        moving_set.push({n:n});
+                    }
+                }
+            });
+            updateSelection();
+            lasso.remove();
+            lasso = null;
+        } else if (mouse_mode == RED.state.DEFAULT && mousedown_link == null && !d3.event.ctrlKey ) {
+            clearSelection();
+            updateSelection();
+        }
+        if (mouse_mode == RED.state.MOVING_ACTIVE) {
+               //console.log("node moved active.");
+               //CSS setting view dirty if the node was moved 
+               //RED.view.dirty(true);
+            if (moving_set.length > 0) {
+                var ns = [];
+                for (var j=0;j<moving_set.length;j++) {
+                    ns.push({n:moving_set[j].n,ox:moving_set[j].ox,oy:moving_set[j].oy});
+                }
+                RED.history.push({t:'move',nodes:ns,dirty:dirty});
+            }
+        }
+        if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
+               //console.log("node moving or MOVING_ACTIVE.");
+            for (var i=0;i<moving_set.length;i++) {
+                delete moving_set[i].ox;
+                delete moving_set[i].oy;
+            }
+        }
+        if (mouse_mode == RED.state.IMPORT_DRAGGING) {
+            RED.keyboard.remove(/* ESCAPE */ 27);
+            setDirty(true);
+        }
+        redraw();
+        // clear mouse event vars
+        resetMouseVars();
+    }
+
+    $('#btn-zoom-out').click(function() {zoomOut();});
+    $('#btn-zoom-zero').click(function() {zoomZero();});
+    $('#btn-zoom-in').click(function() {zoomIn();});
+    $("#chart").on('DOMMouseScroll mousewheel', function (evt) {
+        if ( evt.altKey ) {
+            evt.preventDefault();
+            evt.stopPropagation();
+            var move = -(evt.originalEvent.detail) || evt.originalEvent.wheelDelta;
+            if (move <= 0) { zoomOut(); }
+            else { zoomIn(); }
+        }
+    });
+    $("#chart").droppable({
+            accept:".palette_node",
+            drop: function( event, ui ) {
+                d3.event = event;
+                var selected_tool = ui.draggable[0].type;
+                var mousePos = d3.touches(this)[0]||d3.mouse(this);
+                mousePos[1] += this.scrollTop;
+                mousePos[0] += this.scrollLeft;
+                mousePos[1] /= scaleFactor;
+                mousePos[0] /= scaleFactor;
+
+                var nn = { id:(1+Math.random()*4294967295).toString(16),x: mousePos[0],y:mousePos[1],w:node_width,z:activeWorkspace};
+
+                nn.type = selected_tool;
+                nn._def = RED.nodes.getType(nn.type);
+                nn.outputs = nn._def.outputs;
+                nn.changed = true;
+
+                for (var d in nn._def.defaults) {
+                    if (nn._def.defaults.hasOwnProperty(d)) {
+                        nn[d] = nn._def.defaults[d].value;
+                    }
+                }
+
+                if (nn._def.onadd) {
+                    nn._def.onadd.call(nn);
+                }
+
+                nn.h = Math.max(node_height,(nn.outputs||0) * 15);
+                RED.history.push({t:'add',nodes:[nn.id],dirty:dirty});
+                RED.nodes.add(nn);
+                RED.editor.validateNode(nn);
+                setDirty(true);
+                // auto select dropped node - so info shows (if visible)
+                clearSelection();
+                nn.selected = true;
+                moving_set.push({n:nn});
+                updateSelection();
+                redraw();
+
+                if (nn._def.autoedit) {
+                    RED.editor.edit(nn);
+                }
+            }
+    });
+
+    function zoomIn() {
+        if (scaleFactor < 2) {
+            scaleFactor += 0.1;
+            redraw();
+        }
+    }
+    function zoomOut() {
+        if (scaleFactor > 0.3) {
+            scaleFactor -= 0.1;
+            redraw();
+        }
+    }
+    function zoomZero() {
+        scaleFactor = 1;
+        redraw();
+    }
+
+    function selectAll() {
+        RED.nodes.eachNode(function(n) {
+            if (n.z == activeWorkspace) {
+                if (!n.selected) {
+                    n.selected = true;
+                    n.dirty = true;
+                    moving_set.push({n:n});
+                }
+            }
+        });
+        selected_link = null;
+        updateSelection();
+        redraw();
+    }
+
+    function clearSelection() {
+        for (var i=0;i<moving_set.length;i++) {
+            var n = moving_set[i];
+            n.n.dirty = true;
+            n.n.selected = false;
+        }
+        moving_set = [];
+        selected_link = null;
+    }
+
+    function updateSelection() {
+        if (moving_set.length === 0) {
+            RED.menu.setDisabled("btn-export-menu",true);
+            RED.menu.setDisabled("btn-export-clipboard",true);
+            RED.menu.setDisabled("btn-export-library",true);
+        } else {
+            RED.menu.setDisabled("btn-export-menu",false);
+            RED.menu.setDisabled("btn-export-clipboard",false);
+            RED.menu.setDisabled("btn-export-library",false);
+        }
+        if (moving_set.length === 0 && selected_link == null) {
+            //RED.keyboard.remove(/* backspace */ 8);
+            RED.keyboard.remove(/* delete */ 46);
+            RED.keyboard.remove(/* c */ 67);
+            RED.keyboard.remove(/* x */ 88);
+        } else {
+            //RED.keyboard.add(/* backspace */ 8,function(){deleteSelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* delete */ 46,function(){deleteSelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* c */ 67,{ctrl:true},function(){copySelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* x */ 88,{ctrl:true},function(){copySelection();deleteSelection();d3.event.preventDefault();});
+        }
+        if (moving_set.length === 0) {
+            RED.keyboard.remove(/* up   */ 38);
+            RED.keyboard.remove(/* down */ 40);
+            RED.keyboard.remove(/* left */ 37);
+            RED.keyboard.remove(/* right*/ 39);
+        } else {
+            RED.keyboard.add(/* up   */ 38, function() { if(d3.event.shiftKey){moveSelection(  0,-20)}else{moveSelection( 0,-1);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* down */ 40, function() { if(d3.event.shiftKey){moveSelection(  0, 20)}else{moveSelection( 0, 1);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* left */ 37, function() { if(d3.event.shiftKey){moveSelection(-20,  0)}else{moveSelection(-1, 0);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* right*/ 39, function() { if(d3.event.shiftKey){moveSelection( 20,  0)}else{moveSelection( 1, 0);}d3.event.preventDefault();},endKeyboardMove);
+        }
+        if (moving_set.length == 1) {
+            RED.sidebar.info.refresh(moving_set[0].n);
+        } else {
+            RED.sidebar.info.clear();
+        }
+    }
+    function endKeyboardMove() {
+       //console.log("end keyboard move.");
+       //CSS setting view dirty if the node was moved 
+       //RED.view.dirty(true);
+        var ns = [];
+        for (var i=0;i<moving_set.length;i++) {
+            ns.push({n:moving_set[i].n,ox:moving_set[i].ox,oy:moving_set[i].oy});
+            delete moving_set[i].ox;
+            delete moving_set[i].oy;
+        }
+        RED.history.push({t:'move',nodes:ns,dirty:dirty});
+    }
+    function moveSelection(dx,dy) {
+        var minX = 0;
+        var minY = 0;
+        var node;
+        
+        for (var i=0;i<moving_set.length;i++) {
+            node = moving_set[i];
+            if (node.ox == null && node.oy == null) {
+                node.ox = node.n.x;
+                node.oy = node.n.y;
+            }
+            node.n.x += dx;
+            node.n.y += dy;
+            node.n.dirty = true;
+            minX = Math.min(node.n.x-node.n.w/2-5,minX);
+            minY = Math.min(node.n.y-node.n.h/2-5,minY);
+        }
+
+        if (minX !== 0 || minY !== 0) {
+            for (var n = 0; n<moving_set.length; n++) {
+                node = moving_set[n];
+                node.n.x -= minX;
+                node.n.y -= minY;
+            }
+        }
+
+        redraw();
+    }
+    function deleteSelection() {
+        var removedNodes = [];
+        var removedLinks = [];
+        var startDirty = dirty;
+        if (moving_set.length > 0) {
+            for (var i=0;i<moving_set.length;i++) {
+                var node = moving_set[i].n;
+                node.selected = false;
+                if (node.x < 0) {
+                    node.x = 25
+                }
+                var rmlinks = RED.nodes.remove(node.id);
+                removedNodes.push(node);
+                removedLinks = removedLinks.concat(rmlinks);
+            }
+            moving_set = [];
+            setDirty(true);
+        }
+        if (selected_link) {
+            RED.nodes.removeLink(selected_link);
+            removedLinks.push(selected_link);
+            setDirty(true);
+        }
+        RED.history.push({t:'delete',nodes:removedNodes,links:removedLinks,dirty:startDirty});
+
+        selected_link = null;
+        updateSelection();
+        redraw();
+    }
+
+    function copySelection() {
+        if (moving_set.length > 0) {
+            var nns = [];
+            for (var n=0;n<moving_set.length;n++) {
+                var node = moving_set[n].n;
+                nns.push(RED.nodes.convertNode(node));
+            }
+            clipboard = JSON.stringify(nns);
+            RED.notify(moving_set.length+" node"+(moving_set.length>1?"s":"")+" copied");
+        }
+    }
+
+
+    function calculateTextWidth(str) {
+        var sp = document.createElement("span");
+        sp.className = "node_label";
+        sp.style.position = "absolute";
+        sp.style.top = "-1000px";
+        sp.innerHTML = (str||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+        document.body.appendChild(sp);
+        var w = sp.offsetWidth;
+        document.body.removeChild(sp);
+        return 50+w;
+    }
+
+    function resetMouseVars() {
+        mousedown_node = null;
+        mouseup_node = null;
+        mousedown_link = null;
+        mouse_mode = 0;
+        mousedown_port_type = 0;
+    }
+
+    function portMouseDown(d,portType,portIndex) {
+        // disable zoom
+        //vis.call(d3.behavior.zoom().on("zoom"), null);
+        mousedown_node = d;
+        selected_link = null;
+        mouse_mode = RED.state.JOINING;
+        mousedown_port_type = portType;
+        mousedown_port_index = portIndex || 0;
+        document.body.style.cursor = "crosshair";
+        d3.event.preventDefault();
+    }
+
+    function portMouseUp(d,portType,portIndex) {
+        document.body.style.cursor = "";
+        if (mouse_mode == RED.state.JOINING && mousedown_node) {
+            if (typeof TouchEvent != "undefined" && d3.event instanceof TouchEvent) {
+                RED.nodes.eachNode(function(n) {
+                        if (n.z == activeWorkspace) {
+                            var hw = n.w/2;
+                            var hh = n.h/2;
+                            if (n.x-hw<mouse_position[0] && n.x+hw> mouse_position[0] &&
+                                n.y-hh<mouse_position[1] && n.y+hh>mouse_position[1]) {
+                                    mouseup_node = n;
+                                    portType = mouseup_node._def.inputs>0?1:0;
+                                    portIndex = 0;
+                            }
+                        }
+                });
+            } else {
+                mouseup_node = d;
+            }
+            if (portType == mousedown_port_type || mouseup_node === mousedown_node) {
+                drag_line.attr("class", "drag_line_hidden");
+                resetMouseVars();
+                return;
+            }
+            var src,dst,src_port;
+            if (mousedown_port_type === 0) {
+                src = mousedown_node;
+                src_port = mousedown_port_index;
+                dst = mouseup_node;
+            } else if (mousedown_port_type == 1) {
+                src = mouseup_node;
+                dst = mousedown_node;
+                src_port = portIndex;
+            }
+
+            var existingLink = false;
+            RED.nodes.eachLink(function(d) {
+                    existingLink = existingLink || (d.source === src && d.target === dst && d.sourcePort == src_port);
+            });
+            if (!existingLink) {
+                var link = {source: src, sourcePort:src_port, target: dst};
+                RED.nodes.addLink(link);
+                RED.history.push({t:'add',links:[link],dirty:dirty});
+                setDirty(true);
+            }
+            selected_link = null;
+            redraw();
+        }
+    }
+
+    function nodeMouseUp(d) {
+        if (dblClickPrimed && mousedown_node == d && clickElapsed > 0 && clickElapsed < 750) {
+            RED.editor.edit(d);
+            clickElapsed = 0;
+            d3.event.stopPropagation();
+            return;
+        }
+        portMouseUp(d, d._def.inputs > 0 ? 1 : 0, 0);
+    }
+
+    function nodeMouseDown(d) {
+        //var touch0 = d3.event;
+        //var pos = [touch0.pageX,touch0.pageY];
+        //RED.touch.radialMenu.show(d3.select(this),pos);
+        if (mouse_mode == RED.state.IMPORT_DRAGGING) {
+            RED.keyboard.remove(/* ESCAPE */ 27);
+            updateSelection();
+            setDirty(true);
+            redraw();
+            resetMouseVars();
+            d3.event.stopPropagation();
+            return;
+        }
+        mousedown_node = d;
+        var now = Date.now();
+        clickElapsed = now-clickTime;
+        clickTime = now;
+
+        dblClickPrimed = (lastClickNode == mousedown_node);
+        lastClickNode = mousedown_node;
+        
+        var i;
+        
+        if (d.selected && d3.event.ctrlKey) {
+            d.selected = false;
+            for (i=0;i<moving_set.length;i+=1) {
+                if (moving_set[i].n === d) {
+                    moving_set.splice(i,1);
+                    break;
+                }
+            }
+        } else {
+            if (d3.event.shiftKey) {
+                clearSelection();
+                var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
+                for (var n=0;n<cnodes.length;n++) {
+                    cnodes[n].selected = true;
+                    cnodes[n].dirty = true;
+                    moving_set.push({n:cnodes[n]});
+                }
+            } else if (!d.selected) {
+                if (!d3.event.ctrlKey) {
+                    clearSelection();
+                }
+                mousedown_node.selected = true;
+                moving_set.push({n:mousedown_node});
+            }
+            selected_link = null;
+            if (d3.event.button != 2) {
+                mouse_mode = RED.state.MOVING;
+                var mouse = d3.touches(this)[0]||d3.mouse(this);
+                mouse[0] += d.x-d.w/2;
+                mouse[1] += d.y-d.h/2;
+                for (i=0;i<moving_set.length;i++) {
+                    moving_set[i].ox = moving_set[i].n.x;
+                    moving_set[i].oy = moving_set[i].n.y;
+                    moving_set[i].dx = moving_set[i].n.x-mouse[0];
+                    moving_set[i].dy = moving_set[i].n.y-mouse[1];
+                }
+                mouse_offset = d3.mouse(document.body);
+                if (isNaN(mouse_offset[0])) {
+                    mouse_offset = d3.touches(document.body)[0];
+                }
+            }
+        }
+        d.dirty = true;
+        updateSelection();
+        redraw();
+        d3.event.stopPropagation();
+    }
+
+    function nodeButtonClicked(d) {
+        if (d._def.button.toggle) {
+            d[d._def.button.toggle] = !d[d._def.button.toggle];
+            d.dirty = true;
+        }
+        if (d._def.button.onclick) {
+            d._def.button.onclick.call(d);
+        }
+        if (d.dirty) {
+            redraw();
+        }
+        d3.event.preventDefault();
+    }
+
+    function showTouchMenu(obj,pos) {
+        var mdn = mousedown_node;
+        var options = [];
+        options.push({name:"delete",disabled:(moving_set.length===0),onselect:function() {deleteSelection();}});
+        options.push({name:"cut",disabled:(moving_set.length===0),onselect:function() {copySelection();deleteSelection();}});
+        options.push({name:"copy",disabled:(moving_set.length===0),onselect:function() {copySelection();}});
+        options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard,true);}});
+        options.push({name:"edit",disabled:(moving_set.length != 1),onselect:function() { RED.editor.edit(mdn);}});
+        options.push({name:"select",onselect:function() {selectAll();}});
+        options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
+        
+        RED.touch.radialMenu.show(obj,pos,options);
+        resetMouseVars();
+    }
+    function redraw() {
+        vis.attr("transform","scale("+scaleFactor+")");
+        outer.attr("width", space_width*scaleFactor).attr("height", space_height*scaleFactor);
+
+        if (mouse_mode != RED.state.JOINING) {
+            // Don't bother redrawing nodes if we're drawing links
+
+            var node = vis.selectAll(".nodegroup").data(RED.nodes.nodes.filter(function(d) { return d.z == activeWorkspace }),function(d){return d.id});
+            node.exit().remove();
+
+            var nodeEnter = node.enter().insert("svg:g").attr("class", "node nodegroup");
+            nodeEnter.each(function(d,i) {
+                    var node = d3.select(this);
+                    node.attr("id",d.id);
+                    var l = d._def.label;
+                    l = (typeof l === "function" ? l.call(d) : l)||"";
+                    d.w = Math.max(node_width,calculateTextWidth(l)+(d._def.inputs>0?7:0) );
+                    d.h = Math.max(node_height,(d.outputs||0) * 15);
+
+                    if (d._def.badge) {
+                        var badge = node.append("svg:g").attr("class","node_badge_group");
+                        var badgeRect = badge.append("rect").attr("class","node_badge").attr("rx",5).attr("ry",5).attr("width",40).attr("height",15);
+                        badge.append("svg:text").attr("class","node_badge_label").attr("x",35).attr("y",11).attr('text-anchor','end').text(d._def.badge());
+                        if (d._def.onbadgeclick) {
+                            badgeRect.attr("cursor","pointer")
+                                .on("click",function(d) { d._def.onbadgeclick.call(d);d3.event.preventDefault();});
+                        }
+                    }
+
+                    if (d._def.button) {
+                        var nodeButtonGroup = node.append('svg:g')
+                            .attr("transform",function(d) { return "translate("+((d._def.align == "right") ? 94 : -25)+",2)"; })
+                            .attr("class",function(d) { return "node_button "+((d._def.align == "right") ? "node_right_button" : "node_left_button"); });
+                        nodeButtonGroup.append('rect')
+                            .attr("rx",8)
+                            .attr("ry",8)
+                            .attr("width",32)
+                            .attr("height",node_height-4)
+                            .attr("fill","#eee");//function(d) { return d._def.color;})
+                        nodeButtonGroup.append('rect')
+                            .attr("x",function(d) { return d._def.align == "right"? 10:5})
+                            .attr("y",4)
+                            .attr("rx",5)
+                            .attr("ry",5)
+                            .attr("width",16)
+                            .attr("height",node_height-12)
+                            .attr("fill",function(d) { return d._def.color;})
+                            .attr("cursor","pointer")
+                            .on("mousedown",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.2);d3.event.preventDefault(); d3.event.stopPropagation();}})
+                            .on("mouseup",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.4);d3.event.preventDefault();d3.event.stopPropagation();}})
+                            .on("mouseover",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.4);}})
+                            .on("mouseout",function(d) {if (!lasso) {
+                                var op = 1;
+                                if (d._def.button.toggle) {
+                                    op = d[d._def.button.toggle]?1:0.2;
+                                }
+                                d3.select(this).attr("fill-opacity",op);
+                            }})
+                            .on("click",nodeButtonClicked)
+                            .on("touchstart",nodeButtonClicked)
+                    }
+
+                    var mainRect = node.append("rect")
+                        .attr("class", "node")
+                        .classed("node_unknown",function(d) { return d.type == "unknown"; })
+                        .attr("rx", 6)
+                        .attr("ry", 6)
+                        .attr("fill",function(d) { return d._def.color;})
+                        .on("mouseup",nodeMouseUp)
+                        .on("mousedown",nodeMouseDown)
+                        .on("touchstart",function(d) {
+                            var obj = d3.select(this);
+                            var touch0 = d3.event.touches.item(0);
+                            var pos = [touch0.pageX,touch0.pageY];
+                            startTouchCenter = [touch0.pageX,touch0.pageY];
+                            startTouchDistance = 0;
+                            touchStartTime = setTimeout(function() {
+                                showTouchMenu(obj,pos);
+                            },touchLongPressTimeout);
+                            nodeMouseDown.call(this,d)       
+                        })
+                        .on("touchend", function(d) {
+                            clearTimeout(touchStartTime);
+                            touchStartTime = null;
+                            if  (RED.touch.radialMenu.active()) {
+                                d3.event.stopPropagation();
+                                return;
+                            }
+                            nodeMouseUp.call(this,d);
+                        })
+                        .on("mouseover",function(d) {
+                                if (mouse_mode === 0) {
+                                    var node = d3.select(this);
+                                    node.classed("node_hovered",true);
+                                }
+                        })
+                        .on("mouseout",function(d) {
+                                var node = d3.select(this);
+                                node.classed("node_hovered",false);
+                        });
+
+                   //node.append("rect").attr("class", "node-gradient-top").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-top)").style("pointer-events","none");
+                   //node.append("rect").attr("class", "node-gradient-bottom").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-bottom)").style("pointer-events","none");
+
+                    if (d._def.icon) {
+                        
+                        var icon_group = node.append("g")
+                            .attr("class","node_icon_group")
+                            .attr("x",0).attr("y",0);
+                        
+                        var icon_shade = icon_group.append("rect")
+                            .attr("x",0).attr("y",0)
+                            .attr("class","node_icon_shade")
+                            .attr("width","30")
+                            .attr("stroke","none")
+                            .attr("fill","#000")
+                            .attr("fill-opacity","0.05")
+                            .attr("height",function(d){return Math.min(50,d.h-4);});
+                            
+                        var icon = icon_group.append("image")
+                            .attr("xlink:href","icons/"+d._def.icon)
+                            .attr("class","node_icon")
+                            .attr("x",0)
+                            .attr("width","30")
+                            .attr("height","30");
+                            
+                        var icon_shade_border = icon_group.append("path")
+                            .attr("d",function(d) { return "M 30 1 l 0 "+(d.h-2)})
+                            .attr("class","node_icon_shade_border")
+                            .attr("stroke-opacity","0.1")
+                            .attr("stroke","#000")
+                            .attr("stroke-width","2");
+
+                        if ("right" == d._def.align) {
+                            icon_group.attr('class','node_icon_group node_icon_group_'+d._def.align);
+                            icon_shade_border.attr("d",function(d) { return "M 0 1 l 0 "+(d.h-2)})
+                            //icon.attr('class','node_icon node_icon_'+d._def.align);
+                            //icon.attr('class','node_icon_shade node_icon_shade_'+d._def.align);
+                            //icon.attr('class','node_icon_shade_border node_icon_shade_border_'+d._def.align);
+                        }
+                        
+                        //if (d._def.inputs > 0 && d._def.align == null) {
+                        //    icon_shade.attr("width",35);
+                        //    icon.attr("transform","translate(5,0)");
+                        //    icon_shade_border.attr("transform","translate(5,0)");
+                        //}
+                        //if (d._def.outputs > 0 && "right" == d._def.align) {
+                        //    icon_shade.attr("width",35); //icon.attr("x",5);
+                        //}
+                        
+                        var img = new Image();
+                        img.src = "icons/"+d._def.icon;
+                        img.onload = function() {
+                            icon.attr("width",Math.min(img.width,30));
+                            icon.attr("height",Math.min(img.height,30));
+                            icon.attr("x",15-Math.min(img.width,30)/2);
+                            //if ("right" == d._def.align) {
+                            //    icon.attr("x",function(d){return d.w-img.width-1-(d.outputs>0?5:0);});
+                            //    icon_shade.attr("x",function(d){return d.w-30});
+                            //    icon_shade_border.attr("d",function(d){return "M "+(d.w-30)+" 1 l 0 "+(d.h-2);});
+                            //}
+                        }
+                        
+                        //icon.style("pointer-events","none");
+                        icon_group.style("pointer-events","none");
+                    }
+                    var text = node.append('svg:text').attr('class','node_label').attr('x', 38).attr('dy', '.35em').attr('text-anchor','start');
+                    if (d._def.align) {
+                        text.attr('class','node_label node_label_'+d._def.align);
+                        text.attr('text-anchor','end');
+                    }
+
+                    var status = node.append("svg:g").attr("class","node_status_group").style("display","none");
+
+                    var statusRect = status.append("rect").attr("class","node_status")
+                                        .attr("x",6).attr("y",1).attr("width",9).attr("height",9)
+                                        .attr("rx",2).attr("ry",2).attr("stroke-width","3");
+
+                    var statusLabel = status.append("svg:text")
+                        .attr("class","node_status_label")
+                        .attr('x',20).attr('y',9)
+                        .style({
+                                'stroke-width': 0,
+                                'fill': '#888',
+                                'font-size':'9pt',
+                                'stroke':'#000',
+                                'text-anchor':'start'
+                        });
+
+                    var dgNumber = node.append("svg:g").attr("class","node_dgnumber_group").style("display","none");
+
+                    /*var dgNumberRect = dgNumber.append("rect").attr("class","node_dgnumber")
+                                        .attr("x",6).attr("y",-49).attr("width",9).attr("height",9)
+                                        .attr("rx",2).attr("ry",2).attr("stroke-width","3");
+                       */
+
+                    var dgNumberLabel = dgNumber.append("svg:text")
+                        .attr("class","node_dgnumber_label")
+                        .attr('x',1).attr('y',-43)
+                        .style({
+                                'stroke-width': 0,
+                                /*'fill': '#2E4F83',*/
+                                'fill': 'blue',
+                                'font-size':'12pt',
+                                'stroke':'#000',
+                                'text-anchor':'start'
+                        });
+
+                   var dgNumberTitle = dgNumber.append("title")
+                                       .attr("class","node_dgnumber_title");
+
+                    //node.append("circle").attr({"class":"centerDot","cx":0,"cy":0,"r":5});
+
+                    if (d._def.inputs > 0) {
+                        text.attr("x",38);
+                        node.append("rect").attr("class","port port_input").attr("rx",3).attr("ry",3).attr("x",-5).attr("width",10).attr("height",10)
+                            .on("mousedown",function(d){portMouseDown(d,1,0);})
+                            .on("touchstart",function(d){portMouseDown(d,1,0);})
+                            .on("mouseup",function(d){portMouseUp(d,1,0);} )
+                            .on("touchend",function(d){portMouseUp(d,1,0);} )
+                            .on("mouseover",function(d) { var port = d3.select(this); port.classed("port_hovered",(mouse_mode!=RED.state.JOINING || mousedown_port_type != 1 ));})
+                            .on("mouseout",function(d) { var port = d3.select(this); port.classed("port_hovered",false);})
+                    }
+
+                    //node.append("path").attr("class","node_error").attr("d","M 3,-3 l 10,0 l -5,-8 z");
+                    node.append("image").attr("class","node_error hidden").attr("xlink:href","icons/node-error.png").attr("x",0).attr("y",-6).attr("width",10).attr("height",9);
+                    node.append("image").attr("class","node_changed hidden").attr("xlink:href","icons/node-changed.png").attr("x",12).attr("y",-6).attr("width",10).attr("height",10);
+            });
+
+            node.each(function(d,i) {
+                    if (d.dirty) {
+                        //if (d.x < -50) deleteSelection();  // Delete nodes if dragged back to palette
+                        if (d.resize) {
+                            var l = d._def.label;
+                            l = (typeof l === "function" ? l.call(d) : l)||"";
+                            d.w = Math.max(node_width,calculateTextWidth(l)+(d._def.inputs>0?7:0) );
+                            d.h = Math.max(node_height,(d.outputs||0) * 15);
+                        }
+                        var thisNode = d3.select(this);
+                        //thisNode.selectAll(".centerDot").attr({"cx":function(d) { return d.w/2;},"cy":function(d){return d.h/2}});
+                        thisNode.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; });
+                        thisNode.selectAll(".node")
+                            .attr("width",function(d){return d.w})
+                            .attr("height",function(d){return d.h})
+                            .classed("node_selected",function(d) { return d.selected; })
+                            .classed("node_highlighted",function(d) { return d.highlighted; })
+                        ;
+                        //thisNode.selectAll(".node-gradient-top").attr("width",function(d){return d.w});
+                        //thisNode.selectAll(".node-gradient-bottom").attr("width",function(d){return d.w}).attr("y",function(d){return d.h-30});
+
+                        thisNode.selectAll(".node_icon_group_right").attr('transform', function(d){return "translate("+(d.w-30)+",0)"});
+                        thisNode.selectAll(".node_label_right").attr('x', function(d){return d.w-38});
+                        //thisNode.selectAll(".node_icon_right").attr("x",function(d){return d.w-d3.select(this).attr("width")-1-(d.outputs>0?5:0);});
+                        //thisNode.selectAll(".node_icon_shade_right").attr("x",function(d){return d.w-30;});
+                        //thisNode.selectAll(".node_icon_shade_border_right").attr("d",function(d){return "M "+(d.w-30)+" 1 l 0 "+(d.h-2)});
+
+                        
+                        var numOutputs = d.outputs;
+                        var y = (d.h/2)-((numOutputs-1)/2)*13;
+                        d.ports = d.ports || d3.range(numOutputs);
+                        d._ports = thisNode.selectAll(".port_output").data(d.ports);
+                        d._ports.enter().append("rect").attr("class","port port_output").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
+                            .on("mousedown",(function(){var node = d; return function(d,i){portMouseDown(node,0,i);}})() )
+                            .on("touchstart",(function(){var node = d; return function(d,i){portMouseDown(node,0,i);}})() )
+                            .on("mouseup",(function(){var node = d; return function(d,i){portMouseUp(node,0,i);}})() )
+                            .on("touchend",(function(){var node = d; return function(d,i){portMouseUp(node,0,i);}})() )
+                            .on("mouseover",function(d,i) { var port = d3.select(this); port.classed("port_hovered",(mouse_mode!=RED.state.JOINING || mousedown_port_type !== 0 ));})
+                            .on("mouseout",function(d,i) { var port = d3.select(this); port.classed("port_hovered",false);});
+                        d._ports.exit().remove();
+                        if (d._ports) {
+                            numOutputs = d.outputs || 1;
+                            y = (d.h/2)-((numOutputs-1)/2)*13;
+                            var x = d.w - 5;
+                            d._ports.each(function(d,i) {
+                                    var port = d3.select(this);
+                                    port.attr("y",(y+13*i)-5).attr("x",x);
+                            });
+                        }
+                        thisNode.selectAll('text.node_label').text(function(d,i){
+                                if (d._def.label) {
+                                    if (typeof d._def.label == "function") {
+                                        return d._def.label.call(d);
+                                    } else {
+                                        return d._def.label;
+                                    }
+                                }
+                                return "";
+                        })
+                            .attr('y', function(d){return (d.h/2)-1;})
+                            .attr('class',function(d){
+                                return 'node_label'+
+                                (d._def.align?' node_label_'+d._def.align:'')+
+                                (d._def.labelStyle?' '+(typeof d._def.labelStyle == "function" ? d._def.labelStyle.call(d):d._def.labelStyle):'') ;
+                        });
+                        thisNode.selectAll(".node_tools").attr("x",function(d){return d.w-35;}).attr("y",function(d){return d.h-20;});
+
+                        thisNode.selectAll(".node_changed")
+                            .attr("x",function(d){return d.w-10})
+                            .classed("hidden",function(d) { return !d.changed; });
+
+                        thisNode.selectAll(".node_error")
+                            .attr("x",function(d){return d.w-10-(d.changed?13:0)})
+                            .classed("hidden",function(d) { return d.valid; });
+
+                        thisNode.selectAll(".port_input").each(function(d,i) {
+                                var port = d3.select(this);
+                                port.attr("y",function(d){return (d.h/2)-5;})
+                        });
+
+                        thisNode.selectAll(".node_icon").attr("y",function(d){return (d.h-d3.select(this).attr("height"))/2;});
+                        thisNode.selectAll(".node_icon_shade").attr("height",function(d){return d.h;});
+                        thisNode.selectAll(".node_icon_shade_border").attr("d",function(d){ return "M "+(("right" == d._def.align) ?0:30)+" 1 l 0 "+(d.h-2)});
+
+                        
+                        thisNode.selectAll('.node_right_button').attr("transform",function(d){
+                                var x = d.w-6;
+                                if (d._def.button.toggle && !d[d._def.button.toggle]) {
+                                    x = x - 8;
+                                }
+                                return "translate("+x+",2)";
+                        });
+                        thisNode.selectAll('.node_right_button rect').attr("fill-opacity",function(d){
+                                if (d._def.button.toggle) {
+                                    return d[d._def.button.toggle]?1:0.2;
+                                }
+                                return 1;
+                        });
+
+                        //thisNode.selectAll('.node_right_button').attr("transform",function(d){return "translate("+(d.w - d._def.button.width.call(d))+","+0+")";}).attr("fill",function(d) {
+                        //         return typeof d._def.button.color  === "function" ? d._def.button.color.call(d):(d._def.button.color != null ? d._def.button.color : d._def.color)
+                        //});
+
+                        thisNode.selectAll('.node_badge_group').attr("transform",function(d){return "translate("+(d.w-40)+","+(d.h+3)+")";});
+                        thisNode.selectAll('text.node_badge_label').text(function(d,i) {
+                            if (d._def.badge) {
+                                if (typeof d._def.badge == "function") {
+                                    return d._def.badge.call(d);
+                                } else {
+                                    return d._def.badge;
+                                }
+                            }
+                            return "";
+                        });
+                        if (!showStatus || !d.status) {
+                            thisNode.selectAll('.node_status_group').style("display","none");
+                        } else {
+                            thisNode.selectAll('.node_status_group').style("display","inline").attr("transform","translate(3,"+(d.h+3)+")");
+                            var fill = status_colours[d.status.fill]; // Only allow our colours for now
+                            if (d.status.shape == null && fill == null) {
+                                thisNode.selectAll('.node_status').style("display","none");
+                            } else {
+                                var style;
+                                if (d.status.shape == null || d.status.shape == "dot") {
+                                    style = {
+                                        display: "inline",
+                                        fill: fill,
+                                        stroke: fill
+                                    };
+                                } else if (d.status.shape == "ring" ){
+                                    style = {
+                                        display: "inline",
+                                        fill: '#fff',
+                                        stroke: fill
+                                    }
+                                }
+                                thisNode.selectAll('.node_status').style(style);
+                            }
+                            if (d.status.text) {
+                                thisNode.selectAll('.node_status_label').text(d.status.text);
+                            } else {
+                                thisNode.selectAll('.node_status_label').text("");
+                            }
+                        }
+                               //console.dir("d value");
+                               //console.dir(d);
+                            if (showNumbers && d.dgnumber != null && d.dgnumber != undefined  && d.dgnumber.length >0) {
+                                       thisNode.selectAll('.node_dgnumber_group').style("display","inline").attr("transform","translate(9,"+(d.h+9)+")");
+                                       thisNode.selectAll('.node_dgnumber_label').text(d.dgnumber.toString());
+                                       var dgnumberList = d.dgnumber;
+                                       var dgnum = "";
+                                       if(dgnumberList != null && dgnumberList.length >=1){
+                                               dgnum = dgnumberList[0];
+                                               thisNode.select('.node_dgnumber_label').text(dgnum);
+                                               //console.log(dgnumberList);
+                                               thisNode.select('.node_dgnumber_title').text(dgnumberList);
+                                       }
+                               /*
+                               if(d.dgnumber.length > 1){
+                                       thisNode.selectAll('.node_dgnumber_group').style("display","inline").attr("transform","translate(9,"+(d.h-15)+")");
+                                       thisNode.selectAll('.node_dgnumber_label').text(d.dgnumber.toString());
+                               }else{
+                                       thisNode.selectAll('.node_dgnumber_group').style("display","inline").attr("transform","translate(9,"+(d.h+9)+")");
+                                       thisNode.selectAll('.node_dgnumber_label').text(d.dgnumber.toString());
+                               }
+                               */
+                            } else {
+                               //console.log("fhfjhfjh ");
+                                thisNode.select('.node_dgnumber').style("display","none");
+                                thisNode.select('.node_dgnumber_label').text("");
+                                thisNode.select('.node_dgnumber_title').text("");
+                            }
+
+                        d.dirty = false;
+                    }
+            });
+        }
+
+        var link = vis.selectAll(".link").data(RED.nodes.links.filter(function(d) { return d.source.z == activeWorkspace && d.target.z == activeWorkspace }),function(d) { return d.source.id+":"+d.sourcePort+":"+d.target.id;});
+
+        var linkEnter = link.enter().insert("g",".node").attr("class","link");
+        
+        linkEnter.each(function(d,i) {
+            var l = d3.select(this);
+            l.append("svg:path").attr("class","link_background link_path")
+               .on("mousedown",function(d) {
+                    mousedown_link = d;
+                    clearSelection();
+                    selected_link = mousedown_link;
+                    updateSelection();
+                    redraw();
+                    d3.event.stopPropagation();
+                })
+                .on("touchstart",function(d) {
+                    mousedown_link = d;
+                    clearSelection();
+                    selected_link = mousedown_link;
+                    updateSelection();
+                    redraw();
+                    d3.event.stopPropagation();
+                });
+            l.append("svg:path").attr("class","link_outline link_path");
+            l.append("svg:path").attr("class","link_line link_path");
+        });
+
+        link.exit().remove();
+
+        var links = vis.selectAll(".link_path")
+        links.attr("d",function(d){
+                var numOutputs = d.source.outputs || 1;
+                var sourcePort = d.sourcePort || 0;
+                var y = -((numOutputs-1)/2)*13 +13*sourcePort;
+
+                var dy = d.target.y-(d.source.y+y);
+                var dx = (d.target.x-d.target.w/2)-(d.source.x+d.source.w/2);
+                var delta = Math.sqrt(dy*dy+dx*dx);
+                var scale = lineCurveScale;
+                var scaleY = 0;
+                if (delta < node_width) {
+                    scale = 0.75-0.75*((node_width-delta)/node_width);
+                }
+
+                if (dx < 0) {
+                    scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
+                    if (Math.abs(dy) < 3*node_height) {
+                        scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
+                    }
+                }
+
+                d.x1 = d.source.x+d.source.w/2;
+                d.y1 = d.source.y+y;
+                d.x2 = d.target.x-d.target.w/2;
+                d.y2 = d.target.y;
+
+                return "M "+(d.source.x+d.source.w/2)+" "+(d.source.y+y)+
+                    " C "+(d.source.x+d.source.w/2+scale*node_width)+" "+(d.source.y+y+scaleY*node_height)+" "+
+                    (d.target.x-d.target.w/2-scale*node_width)+" "+(d.target.y-scaleY*node_height)+" "+
+                    (d.target.x-d.target.w/2)+" "+d.target.y;
+        })
+
+        link.classed("link_selected", function(d) { return d === selected_link || d.selected; });
+        link.classed("link_unknown",function(d) { return d.target.type == "unknown" || d.source.type == "unknown"});
+
+        if (d3.event) {
+            d3.event.preventDefault();
+        }
+    }
+
+    RED.keyboard.add(/* z */ 90,{ctrl:true},function(){RED.history.pop();});
+    RED.keyboard.add(/* a */ 65,{ctrl:true},function(){selectAll();d3.event.preventDefault();});
+    RED.keyboard.add(/* = */ 187,{ctrl:true},function(){zoomIn();d3.event.preventDefault();});
+    RED.keyboard.add(/* - */ 189,{ctrl:true},function(){zoomOut();d3.event.preventDefault();});
+    RED.keyboard.add(/* 0 */ 48,{ctrl:true},function(){zoomZero();d3.event.preventDefault();});
+    RED.keyboard.add(/* v */ 86,{ctrl:true},function(){importNodes(clipboard);d3.event.preventDefault();});
+    RED.keyboard.add(/* e */ 69,{ctrl:true},function(){showExportNodesDialog();d3.event.preventDefault();});
+    RED.keyboard.add(/* i */ 73,{ctrl:true},function(){showImportNodesDialog();d3.event.preventDefault();});
+    RED.keyboard.add(/* B */ 66,{ctrl:true},function(){RED.view.showDgNumberDialog();d3.event.preventDefault();});
+    RED.keyboard.add(/* [ */ 219,{ctrl:true},function(){RED.view.showSearchTextDialog();d3.event.preventDefault();});
+    RED.keyboard.add(/* O */ 79,{ctrl:true},function(){RED.view.showRequestTemplateDialog();d3.event.preventDefault();});
+
+
+    // TODO: 'dirty' should be a property of RED.nodes - with an event callback for ui hooks
+    function setDirty(d) {
+        dirty = d;
+        if (dirty) {
+            $("#btn-deploy").removeClass("disabled");
+        } else {
+            $("#btn-deploy").addClass("disabled");
+        }
+    }
+
+    /**
+     * Imports a new collection of nodes from a JSON String.
+     *  - all get new IDs assigned
+     *  - all 'selected'
+     *  - attached to mouse for placing - 'IMPORT_DRAGGING'
+     */
+    function importNodes(newNodesStr,touchImport) {
+        try {
+            var result = RED.nodes.import(newNodesStr,true);
+            if (result) {
+                var new_nodes = result[0];
+                var new_links = result[1];
+                var new_workspaces = result[2];
+                
+                var new_ms = new_nodes.filter(function(n) { return n.z == activeWorkspace }).map(function(n) { return {n:n};});
+                var new_node_ids = new_nodes.map(function(n){ return n.id; });
+                
+                // TODO: pick a more sensible root node
+                if (new_ms.length > 0) {
+                    var root_node = new_ms[0].n;
+                    var dx = root_node.x;
+                    var dy = root_node.y;
+    
+                    if (mouse_position == null) {
+                        mouse_position = [0,0];
+                    }
+    
+                    var minX = 0;
+                    var minY = 0;
+                    var i;
+                    var node;
+                    
+                    for (i=0;i<new_ms.length;i++) {
+                        node = new_ms[i];
+                        node.n.selected = true;
+                        node.n.changed = true;
+                        node.n.x -= dx - mouse_position[0];
+                        node.n.y -= dy - mouse_position[1];
+                        node.dx = node.n.x - mouse_position[0];
+                        node.dy = node.n.y - mouse_position[1];
+                        minX = Math.min(node.n.x-node_width/2-5,minX);
+                        minY = Math.min(node.n.y-node_height/2-5,minY);
+                    }
+                    for (i=0;i<new_ms.length;i++) {
+                        node = new_ms[i];
+                        node.n.x -= minX;
+                        node.n.y -= minY;
+                        node.dx -= minX;
+                        node.dy -= minY;
+                    }
+                    if (!touchImport) {
+                        mouse_mode = RED.state.IMPORT_DRAGGING;
+                    }
+    
+                    RED.keyboard.add(/* ESCAPE */ 27,function(){
+                            RED.keyboard.remove(/* ESCAPE */ 27);
+                            clearSelection();
+                            RED.history.pop();
+                            mouse_mode = 0;
+                    });
+                    clearSelection();
+                    moving_set = new_ms;
+                }
+
+                RED.history.push({t:'add',nodes:new_node_ids,links:new_links,workspaces:new_workspaces,dirty:RED.view.dirty()});
+
+
+                redraw();
+            }
+        } catch(error) {
+            console.log(error.stack);
+            RED.notify("<strong>Error</strong>: "+error,"error");
+        }
+    }
+
+    function showExportNodesDialog() {
+        mouse_mode = RED.state.EXPORT;
+        var nns = RED.nodes.createExportableNodeSet(moving_set);
+        $("#dialog-form").html($("script[data-template-name='export-clipboard-dialog']").html());
+        $("#node-input-export").val(JSON.stringify(nns));
+        $("#node-input-export").focus(function() {
+                var textarea = $(this);
+                textarea.select();
+                textarea.mouseup(function() {
+                        textarea.unbind("mouseup");
+                        return false;
+                });
+        });
+        $( "#dialog" ).dialog("option","title","Export nodes to clipboard").dialog( "open" );
+        $("#node-input-export").focus();
+    }
+
+    function showExportNodesLibraryDialog() {
+        mouse_mode = RED.state.EXPORT;
+        var nns = RED.nodes.createExportableNodeSet(moving_set);
+        $("#dialog-form").html($("script[data-template-name='export-library-dialog']").html());
+        $("#node-input-filename").attr('nodes',JSON.stringify(nns));
+        $( "#dialog" ).dialog("option","title","Export nodes to library").dialog( "open" );
+    }
+
+    function showImportNodesDialog() {
+        mouse_mode = RED.state.IMPORT;
+        $("#dialog-form").html($("script[data-template-name='import-dialog']").html());
+        $("#node-input-import").val("");
+        $( "#dialog" ).dialog("option","title","Import nodes").dialog( "open" );
+    }
+
+    function showRenameWorkspaceDialog(id) {
+        var ws = RED.nodes.workspace(id);
+        $( "#node-dialog-rename-workspace" ).dialog("option","workspace",ws);
+
+        if (workspace_tabs.count() == 1) {
+            $( "#node-dialog-rename-workspace").next().find(".leftButton")
+                .prop('disabled',true)
+                .addClass("ui-state-disabled");
+        } else {
+            $( "#node-dialog-rename-workspace").next().find(".leftButton")
+                .prop('disabled',false)
+                .removeClass("ui-state-disabled");
+        }
+
+        $( "#node-input-workspace-name" ).val(ws.label);
+        $( "#node-dialog-rename-workspace" ).dialog("open");
+    }
+
+    $("#node-dialog-rename-workspace form" ).submit(function(e) { e.preventDefault();});
+    $( "#node-dialog-rename-workspace" ).dialog({
+        modal: true,
+        autoOpen: false,
+        width: 500,
+        title: "Rename sheet",
+        buttons: [
+            {
+                class: 'leftButton',
+                text: "Delete",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    $( this ).dialog( "close" );
+                    deleteWorkspace(workspace.id);
+                }
+            },
+            {
+                text: "Ok",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    var label = $( "#node-input-workspace-name" ).val();
+                    if (workspace.label != label) {
+                        workspace.label = label;
+                        var link = $("#workspace-tabs a[href='#"+workspace.id+"']");
+                        link.attr("title",label);
+                        link.text(label);
+                        RED.view.dirty(true);
+                    }
+                    $( this ).dialog( "close" );
+                }
+            },
+            {
+                text: "Cancel",
+                click: function() {
+                    $( this ).dialog( "close" );
+                }
+            }
+        ],
+        open: function(e) {
+            RED.keyboard.disable();
+        },
+        close: function(e) {
+            RED.keyboard.enable();
+        }
+    });
+    $( "#node-dialog-delete-workspace" ).dialog({
+        modal: true,
+        autoOpen: false,
+        width: 500,
+        title: "Confirm delete",
+        buttons: [
+            {
+                text: "Ok",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    RED.view.removeWorkspace(workspace);
+                    var historyEvent = RED.nodes.removeWorkspace(workspace.id);
+                    historyEvent.t = 'delete';
+                    historyEvent.dirty = dirty;
+                    historyEvent.workspaces = [workspace];
+                    RED.history.push(historyEvent);
+                    RED.view.dirty(true);
+                    $( this ).dialog( "close" );
+                }
+            },
+            {
+                text: "Cancel",
+                click: function() {
+                    $( this ).dialog( "close" );
+                }
+            }
+        ],
+        open: function(e) {
+            RED.keyboard.disable();
+        },
+        close: function(e) {
+            RED.keyboard.enable();
+        }
+
+    });
+    return {
+        state:function(state) {
+            if (state == null) {
+                return mouse_mode
+            } else {
+                mouse_mode = state;
+            }
+        },
+        addWorkspace: function(ws) {
+            workspace_tabs.addTab(ws);
+            workspace_tabs.resize();
+        },
+        removeWorkspace: function(ws) {
+            workspace_tabs.removeTab(ws.id);
+        },
+        getWorkspace: function() {
+            return activeWorkspace;
+        },
+        showWorkspace: function(id) {
+            workspace_tabs.activateTab(id);
+        },
+        redraw:redraw,
+        dirty: function(d) {
+            if (d == null) {
+                return dirty;
+            } else {
+                setDirty(d);
+            }
+        },
+        importNodes: importNodes,
+        resize: function() {
+            workspace_tabs.resize();
+        },
+        status: function(s) {
+               validateEachNodeXml();
+            showStatus = s;
+            RED.nodes.eachNode(function(n) { n.dirty = true;});
+            //TODO: subscribe/unsubscribe here
+            redraw();
+        },
+       showYangUploadDialog:function showYangUploadDialog(){
+               $(function() {
+                       var htmlStr= "<div id='yang-upload-div' style='width:375;height:225'>" +
+                       '<form id="uploadForm" name="uploadForm" enctype="multipart/form-data" action="/api/uploadyang" method="post" >' + 
+                       "<input id='yang-file-id' name='yangFile' type='file' accept='.yang,.zip'><p style='font-size:0.7em'><i>For Module depending on multiple yang files, zip them and upload the zip file. The zip file name should match the exact name of the module with .zip extension</i</p><br><br><br><br><br><p id='yang-upload-status'></p>" +
+                       //'<input id="upload-yang-button-id"  style="font-size:1em;font-weight:bold" type="button" value="Upload Yang" name="upload-yang-button">' +
+                       "</form></div>";
+
+                       $("#yang-upload-dialog").dialog({
+                               modal:true,     
+                               autoOpen :false,
+                               title: "Upload Yang",
+                               width: 500,
+                               height: 260,
+                               minWidth : 300, 
+                               minHeight :260, 
+                               buttons :[
+                                       {
+                                               text: "Upload Yang",
+                                               click: function() {
+                                                       if( document.getElementById("yang-file-id").files.length == 0 ){
+                                                               $("#yang-upload-status").html("<span>No files selected.</span>");
+                                                               return ;
+                                                       }       
+                                                       $('#yang-upload-dialog').parent().find('.ui-dialog-buttonpane button:first').button("disable");
+                                                       //$("#yang-upload-status").empty().text("File is uploading...");
+                                                       $("#yang-upload-status").html("<span>Processing...Please wait</span><img src='images/page-loading.gif'>");
+                                                       $.ajax({
+                                                               url: "/api/uploadyang", 
+                                                               type: "POST",             
+                                                               data: new FormData(document.forms['uploadForm']),
+                                                               contentType: false,       
+                                                               cache: false,             
+                                                               processData:false, 
+                                                               success: function(data) {
+                                                                       $("#yang-upload-status").html("");
+                                                                       $("#yang-upload-status").text(data.msg);
+                                                                       $('#yang-upload-dialog').parent().find('.ui-dialog-buttonpane button:first').button("enable");
+                                                               /*
+                                                                       sliValuesObj = {};
+                                                                       rpcValues = {};
+                                                                       reqInputValues = {};
+                                                                       for(var i=0;i<data.sliValuesObj.length;i++){
+                                                                               var moduleName = data.sliValuesObj[i].moduleName;
+                                                                               sliValuesObj[moduleName] = data.sliValuesObj[i][moduleName + '_PROPS'];
+                                                                               rpcValues[moduleName] = data.sliValuesObj[i][ moduleName +'_RPCS'];
+                                                                               for(var k=0;rpcValues[moduleName] != undefined && k<rpcValues[moduleName].length;k++){
+                                                                                       var rpcName = rpcValues[moduleName][k];
+                                                                                       reqInputValues[moduleName + "_" + rpcName] = data.sliValuesObj[i][rpcName +"-input"];
+                                                                               }
+                                                                       }
+                                                                */
+                                                                       //close the yang upload dialogog box and open the load dialogbox
+                                                                       $('#yang-upload-dialog').dialog("close");
+                                                                       $("#btn-available-yang-modules").trigger("click");
+                                                               },
+                                                               error:function (xhr, desc, err){
+                                                                       $("#yang-upload-status").html(err);
+                                                                       $('#yang-upload-dialog').parent().find('.ui-dialog-buttonpane button:first').button("enable");
+                                                               }
+                                                       });
+                                               }
+                                       },
+                                       {
+                                               text: "Close",
+                                               click: function() {
+                                                       $("#yang-upload-dialog").dialog("close");
+                                               }
+                                       }
+                                       ]
+                       }).dialog("open").html(htmlStr);
+               });
+       },
+        showDgNumberDialog: function showDgNumberDialog(){
+       $(function() {
+               var isLoopDetected = detectLoop();
+               console.log("isLoopDetected:" + isLoopDetected);
+               if(isLoopDetected){
+                       return false;
+               }
+               updateDgNumbers();
+       var htmlStr="<div id='find-dgnumber-div' style='width:375;height:225'><label>DG Number</label><input id='dgnumber-val-id' type='text' value=''><p id='find-dgnumber-status' style='color:red'></p></div>";
+       $("#dgnumber-find-dialog").dialog({
+               modal:true,     
+               autoOpen :false,
+               title: "Find Node By DGNumber",
+               width: 300,
+               height: 215,
+                minWidth : 300, 
+                minHeight :215, 
+               buttons :[
+                       {
+                       text: "Find",
+                       click: function() {
+                               var dgnumVal = $("#dgnumber-val-id").val();
+                               $("#find-dgnumber-status").text("");
+                               if(dgnumVal != undefined &&  dgnumVal != '' && dgnumVal != ''){
+                                       dgnumVal = dgnumVal.trim();
+                               }else{
+                                       dgnumVal ="";
+                               }
+                                       
+                               var dgNumberFound = false;
+                               var node = vis.selectAll(".nodegroup").data(RED.nodes.nodes.filter(function(d) { return d.z == activeWorkspace }),function(d){return d.id});
+                               node.each(function(d,i) {
+                                       var thisNode = d3.select(this);
+                                       var dgn = d.dgnumber;
+                                       
+                                       if(dgn != undefined && typeof dgn == 'object'){
+                                               var found = false;
+                                               for(var k=0;k<dgn.length;k++){
+                                                       if(dgn[k] == dgnumVal){
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if(found){
+                                                       //thisNode.select("rect").style({"stroke":"blue","stroke-width" :"3","stroke-dasharray":"5,1"});
+                                                       //$("#" + d.id).find("rect").attr("class","node-found-selected");
+                                                       //$("#" + d.id).find("rect").attr("class","node node_selected");
+                                                       //thisNode.select("rect").attr("class","node node_selected");
+                                                       thisNode.select("rect").attr("class","node node_found");
+                                                       document.getElementById( d.id ).scrollIntoView();       
+                                                       $("#dgnumber-find-dialog").dialog("close");
+
+                                                       //display the node edit dialogbox
+                                                       RED.editor.edit(d);
+                                                       dgNumberFound = true;
+                                               }else{
+                                                       //thisNode.select("rect").style({"stroke":"#999","stroke-width" :"2","stroke-dasharray":"none"});
+                                                       //$("#" + d.id ).find("rect").attr("class","node-found-clear");
+                                                       thisNode.select("rect").attr("class","node");
+                                                       //$("#" + d.id ).find("rect").attr("class","node");
+                                                       //$("#find-dgnumber-status").text("DGNumber :" + dgnumVal + " Not found");
+                                                       
+                                               }
+                                       }
+                               });
+                               if(!dgNumberFound){
+                                       $("#find-dgnumber-status").text("DGNumber :" + dgnumVal + " Not found");
+                               }
+                       }
+                       },
+                       {
+                       text: "Close",
+                       click: function() {
+                               $("#dgnumber-find-dialog").dialog("close");
+                       }
+                       }
+               ],
+               open:function(){
+                       //Bind the Enter key to Find button
+                       $('#dgnumber-find-dialog').keypress(function(e) {
+                               if (e.keyCode == $.ui.keyCode.ENTER) {
+                                       $('#dgnumber-find-dialog').parent().find('.ui-dialog-buttonpane button:first').click();
+                                               return false;
+                                        }
+                        });
+                       $(function(){
+                               //set focus on the input box
+                               $("#dgnumber-val-id").focus();
+                       });
+               }
+               }).dialog("open").html(htmlStr);
+       });
+       },      
+        showSearchTextDialog: function showSearchTextDialog(){
+       $(function() {
+               var isLoopDetected = detectLoop();
+               console.log("isLoopDetected:" + isLoopDetected);
+               if(isLoopDetected){
+                       return false;
+               }
+               updateDgNumbers();
+       //console.log("In the showSearchTextDialog.");  
+       var htmlStr="<div id='search-text-div' style='width:675;height:525'><label>Search Text</label><input style='width:500px;' id='search-text-val-id' type='text' value=''><br><input id='ignore-case-id' type='checkbox' name='ignorecase' value='1' >Ignore Case<br><p id='search-text-status' style='color:red'></p></div>";
+       //console.log("setting up search-text-dialog.");        
+       $("#search-text-dialog").dialog({
+               modal:true,     
+               autoOpen :false,
+               title: "Search text in DG",
+               width: 600,
+               height: 515,
+                minWidth : 500, 
+                minHeight :415, 
+               buttons :[
+                       {
+                       text: "Search",
+                       click: function() {
+       
+                               var node = vis.selectAll(".nodegroup").data(RED.nodes.nodes.filter(function(d) { return d.z == activeWorkspace }),function(d){return d.id});
+                               var searchText = $("#search-text-val-id").val();
+                               $("#search-text-status").text("");
+                               if(searchText != undefined &&  searchText != '' && searchText != ''){
+                                       searchText = searchText.trim();
+                               }else{
+                                       searchText ="";
+                                       node.each(function(d,i) {
+                                               var thisNode = d3.select(this);
+                                               thisNode.select("rect").attr("class","node");
+                                       });
+                                       return;
+                               }
+                                       
+                               var foundSearchText = false;
+                               var foundInDgNumArr = [];
+                               //console.log("In search function");
+                               node.each(function(d,i) {
+                                       var thisNode = d3.select(this);
+                                       var dgn = d.dgnumber;
+                                       var xml = d.xml;
+                                       var nName = d.name;
+                       
+                                       var ignoreCase = $('#ignore-case-id').prop('checked') 
+                                       var options = 'g';
+                                       if(ignoreCase){
+                                               options='gi';
+                                       }
+                                       var searchPattern = new RegExp(searchText, options );
+                                       if(xml == undefined || xml == null){
+                                               xml = "";
+                                       }
+                                       if(nName == undefined || nName == null){
+                                               nName = "";
+                                       }
+                                       //console.log(searchPattern);
+                                       var count1 = (xml.match(searchPattern) || []).length;
+                                       //console.log(count1);  
+                                       var count2 = (nName.match(searchPattern) || []).length;
+                                       //console.log(count2);  
+                                               
+                                       if(count1 >0 || count2 > 0){
+                                               thisNode.select("rect").attr("class","node text_found");
+                                               var dgn = d.dgnumber;
+                                       
+                                               var dgNumber =  dgn;
+                                               if(dgn != undefined && typeof dgn == 'object'){
+                                                       console.log("DGNUMBERS:"  + dgn);
+                                                       dgNumber =  dgn[0];
+                                               }
+                                               if(dgn != undefined ){
+                                                       foundInDgNumArr.push(dgNumber);
+                                               }else{
+                                                       foundInDgNumArr.push(d.type);
+                                               }
+                                               foundSearchText=true;
+                                       }else{
+                                               thisNode.select("rect").attr("class","node");
+                                       }
+                               });
+                               if(!foundSearchText){
+                                       $("#search-text-status").text("Search Text :" + searchText  + " Not found");
+                               }else{
+                                       //console.log("closing dialog");
+                                       //$("#search-text-dialog").dialog("close");
+                                       console.log(foundInDgNumArr);
+                                       $("#search-text-status").text("Found in DG numbers :" + foundInDgNumArr);
+                               }
+                       }
+                       },
+                       {
+                       text: "Close",
+                       click: function() {
+                               //console.log("closing dialog");
+                               $("#search-text-dialog").dialog("close");
+                       }
+                       }
+               ],
+               open:function(){
+                       //console.log("called open.");
+                       //Bind the Enter key to Find button
+                       $('#search-text-dialog').keypress(function(e) {
+                               if (e.keyCode == $.ui.keyCode.ENTER) {
+                                       $('#search-text-dialog').parent().find('.ui-dialog-buttonpane button:first').click();
+                                               return false;
+                                        }
+                        });
+                       $(function(){
+                               //set focus on the input box
+                               $("#search-text-id").focus();
+                       });
+                       //console.log("done open call.");
+               }
+               }).dialog('open').html(htmlStr);
+       });
+       },      
+        showRequestTemplateDialog: function showRequestTemplateDialog(){
+       $(function() {
+               var currNodes =  RED.nodes.nodes.filter(function(d) { return d.z == activeWorkspace })
+               var moduleName = "";
+               var rpcName = "";
+               if(currNodes != null && currNodes.length > 1){
+                       currNodes.forEach(function(n){
+                               if(n.type == 'service-logic'){
+                                       moduleName = getAttributeValue(n.xml,"module");
+                               }else if(n.type == 'method'){
+                                       rpcName = getAttributeValue(n.xml,"rpc");
+                               }
+                       });
+               }
+               console.log("moduleName:" + moduleName);
+               console.log("rpcName:" + rpcName);
+               var inputValObj = reqInputValues[moduleName + "_" + rpcName];
+               var inputValStr = "Not found. Please make sure that the Module is loaded and the rpc has input.";
+               if(inputValObj != undefined && inputValObj != null){
+                       inputValStr = "{\n\"input\" : " + JSON.stringify(inputValObj,null,4)+ "\n}";
+               }       
+               
+               //var htmlStr="<div id='request-template-div' style='width:875px;height:575px'><textarea style='width:875px;height:575px'>" + inputValStr + "</textarea></div>"
+               //var htmlStr="<div id='request-template-div' style='width:750px;height:550px;font-weight:bold;font-size:1em'><pre>" + inputValStr + "</pre></div>"
+               var htmlStr="<textarea readonly='1' id='request-template-textarea' style='width:750px;height:550px;font-weight:bold;font-size:1em'>" + inputValStr + "</textarea>"
+               $("#request-input-dialog").dialog({
+                       dialogClass :"no-close",
+                       modal:true,     
+                       autoOpen :false,
+                       title: "Request Template for Module:" + moduleName + "    RPC:" + rpcName,
+                       width: 800,
+                       height: "auto",
+                       buttons :[
+                       {
+                               text: "Close",
+                               click: function() {
+                                       $("#request-input-dialog").dialog("close");
+                               }
+                       }
+                       ],
+                       open:function(){
+                                $('#request-input-dialog').css('overflow', 'hidden'); 
+                       }
+               }).dialog("open").html(htmlStr);
+       });
+       },
+        showNumbers: function(s) {
+               console.log("showNumbers:" + s);
+               showNumbers = s;
+            RED.nodes.eachNode(function(n) { n.dirty = true;});
+            redraw();
+        },
+        showNodePalette: function(s) {
+               showNodePalette=s;
+               if(!s){
+                       $("#main-container").addClass("palette-bar-closed");
+                       //RED.menu.setSelected("btn-node-panel",true);
+               }else{
+                       $("#main-container").removeClass("palette-bar-closed");
+               }
+               //console.log("showNodePalette:" + showNodePalette);
+        },
+        
+        //TODO: should these move to an import/export module?
+        showImportNodesDialog: showImportNodesDialog,
+        showExportNodesDialog: showExportNodesDialog,
+        showExportNodesLibraryDialog: showExportNodesLibraryDialog
+    };
+})();
diff --git a/dgbuilder/public/red/ui/view.js.orig b/dgbuilder/public/red/ui/view.js.orig
new file mode 100644 (file)
index 0000000..73981fd
--- /dev/null
@@ -0,0 +1,1639 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+
+RED.view = (function() {
+    var space_width = 5000,
+        space_height = 5000,
+        lineCurveScale = 0.75,
+        scaleFactor = 1,
+        node_width = 100,
+        node_height = 30;
+    
+    var touchLongPressTimeout = 1000,
+        startTouchDistance = 0,
+        startTouchCenter = [],
+        moveTouchCenter = [],
+        touchStartTime = 0;
+
+
+    var activeWorkspace = 0;
+    var workspaceScrollPositions = {};
+
+    var selected_link = null,
+        mousedown_link = null,
+        mousedown_node = null,
+        mousedown_port_type = null,
+        mousedown_port_index = 0,
+        mouseup_node = null,
+        mouse_offset = [0,0],
+        mouse_position = null,
+        mouse_mode = 0,
+        moving_set = [],
+        dirty = false,
+        lasso = null,
+        showStatus = false,
+        lastClickNode = null,
+        dblClickPrimed = null,
+        clickTime = 0,
+        clickElapsed = 0;
+
+    var clipboard = "";
+
+    var status_colours = {
+        "red":    "#c00",
+        "green":  "#5a8",
+        "yellow": "#F9DF31",
+        "blue":   "#53A3F3",
+        "grey":   "#d3d3d3"
+    }
+
+    var outer = d3.select("#chart")
+        .append("svg:svg")
+        .attr("width", space_width)
+        .attr("height", space_height)
+        .attr("pointer-events", "all")
+        .style("cursor","crosshair");
+
+     var vis = outer
+        .append('svg:g')
+        .on("dblclick.zoom", null)
+        .append('svg:g')
+        .on("mousemove", canvasMouseMove)
+        .on("mousedown", canvasMouseDown)
+        .on("mouseup", canvasMouseUp)
+        .on("touchend", function() {
+            clearTimeout(touchStartTime);
+            touchStartTime = null;
+            if  (RED.touch.radialMenu.active()) {
+                return;
+            }
+            if (lasso) {
+                outer_background.attr("fill","#fff");
+            }
+            canvasMouseUp.call(this);
+        })
+        .on("touchcancel", canvasMouseUp)
+        .on("touchstart", function() {
+            var touch0;
+            if (d3.event.touches.length>1) {
+                clearTimeout(touchStartTime);
+                touchStartTime = null;
+                d3.event.preventDefault();
+                touch0 = d3.event.touches.item(0);
+                var touch1 = d3.event.touches.item(1);
+                var a = touch0['pageY']-touch1['pageY'];
+                var b = touch0['pageX']-touch1['pageX'];
+
+                var offset = $("#chart").offset();
+                var scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
+                startTouchCenter = [
+                    (touch1['pageX']+(b/2)-offset.left+scrollPos[0])/scaleFactor,
+                    (touch1['pageY']+(a/2)-offset.top+scrollPos[1])/scaleFactor
+                ];
+                moveTouchCenter = [
+                    touch1['pageX']+(b/2),
+                    touch1['pageY']+(a/2)
+                ]
+                startTouchDistance = Math.sqrt((a*a)+(b*b));
+            } else {
+                var obj = d3.select(document.body);
+                touch0 = d3.event.touches.item(0);
+                var pos = [touch0.pageX,touch0.pageY];
+                startTouchCenter = [touch0.pageX,touch0.pageY];
+                startTouchDistance = 0;
+                var point = d3.touches(this)[0];
+                touchStartTime = setTimeout(function() {
+                    touchStartTime = null;
+                    showTouchMenu(obj,pos);
+                    //lasso = vis.append('rect')
+                    //    .attr("ox",point[0])
+                    //    .attr("oy",point[1])
+                    //    .attr("rx",2)
+                    //    .attr("ry",2)
+                    //    .attr("x",point[0])
+                    //    .attr("y",point[1])
+                    //    .attr("width",0)
+                    //    .attr("height",0)
+                    //    .attr("class","lasso");
+                    //outer_background.attr("fill","#e3e3f3");
+                },touchLongPressTimeout);
+            }
+        })
+        .on("touchmove", function(){
+                if  (RED.touch.radialMenu.active()) {
+                    d3.event.preventDefault();
+                    return;
+                }
+                var touch0;
+                if (d3.event.touches.length<2) {
+                    if (touchStartTime) {
+                        touch0 = d3.event.touches.item(0);
+                        var dx = (touch0.pageX-startTouchCenter[0]);
+                        var dy = (touch0.pageY-startTouchCenter[1]);
+                        var d = Math.abs(dx*dx+dy*dy);
+                        if (d > 64) {
+                            clearTimeout(touchStartTime);
+                            touchStartTime = null;
+                        }
+                    } else if (lasso) {
+                        d3.event.preventDefault();
+                    }
+                    canvasMouseMove.call(this);
+                } else {
+                    touch0 = d3.event.touches.item(0);
+                    var touch1 = d3.event.touches.item(1);
+                    var a = touch0['pageY']-touch1['pageY'];
+                    var b = touch0['pageX']-touch1['pageX'];
+                    var offset = $("#chart").offset();
+                    var scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
+                    var moveTouchDistance = Math.sqrt((a*a)+(b*b));
+                    var touchCenter = [
+                        touch1['pageX']+(b/2),
+                        touch1['pageY']+(a/2)
+                    ];
+
+                    if (!isNaN(moveTouchDistance)) {
+                        oldScaleFactor = scaleFactor;
+                        scaleFactor = Math.min(2,Math.max(0.3, scaleFactor + (Math.floor(((moveTouchDistance*100)-(startTouchDistance*100)))/10000)));
+
+                        var deltaTouchCenter = [                             // Try to pan whilst zooming - not 100%
+                            startTouchCenter[0]*(scaleFactor-oldScaleFactor),//-(touchCenter[0]-moveTouchCenter[0]),
+                            startTouchCenter[1]*(scaleFactor-oldScaleFactor) //-(touchCenter[1]-moveTouchCenter[1])
+                        ];
+
+                        startTouchDistance = moveTouchDistance;
+                        moveTouchCenter = touchCenter;
+
+                        $("#chart").scrollLeft(scrollPos[0]+deltaTouchCenter[0]);
+                        $("#chart").scrollTop(scrollPos[1]+deltaTouchCenter[1]);
+                        redraw();
+                    }
+                }
+        });
+
+    var outer_background = vis.append('svg:rect')
+        .attr('width', space_width)
+        .attr('height', space_height)
+        .attr('fill','#fff');
+
+    //var gridScale = d3.scale.linear().range([0,2000]).domain([0,2000]);
+    //var grid = vis.append('g');
+    //
+    //grid.selectAll("line.horizontal").data(gridScale.ticks(100)).enter()
+    //    .append("line")
+    //        .attr(
+    //        {
+    //            "class":"horizontal",
+    //            "x1" : 0,
+    //            "x2" : 2000,
+    //            "y1" : function(d){ return gridScale(d);},
+    //            "y2" : function(d){ return gridScale(d);},
+    //            "fill" : "none",
+    //            "shape-rendering" : "crispEdges",
+    //            "stroke" : "#eee",
+    //            "stroke-width" : "1px"
+    //        });
+    //grid.selectAll("line.vertical").data(gridScale.ticks(100)).enter()
+    //    .append("line")
+    //        .attr(
+    //        {
+    //            "class":"vertical",
+    //            "y1" : 0,
+    //            "y2" : 2000,
+    //            "x1" : function(d){ return gridScale(d);},
+    //            "x2" : function(d){ return gridScale(d);},
+    //            "fill" : "none",
+    //            "shape-rendering" : "crispEdges",
+    //            "stroke" : "#eee",
+    //            "stroke-width" : "1px"
+    //        });
+
+
+    var drag_line = vis.append("svg:path").attr("class", "drag_line");
+
+    var workspace_tabs = RED.tabs.create({
+        id: "workspace-tabs",
+        onchange: function(tab) {
+            if (tab.type == "subflow") {
+                $("#workspace-toolbar").show();
+            } else {
+                $("#workspace-toolbar").hide();
+            }
+            var chart = $("#chart");
+            if (activeWorkspace !== 0) {
+                workspaceScrollPositions[activeWorkspace] = {
+                    left:chart.scrollLeft(),
+                    top:chart.scrollTop()
+                };
+            }
+            var scrollStartLeft = chart.scrollLeft();
+            var scrollStartTop = chart.scrollTop();
+
+            activeWorkspace = tab.id;
+            if (workspaceScrollPositions[activeWorkspace]) {
+                chart.scrollLeft(workspaceScrollPositions[activeWorkspace].left);
+                chart.scrollTop(workspaceScrollPositions[activeWorkspace].top);
+            } else {
+                chart.scrollLeft(0);
+                chart.scrollTop(0);
+            }
+            var scrollDeltaLeft = chart.scrollLeft() - scrollStartLeft;
+            var scrollDeltaTop = chart.scrollTop() - scrollStartTop;
+            if (mouse_position != null) {
+                mouse_position[0] += scrollDeltaLeft;
+                mouse_position[1] += scrollDeltaTop;
+            }
+
+            clearSelection();
+            RED.nodes.eachNode(function(n) {
+                    n.dirty = true;
+            });
+            redraw();
+        },
+        ondblclick: function(tab) {
+            showRenameWorkspaceDialog(tab.id);
+        },
+        onadd: function(tab) {
+            RED.menu.addItem("btn-workspace-menu",{
+                id:"btn-workspace-menu-"+tab.id.replace(".","-"),
+                label:tab.label,
+                onselect:function() {
+                    workspace_tabs.activateTab(tab.id);
+                }
+            });
+            RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
+        },
+        onremove: function(tab) {
+            RED.menu.setDisabled("btn-workspace-delete",workspace_tabs.count() == 1);
+            RED.menu.removeItem("btn-workspace-menu-"+tab.id.replace(".","-"));
+        }
+    });
+
+    var workspaceIndex = 0;
+
+    function addWorkspace() {
+        var tabId = RED.nodes.id();
+        do {
+            workspaceIndex += 1;
+        } while($("#workspace-tabs a[title='Sheet "+workspaceIndex+"']").size() !== 0);
+
+        var ws = {type:"tab",id:tabId,label:"Sheet "+workspaceIndex};
+        RED.nodes.addWorkspace(ws);
+        workspace_tabs.addTab(ws);
+        workspace_tabs.activateTab(tabId);
+        RED.history.push({t:'add',workspaces:[ws],dirty:dirty});
+        RED.view.dirty(true);
+    }
+    $(function() {
+        $('#btn-workspace-add-tab').on("click",addWorkspace);
+        $('#btn-workspace-add').on("click",addWorkspace);
+        $('#btn-workspace-edit').on("click",function() {
+            showRenameWorkspaceDialog(activeWorkspace);
+        });
+        $('#btn-workspace-delete').on("click",function() {
+            deleteWorkspace(activeWorkspace);
+        });
+    });
+
+    function deleteWorkspace(id) {
+        if (workspace_tabs.count() == 1) {
+            return;
+        }
+        var ws = RED.nodes.workspace(id);
+        $( "#node-dialog-delete-workspace" ).dialog('option','workspace',ws);
+        $( "#node-dialog-delete-workspace-name" ).text(ws.label);
+        $( "#node-dialog-delete-workspace" ).dialog('open');
+    }
+
+    function canvasMouseDown() {
+        if (!mousedown_node && !mousedown_link) {
+            selected_link = null;
+            updateSelection();
+        }
+        if (mouse_mode === 0) {
+            if (lasso) {
+                lasso.remove();
+                lasso = null;
+            }
+            
+            if (!touchStartTime) {
+                var point = d3.mouse(this);
+                lasso = vis.append('rect')
+                    .attr("ox",point[0])
+                    .attr("oy",point[1])
+                    .attr("rx",2)
+                    .attr("ry",2)
+                    .attr("x",point[0])
+                    .attr("y",point[1])
+                    .attr("width",0)
+                    .attr("height",0)
+                    .attr("class","lasso");
+                d3.event.preventDefault();
+            }
+        }
+    }
+
+    function canvasMouseMove() {
+        mouse_position = d3.touches(this)[0]||d3.mouse(this);
+
+        // Prevent touch scrolling...
+        //if (d3.touches(this)[0]) {
+        //    d3.event.preventDefault();
+        //}
+
+        // TODO: auto scroll the container
+        //var point = d3.mouse(this);
+        //if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; }
+        //console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop);
+
+        if (lasso) {
+            var ox = parseInt(lasso.attr("ox"));
+            var oy = parseInt(lasso.attr("oy"));
+            var x = parseInt(lasso.attr("x"));
+            var y = parseInt(lasso.attr("y"));
+            var w;
+            var h;
+            if (mouse_position[0] < ox) {
+                x = mouse_position[0];
+                w = ox-x;
+            } else {
+                w = mouse_position[0]-x;
+            }
+            if (mouse_position[1] < oy) {
+                y = mouse_position[1];
+                h = oy-y;
+            } else {
+                h = mouse_position[1]-y;
+            }
+            lasso
+                .attr("x",x)
+                .attr("y",y)
+                .attr("width",w)
+                .attr("height",h)
+            ;
+            return;
+        }
+
+        if (mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && selected_link == null) {
+            return;
+        }
+
+        var mousePos;
+        if (mouse_mode == RED.state.JOINING) {
+            // update drag line
+            drag_line.attr("class", "drag_line");
+            mousePos = mouse_position;
+            var numOutputs = (mousedown_port_type === 0)?(mousedown_node.outputs || 1):1;
+            var sourcePort = mousedown_port_index;
+            var portY = -((numOutputs-1)/2)*13 +13*sourcePort;
+
+            var sc = (mousedown_port_type === 0)?1:-1;
+
+            var dy = mousePos[1]-(mousedown_node.y+portY);
+            var dx = mousePos[0]-(mousedown_node.x+sc*mousedown_node.w/2);
+            var delta = Math.sqrt(dy*dy+dx*dx);
+            var scale = lineCurveScale;
+            var scaleY = 0;
+
+            if (delta < node_width) {
+                scale = 0.75-0.75*((node_width-delta)/node_width);
+            }
+            if (dx*sc < 0) {
+                scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
+                if (Math.abs(dy) < 3*node_height) {
+                    scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
+                }
+            }
+
+            drag_line.attr("d",
+                "M "+(mousedown_node.x+sc*mousedown_node.w/2)+" "+(mousedown_node.y+portY)+
+                " C "+(mousedown_node.x+sc*(mousedown_node.w/2+node_width*scale))+" "+(mousedown_node.y+portY+scaleY*node_height)+" "+
+                (mousePos[0]-sc*(scale)*node_width)+" "+(mousePos[1]-scaleY*node_height)+" "+
+                mousePos[0]+" "+mousePos[1]
+                );
+            d3.event.preventDefault();
+        } else if (mouse_mode == RED.state.MOVING) {
+            mousePos = mouse_position;
+            var d = (mouse_offset[0]-mousePos[0])*(mouse_offset[0]-mousePos[0]) + (mouse_offset[1]-mousePos[1])*(mouse_offset[1]-mousePos[1]);
+            if (d > 2) {
+                mouse_mode = RED.state.MOVING_ACTIVE;
+                clickElapsed = 0;
+            }
+        } else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING) {
+            mousePos = mouse_position;
+            var node;
+            var i;
+            var minX = 0;
+            var minY = 0;
+            for (var n = 0; n<moving_set.length; n++) {
+                node = moving_set[n];
+                if (d3.event.shiftKey) {
+                    node.n.ox = node.n.x;
+                    node.n.oy = node.n.y;
+                }
+                node.n.x = mousePos[0]+node.dx;
+                node.n.y = mousePos[1]+node.dy;
+                node.n.dirty = true;
+                minX = Math.min(node.n.x-node.n.w/2-5,minX);
+                minY = Math.min(node.n.y-node.n.h/2-5,minY);
+            }
+            if (minX !== 0 || minY !== 0) {
+                for (i = 0; i<moving_set.length; i++) {
+                    node = moving_set[i];
+                    node.n.x -= minX;
+                    node.n.y -= minY;
+                }
+            }
+            if (d3.event.shiftKey && moving_set.length > 0) {
+                var gridOffset =  [0,0];
+                node = moving_set[0];
+                gridOffset[0] = node.n.x-(20*Math.floor((node.n.x-node.n.w/2)/20)+node.n.w/2);
+                gridOffset[1] = node.n.y-(20*Math.floor(node.n.y/20));
+                if (gridOffset[0] !== 0 || gridOffset[1] !== 0) {
+                    for (i = 0; i<moving_set.length; i++) {
+                        node = moving_set[i];
+                        node.n.x -= gridOffset[0];
+                        node.n.y -= gridOffset[1];
+                        if (node.n.x == node.n.ox && node.n.y == node.n.oy) {
+                            node.dirty = false;
+                        }
+                    }
+                }
+            }
+        }
+        redraw();
+    }
+
+    function canvasMouseUp() {
+        if (mousedown_node && mouse_mode == RED.state.JOINING) {
+            drag_line.attr("class", "drag_line_hidden");
+        }
+        if (lasso) {
+            var x = parseInt(lasso.attr("x"));
+            var y = parseInt(lasso.attr("y"));
+            var x2 = x+parseInt(lasso.attr("width"));
+            var y2 = y+parseInt(lasso.attr("height"));
+            if (!d3.event.ctrlKey) {
+                clearSelection();
+            }
+            RED.nodes.eachNode(function(n) {
+                if (n.z == activeWorkspace && !n.selected) {
+                    n.selected = (n.x > x && n.x < x2 && n.y > y && n.y < y2);
+                    if (n.selected) {
+                        n.dirty = true;
+                        moving_set.push({n:n});
+                    }
+                }
+            });
+            updateSelection();
+            lasso.remove();
+            lasso = null;
+        } else if (mouse_mode == RED.state.DEFAULT && mousedown_link == null && !d3.event.ctrlKey ) {
+            clearSelection();
+            updateSelection();
+        }
+        if (mouse_mode == RED.state.MOVING_ACTIVE) {
+            if (moving_set.length > 0) {
+                var ns = [];
+                for (var j=0;j<moving_set.length;j++) {
+                    ns.push({n:moving_set[j].n,ox:moving_set[j].ox,oy:moving_set[j].oy});
+                }
+                RED.history.push({t:'move',nodes:ns,dirty:dirty});
+            }
+        }
+        if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
+            for (var i=0;i<moving_set.length;i++) {
+                delete moving_set[i].ox;
+                delete moving_set[i].oy;
+            }
+        }
+        if (mouse_mode == RED.state.IMPORT_DRAGGING) {
+            RED.keyboard.remove(/* ESCAPE */ 27);
+            setDirty(true);
+        }
+        redraw();
+        // clear mouse event vars
+        resetMouseVars();
+    }
+
+    $('#btn-zoom-out').click(function() {zoomOut();});
+    $('#btn-zoom-zero').click(function() {zoomZero();});
+    $('#btn-zoom-in').click(function() {zoomIn();});
+    $("#chart").on('DOMMouseScroll mousewheel', function (evt) {
+        if ( evt.altKey ) {
+            evt.preventDefault();
+            evt.stopPropagation();
+            var move = -(evt.originalEvent.detail) || evt.originalEvent.wheelDelta;
+            if (move <= 0) { zoomOut(); }
+            else { zoomIn(); }
+        }
+    });
+    $("#chart").droppable({
+            accept:".palette_node",
+            drop: function( event, ui ) {
+                d3.event = event;
+                var selected_tool = ui.draggable[0].type;
+                var mousePos = d3.touches(this)[0]||d3.mouse(this);
+                mousePos[1] += this.scrollTop;
+                mousePos[0] += this.scrollLeft;
+                mousePos[1] /= scaleFactor;
+                mousePos[0] /= scaleFactor;
+
+                var nn = { id:(1+Math.random()*4294967295).toString(16),x: mousePos[0],y:mousePos[1],w:node_width,z:activeWorkspace};
+
+                nn.type = selected_tool;
+                nn._def = RED.nodes.getType(nn.type);
+                nn.outputs = nn._def.outputs;
+                nn.changed = true;
+
+                for (var d in nn._def.defaults) {
+                    if (nn._def.defaults.hasOwnProperty(d)) {
+                        nn[d] = nn._def.defaults[d].value;
+                    }
+                }
+
+                if (nn._def.onadd) {
+                    nn._def.onadd.call(nn);
+                }
+
+                nn.h = Math.max(node_height,(nn.outputs||0) * 15);
+                RED.history.push({t:'add',nodes:[nn.id],dirty:dirty});
+                RED.nodes.add(nn);
+                RED.editor.validateNode(nn);
+                setDirty(true);
+                // auto select dropped node - so info shows (if visible)
+                clearSelection();
+                nn.selected = true;
+                moving_set.push({n:nn});
+                updateSelection();
+                redraw();
+
+                if (nn._def.autoedit) {
+                    RED.editor.edit(nn);
+                }
+            }
+    });
+
+    function zoomIn() {
+        if (scaleFactor < 2) {
+            scaleFactor += 0.1;
+            redraw();
+        }
+    }
+    function zoomOut() {
+        if (scaleFactor > 0.3) {
+            scaleFactor -= 0.1;
+            redraw();
+        }
+    }
+    function zoomZero() {
+        scaleFactor = 1;
+        redraw();
+    }
+
+    function selectAll() {
+        RED.nodes.eachNode(function(n) {
+            if (n.z == activeWorkspace) {
+                if (!n.selected) {
+                    n.selected = true;
+                    n.dirty = true;
+                    moving_set.push({n:n});
+                }
+            }
+        });
+        selected_link = null;
+        updateSelection();
+        redraw();
+    }
+
+    function clearSelection() {
+        for (var i=0;i<moving_set.length;i++) {
+            var n = moving_set[i];
+            n.n.dirty = true;
+            n.n.selected = false;
+        }
+        moving_set = [];
+        selected_link = null;
+    }
+
+    function updateSelection() {
+        if (moving_set.length === 0) {
+            RED.menu.setDisabled("btn-export-menu",true);
+            RED.menu.setDisabled("btn-export-clipboard",true);
+            RED.menu.setDisabled("btn-export-library",true);
+        } else {
+            RED.menu.setDisabled("btn-export-menu",false);
+            RED.menu.setDisabled("btn-export-clipboard",false);
+            RED.menu.setDisabled("btn-export-library",false);
+        }
+        if (moving_set.length === 0 && selected_link == null) {
+            RED.keyboard.remove(/* backspace */ 8);
+            RED.keyboard.remove(/* delete */ 46);
+            RED.keyboard.remove(/* c */ 67);
+            RED.keyboard.remove(/* x */ 88);
+        } else {
+            RED.keyboard.add(/* backspace */ 8,function(){deleteSelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* delete */ 46,function(){deleteSelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* c */ 67,{ctrl:true},function(){copySelection();d3.event.preventDefault();});
+            RED.keyboard.add(/* x */ 88,{ctrl:true},function(){copySelection();deleteSelection();d3.event.preventDefault();});
+        }
+        if (moving_set.length === 0) {
+            RED.keyboard.remove(/* up   */ 38);
+            RED.keyboard.remove(/* down */ 40);
+            RED.keyboard.remove(/* left */ 37);
+            RED.keyboard.remove(/* right*/ 39);
+        } else {
+            RED.keyboard.add(/* up   */ 38, function() { if(d3.event.shiftKey){moveSelection(  0,-20)}else{moveSelection( 0,-1);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* down */ 40, function() { if(d3.event.shiftKey){moveSelection(  0, 20)}else{moveSelection( 0, 1);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* left */ 37, function() { if(d3.event.shiftKey){moveSelection(-20,  0)}else{moveSelection(-1, 0);}d3.event.preventDefault();},endKeyboardMove);
+            RED.keyboard.add(/* right*/ 39, function() { if(d3.event.shiftKey){moveSelection( 20,  0)}else{moveSelection( 1, 0);}d3.event.preventDefault();},endKeyboardMove);
+        }
+        if (moving_set.length == 1) {
+            RED.sidebar.info.refresh(moving_set[0].n);
+        } else {
+            RED.sidebar.info.clear();
+        }
+    }
+    function endKeyboardMove() {
+        var ns = [];
+        for (var i=0;i<moving_set.length;i++) {
+            ns.push({n:moving_set[i].n,ox:moving_set[i].ox,oy:moving_set[i].oy});
+            delete moving_set[i].ox;
+            delete moving_set[i].oy;
+        }
+        RED.history.push({t:'move',nodes:ns,dirty:dirty});
+    }
+    function moveSelection(dx,dy) {
+        var minX = 0;
+        var minY = 0;
+        var node;
+        
+        for (var i=0;i<moving_set.length;i++) {
+            node = moving_set[i];
+            if (node.ox == null && node.oy == null) {
+                node.ox = node.n.x;
+                node.oy = node.n.y;
+            }
+            node.n.x += dx;
+            node.n.y += dy;
+            node.n.dirty = true;
+            minX = Math.min(node.n.x-node.n.w/2-5,minX);
+            minY = Math.min(node.n.y-node.n.h/2-5,minY);
+        }
+
+        if (minX !== 0 || minY !== 0) {
+            for (var n = 0; n<moving_set.length; n++) {
+                node = moving_set[n];
+                node.n.x -= minX;
+                node.n.y -= minY;
+            }
+        }
+
+        redraw();
+    }
+    function deleteSelection() {
+        var removedNodes = [];
+        var removedLinks = [];
+        var startDirty = dirty;
+        if (moving_set.length > 0) {
+            for (var i=0;i<moving_set.length;i++) {
+                var node = moving_set[i].n;
+                node.selected = false;
+                if (node.x < 0) {
+                    node.x = 25
+                }
+                var rmlinks = RED.nodes.remove(node.id);
+                removedNodes.push(node);
+                removedLinks = removedLinks.concat(rmlinks);
+            }
+            moving_set = [];
+            setDirty(true);
+        }
+        if (selected_link) {
+            RED.nodes.removeLink(selected_link);
+            removedLinks.push(selected_link);
+            setDirty(true);
+        }
+        RED.history.push({t:'delete',nodes:removedNodes,links:removedLinks,dirty:startDirty});
+
+        selected_link = null;
+        updateSelection();
+        redraw();
+    }
+
+    function copySelection() {
+        if (moving_set.length > 0) {
+            var nns = [];
+            for (var n=0;n<moving_set.length;n++) {
+                var node = moving_set[n].n;
+                nns.push(RED.nodes.convertNode(node));
+            }
+            clipboard = JSON.stringify(nns);
+            RED.notify(moving_set.length+" node"+(moving_set.length>1?"s":"")+" copied");
+        }
+    }
+
+
+    function calculateTextWidth(str) {
+        var sp = document.createElement("span");
+        sp.className = "node_label";
+        sp.style.position = "absolute";
+        sp.style.top = "-1000px";
+        sp.innerHTML = (str||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+        document.body.appendChild(sp);
+        var w = sp.offsetWidth;
+        document.body.removeChild(sp);
+        return 50+w;
+    }
+
+    function resetMouseVars() {
+        mousedown_node = null;
+        mouseup_node = null;
+        mousedown_link = null;
+        mouse_mode = 0;
+        mousedown_port_type = 0;
+    }
+
+    function portMouseDown(d,portType,portIndex) {
+        // disable zoom
+        //vis.call(d3.behavior.zoom().on("zoom"), null);
+        mousedown_node = d;
+        selected_link = null;
+        mouse_mode = RED.state.JOINING;
+        mousedown_port_type = portType;
+        mousedown_port_index = portIndex || 0;
+        document.body.style.cursor = "crosshair";
+        d3.event.preventDefault();
+    }
+
+    function portMouseUp(d,portType,portIndex) {
+        document.body.style.cursor = "";
+        if (mouse_mode == RED.state.JOINING && mousedown_node) {
+            if (typeof TouchEvent != "undefined" && d3.event instanceof TouchEvent) {
+                RED.nodes.eachNode(function(n) {
+                        if (n.z == activeWorkspace) {
+                            var hw = n.w/2;
+                            var hh = n.h/2;
+                            if (n.x-hw<mouse_position[0] && n.x+hw> mouse_position[0] &&
+                                n.y-hh<mouse_position[1] && n.y+hh>mouse_position[1]) {
+                                    mouseup_node = n;
+                                    portType = mouseup_node._def.inputs>0?1:0;
+                                    portIndex = 0;
+                            }
+                        }
+                });
+            } else {
+                mouseup_node = d;
+            }
+            if (portType == mousedown_port_type || mouseup_node === mousedown_node) {
+                drag_line.attr("class", "drag_line_hidden");
+                resetMouseVars();
+                return;
+            }
+            var src,dst,src_port;
+            if (mousedown_port_type === 0) {
+                src = mousedown_node;
+                src_port = mousedown_port_index;
+                dst = mouseup_node;
+            } else if (mousedown_port_type == 1) {
+                src = mouseup_node;
+                dst = mousedown_node;
+                src_port = portIndex;
+            }
+
+            var existingLink = false;
+            RED.nodes.eachLink(function(d) {
+                    existingLink = existingLink || (d.source === src && d.target === dst && d.sourcePort == src_port);
+            });
+            if (!existingLink) {
+                var link = {source: src, sourcePort:src_port, target: dst};
+                RED.nodes.addLink(link);
+                RED.history.push({t:'add',links:[link],dirty:dirty});
+                setDirty(true);
+            }
+            selected_link = null;
+            redraw();
+        }
+    }
+
+    function nodeMouseUp(d) {
+        if (dblClickPrimed && mousedown_node == d && clickElapsed > 0 && clickElapsed < 750) {
+            RED.editor.edit(d);
+            clickElapsed = 0;
+            d3.event.stopPropagation();
+            return;
+        }
+        portMouseUp(d, d._def.inputs > 0 ? 1 : 0, 0);
+    }
+
+    function nodeMouseDown(d) {
+        //var touch0 = d3.event;
+        //var pos = [touch0.pageX,touch0.pageY];
+        //RED.touch.radialMenu.show(d3.select(this),pos);
+        if (mouse_mode == RED.state.IMPORT_DRAGGING) {
+            RED.keyboard.remove(/* ESCAPE */ 27);
+            updateSelection();
+            setDirty(true);
+            redraw();
+            resetMouseVars();
+            d3.event.stopPropagation();
+            return;
+        }
+        mousedown_node = d;
+        var now = Date.now();
+        clickElapsed = now-clickTime;
+        clickTime = now;
+
+        dblClickPrimed = (lastClickNode == mousedown_node);
+        lastClickNode = mousedown_node;
+        
+        var i;
+        
+        if (d.selected && d3.event.ctrlKey) {
+            d.selected = false;
+            for (i=0;i<moving_set.length;i+=1) {
+                if (moving_set[i].n === d) {
+                    moving_set.splice(i,1);
+                    break;
+                }
+            }
+        } else {
+            if (d3.event.shiftKey) {
+                clearSelection();
+                var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
+                for (var n=0;n<cnodes.length;n++) {
+                    cnodes[n].selected = true;
+                    cnodes[n].dirty = true;
+                    moving_set.push({n:cnodes[n]});
+                }
+            } else if (!d.selected) {
+                if (!d3.event.ctrlKey) {
+                    clearSelection();
+                }
+                mousedown_node.selected = true;
+                moving_set.push({n:mousedown_node});
+            }
+            selected_link = null;
+            if (d3.event.button != 2) {
+                mouse_mode = RED.state.MOVING;
+                var mouse = d3.touches(this)[0]||d3.mouse(this);
+                mouse[0] += d.x-d.w/2;
+                mouse[1] += d.y-d.h/2;
+                for (i=0;i<moving_set.length;i++) {
+                    moving_set[i].ox = moving_set[i].n.x;
+                    moving_set[i].oy = moving_set[i].n.y;
+                    moving_set[i].dx = moving_set[i].n.x-mouse[0];
+                    moving_set[i].dy = moving_set[i].n.y-mouse[1];
+                }
+                mouse_offset = d3.mouse(document.body);
+                if (isNaN(mouse_offset[0])) {
+                    mouse_offset = d3.touches(document.body)[0];
+                }
+            }
+        }
+        d.dirty = true;
+        updateSelection();
+        redraw();
+        d3.event.stopPropagation();
+    }
+
+    function nodeButtonClicked(d) {
+        if (d._def.button.toggle) {
+            d[d._def.button.toggle] = !d[d._def.button.toggle];
+            d.dirty = true;
+        }
+        if (d._def.button.onclick) {
+            d._def.button.onclick.call(d);
+        }
+        if (d.dirty) {
+            redraw();
+        }
+        d3.event.preventDefault();
+    }
+
+    function showTouchMenu(obj,pos) {
+        var mdn = mousedown_node;
+        var options = [];
+        options.push({name:"delete",disabled:(moving_set.length===0),onselect:function() {deleteSelection();}});
+        options.push({name:"cut",disabled:(moving_set.length===0),onselect:function() {copySelection();deleteSelection();}});
+        options.push({name:"copy",disabled:(moving_set.length===0),onselect:function() {copySelection();}});
+        options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard,true);}});
+        options.push({name:"edit",disabled:(moving_set.length != 1),onselect:function() { RED.editor.edit(mdn);}});
+        options.push({name:"select",onselect:function() {selectAll();}});
+        options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
+        
+        RED.touch.radialMenu.show(obj,pos,options);
+        resetMouseVars();
+    }
+    function redraw() {
+        vis.attr("transform","scale("+scaleFactor+")");
+        outer.attr("width", space_width*scaleFactor).attr("height", space_height*scaleFactor);
+
+        if (mouse_mode != RED.state.JOINING) {
+            // Don't bother redrawing nodes if we're drawing links
+
+            var node = vis.selectAll(".nodegroup").data(RED.nodes.nodes.filter(function(d) { return d.z == activeWorkspace }),function(d){return d.id});
+            node.exit().remove();
+
+            var nodeEnter = node.enter().insert("svg:g").attr("class", "node nodegroup");
+            nodeEnter.each(function(d,i) {
+                    var node = d3.select(this);
+                    node.attr("id",d.id);
+                    var l = d._def.label;
+                    l = (typeof l === "function" ? l.call(d) : l)||"";
+                    d.w = Math.max(node_width,calculateTextWidth(l)+(d._def.inputs>0?7:0) );
+                    d.h = Math.max(node_height,(d.outputs||0) * 15);
+
+                    if (d._def.badge) {
+                        var badge = node.append("svg:g").attr("class","node_badge_group");
+                        var badgeRect = badge.append("rect").attr("class","node_badge").attr("rx",5).attr("ry",5).attr("width",40).attr("height",15);
+                        badge.append("svg:text").attr("class","node_badge_label").attr("x",35).attr("y",11).attr('text-anchor','end').text(d._def.badge());
+                        if (d._def.onbadgeclick) {
+                            badgeRect.attr("cursor","pointer")
+                                .on("click",function(d) { d._def.onbadgeclick.call(d);d3.event.preventDefault();});
+                        }
+                    }
+
+                    if (d._def.button) {
+                        var nodeButtonGroup = node.append('svg:g')
+                            .attr("transform",function(d) { return "translate("+((d._def.align == "right") ? 94 : -25)+",2)"; })
+                            .attr("class",function(d) { return "node_button "+((d._def.align == "right") ? "node_right_button" : "node_left_button"); });
+                        nodeButtonGroup.append('rect')
+                            .attr("rx",8)
+                            .attr("ry",8)
+                            .attr("width",32)
+                            .attr("height",node_height-4)
+                            .attr("fill","#eee");//function(d) { return d._def.color;})
+                        nodeButtonGroup.append('rect')
+                            .attr("x",function(d) { return d._def.align == "right"? 10:5})
+                            .attr("y",4)
+                            .attr("rx",5)
+                            .attr("ry",5)
+                            .attr("width",16)
+                            .attr("height",node_height-12)
+                            .attr("fill",function(d) { return d._def.color;})
+                            .attr("cursor","pointer")
+                            .on("mousedown",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.2);d3.event.preventDefault(); d3.event.stopPropagation();}})
+                            .on("mouseup",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.4);d3.event.preventDefault();d3.event.stopPropagation();}})
+                            .on("mouseover",function(d) {if (!lasso) { d3.select(this).attr("fill-opacity",0.4);}})
+                            .on("mouseout",function(d) {if (!lasso) {
+                                var op = 1;
+                                if (d._def.button.toggle) {
+                                    op = d[d._def.button.toggle]?1:0.2;
+                                }
+                                d3.select(this).attr("fill-opacity",op);
+                            }})
+                            .on("click",nodeButtonClicked)
+                            .on("touchstart",nodeButtonClicked)
+                    }
+
+                    var mainRect = node.append("rect")
+                        .attr("class", "node")
+                        .classed("node_unknown",function(d) { return d.type == "unknown"; })
+                        .attr("rx", 6)
+                        .attr("ry", 6)
+                        .attr("fill",function(d) { return d._def.color;})
+                        .on("mouseup",nodeMouseUp)
+                        .on("mousedown",nodeMouseDown)
+                        .on("touchstart",function(d) {
+                            var obj = d3.select(this);
+                            var touch0 = d3.event.touches.item(0);
+                            var pos = [touch0.pageX,touch0.pageY];
+                            startTouchCenter = [touch0.pageX,touch0.pageY];
+                            startTouchDistance = 0;
+                            touchStartTime = setTimeout(function() {
+                                showTouchMenu(obj,pos);
+                            },touchLongPressTimeout);
+                            nodeMouseDown.call(this,d)       
+                        })
+                        .on("touchend", function(d) {
+                            clearTimeout(touchStartTime);
+                            touchStartTime = null;
+                            if  (RED.touch.radialMenu.active()) {
+                                d3.event.stopPropagation();
+                                return;
+                            }
+                            nodeMouseUp.call(this,d);
+                        })
+                        .on("mouseover",function(d) {
+                                if (mouse_mode === 0) {
+                                    var node = d3.select(this);
+                                    node.classed("node_hovered",true);
+                                }
+                        })
+                        .on("mouseout",function(d) {
+                                var node = d3.select(this);
+                                node.classed("node_hovered",false);
+                        });
+
+                   //node.append("rect").attr("class", "node-gradient-top").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-top)").style("pointer-events","none");
+                   //node.append("rect").attr("class", "node-gradient-bottom").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-bottom)").style("pointer-events","none");
+
+                    if (d._def.icon) {
+                        
+                        var icon_group = node.append("g")
+                            .attr("class","node_icon_group")
+                            .attr("x",0).attr("y",0);
+                        
+                        var icon_shade = icon_group.append("rect")
+                            .attr("x",0).attr("y",0)
+                            .attr("class","node_icon_shade")
+                            .attr("width","30")
+                            .attr("stroke","none")
+                            .attr("fill","#000")
+                            .attr("fill-opacity","0.05")
+                            .attr("height",function(d){return Math.min(50,d.h-4);});
+                            
+                        var icon = icon_group.append("image")
+                            .attr("xlink:href","icons/"+d._def.icon)
+                            .attr("class","node_icon")
+                            .attr("x",0)
+                            .attr("width","30")
+                            .attr("height","30");
+                            
+                        var icon_shade_border = icon_group.append("path")
+                            .attr("d",function(d) { return "M 30 1 l 0 "+(d.h-2)})
+                            .attr("class","node_icon_shade_border")
+                            .attr("stroke-opacity","0.1")
+                            .attr("stroke","#000")
+                            .attr("stroke-width","2");
+
+                        if ("right" == d._def.align) {
+                            icon_group.attr('class','node_icon_group node_icon_group_'+d._def.align);
+                            icon_shade_border.attr("d",function(d) { return "M 0 1 l 0 "+(d.h-2)})
+                            //icon.attr('class','node_icon node_icon_'+d._def.align);
+                            //icon.attr('class','node_icon_shade node_icon_shade_'+d._def.align);
+                            //icon.attr('class','node_icon_shade_border node_icon_shade_border_'+d._def.align);
+                        }
+                        
+                        //if (d._def.inputs > 0 && d._def.align == null) {
+                        //    icon_shade.attr("width",35);
+                        //    icon.attr("transform","translate(5,0)");
+                        //    icon_shade_border.attr("transform","translate(5,0)");
+                        //}
+                        //if (d._def.outputs > 0 && "right" == d._def.align) {
+                        //    icon_shade.attr("width",35); //icon.attr("x",5);
+                        //}
+                        
+                        var img = new Image();
+                        img.src = "icons/"+d._def.icon;
+                        img.onload = function() {
+                            icon.attr("width",Math.min(img.width,30));
+                            icon.attr("height",Math.min(img.height,30));
+                            icon.attr("x",15-Math.min(img.width,30)/2);
+                            //if ("right" == d._def.align) {
+                            //    icon.attr("x",function(d){return d.w-img.width-1-(d.outputs>0?5:0);});
+                            //    icon_shade.attr("x",function(d){return d.w-30});
+                            //    icon_shade_border.attr("d",function(d){return "M "+(d.w-30)+" 1 l 0 "+(d.h-2);});
+                            //}
+                        }
+                        
+                        //icon.style("pointer-events","none");
+                        icon_group.style("pointer-events","none");
+                    }
+                    var text = node.append('svg:text').attr('class','node_label').attr('x', 38).attr('dy', '.35em').attr('text-anchor','start');
+                    if (d._def.align) {
+                        text.attr('class','node_label node_label_'+d._def.align);
+                        text.attr('text-anchor','end');
+                    }
+
+                    var status = node.append("svg:g").attr("class","node_status_group").style("display","none");
+
+                    var statusRect = status.append("rect").attr("class","node_status")
+                                        .attr("x",6).attr("y",1).attr("width",9).attr("height",9)
+                                        .attr("rx",2).attr("ry",2).attr("stroke-width","3");
+
+                    var statusLabel = status.append("svg:text")
+                        .attr("class","node_status_label")
+                        .attr('x',20).attr('y',9)
+                        .style({
+                                'stroke-width': 0,
+                                'fill': '#888',
+                                'font-size':'9pt',
+                                'stroke':'#000',
+                                'text-anchor':'start'
+                        });
+
+                    //node.append("circle").attr({"class":"centerDot","cx":0,"cy":0,"r":5});
+
+                    if (d._def.inputs > 0) {
+                        text.attr("x",38);
+                        node.append("rect").attr("class","port port_input").attr("rx",3).attr("ry",3).attr("x",-5).attr("width",10).attr("height",10)
+                            .on("mousedown",function(d){portMouseDown(d,1,0);})
+                            .on("touchstart",function(d){portMouseDown(d,1,0);})
+                            .on("mouseup",function(d){portMouseUp(d,1,0);} )
+                            .on("touchend",function(d){portMouseUp(d,1,0);} )
+                            .on("mouseover",function(d) { var port = d3.select(this); port.classed("port_hovered",(mouse_mode!=RED.state.JOINING || mousedown_port_type != 1 ));})
+                            .on("mouseout",function(d) { var port = d3.select(this); port.classed("port_hovered",false);})
+                    }
+
+                    //node.append("path").attr("class","node_error").attr("d","M 3,-3 l 10,0 l -5,-8 z");
+                    node.append("image").attr("class","node_error hidden").attr("xlink:href","icons/node-error.png").attr("x",0).attr("y",-6).attr("width",10).attr("height",9);
+                    node.append("image").attr("class","node_changed hidden").attr("xlink:href","icons/node-changed.png").attr("x",12).attr("y",-6).attr("width",10).attr("height",10);
+            });
+
+            node.each(function(d,i) {
+                    if (d.dirty) {
+                        //if (d.x < -50) deleteSelection();  // Delete nodes if dragged back to palette
+                        if (d.resize) {
+                            var l = d._def.label;
+                            l = (typeof l === "function" ? l.call(d) : l)||"";
+                            d.w = Math.max(node_width,calculateTextWidth(l)+(d._def.inputs>0?7:0) );
+                            d.h = Math.max(node_height,(d.outputs||0) * 15);
+                        }
+                        var thisNode = d3.select(this);
+                        //thisNode.selectAll(".centerDot").attr({"cx":function(d) { return d.w/2;},"cy":function(d){return d.h/2}});
+                        thisNode.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; });
+                        thisNode.selectAll(".node")
+                            .attr("width",function(d){return d.w})
+                            .attr("height",function(d){return d.h})
+                            .classed("node_selected",function(d) { return d.selected; })
+                            .classed("node_highlighted",function(d) { return d.highlighted; })
+                        ;
+                        //thisNode.selectAll(".node-gradient-top").attr("width",function(d){return d.w});
+                        //thisNode.selectAll(".node-gradient-bottom").attr("width",function(d){return d.w}).attr("y",function(d){return d.h-30});
+
+                        thisNode.selectAll(".node_icon_group_right").attr('transform', function(d){return "translate("+(d.w-30)+",0)"});
+                        thisNode.selectAll(".node_label_right").attr('x', function(d){return d.w-38});
+                        //thisNode.selectAll(".node_icon_right").attr("x",function(d){return d.w-d3.select(this).attr("width")-1-(d.outputs>0?5:0);});
+                        //thisNode.selectAll(".node_icon_shade_right").attr("x",function(d){return d.w-30;});
+                        //thisNode.selectAll(".node_icon_shade_border_right").attr("d",function(d){return "M "+(d.w-30)+" 1 l 0 "+(d.h-2)});
+
+                        
+                        var numOutputs = d.outputs;
+                        var y = (d.h/2)-((numOutputs-1)/2)*13;
+                        d.ports = d.ports || d3.range(numOutputs);
+                        d._ports = thisNode.selectAll(".port_output").data(d.ports);
+                        d._ports.enter().append("rect").attr("class","port port_output").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
+                            .on("mousedown",(function(){var node = d; return function(d,i){portMouseDown(node,0,i);}})() )
+                            .on("touchstart",(function(){var node = d; return function(d,i){portMouseDown(node,0,i);}})() )
+                            .on("mouseup",(function(){var node = d; return function(d,i){portMouseUp(node,0,i);}})() )
+                            .on("touchend",(function(){var node = d; return function(d,i){portMouseUp(node,0,i);}})() )
+                            .on("mouseover",function(d,i) { var port = d3.select(this); port.classed("port_hovered",(mouse_mode!=RED.state.JOINING || mousedown_port_type !== 0 ));})
+                            .on("mouseout",function(d,i) { var port = d3.select(this); port.classed("port_hovered",false);});
+                        d._ports.exit().remove();
+                        if (d._ports) {
+                            numOutputs = d.outputs || 1;
+                            y = (d.h/2)-((numOutputs-1)/2)*13;
+                            var x = d.w - 5;
+                            d._ports.each(function(d,i) {
+                                    var port = d3.select(this);
+                                    port.attr("y",(y+13*i)-5).attr("x",x);
+                            });
+                        }
+                        thisNode.selectAll('text.node_label').text(function(d,i){
+                                if (d._def.label) {
+                                    if (typeof d._def.label == "function") {
+                                        return d._def.label.call(d);
+                                    } else {
+                                        return d._def.label;
+                                    }
+                                }
+                                return "";
+                        })
+                            .attr('y', function(d){return (d.h/2)-1;})
+                            .attr('class',function(d){
+                                return 'node_label'+
+                                (d._def.align?' node_label_'+d._def.align:'')+
+                                (d._def.labelStyle?' '+(typeof d._def.labelStyle == "function" ? d._def.labelStyle.call(d):d._def.labelStyle):'') ;
+                        });
+                        thisNode.selectAll(".node_tools").attr("x",function(d){return d.w-35;}).attr("y",function(d){return d.h-20;});
+
+                        thisNode.selectAll(".node_changed")
+                            .attr("x",function(d){return d.w-10})
+                            .classed("hidden",function(d) { return !d.changed; });
+
+                        thisNode.selectAll(".node_error")
+                            .attr("x",function(d){return d.w-10-(d.changed?13:0)})
+                            .classed("hidden",function(d) { return d.valid; });
+
+                        thisNode.selectAll(".port_input").each(function(d,i) {
+                                var port = d3.select(this);
+                                port.attr("y",function(d){return (d.h/2)-5;})
+                        });
+
+                        thisNode.selectAll(".node_icon").attr("y",function(d){return (d.h-d3.select(this).attr("height"))/2;});
+                        thisNode.selectAll(".node_icon_shade").attr("height",function(d){return d.h;});
+                        thisNode.selectAll(".node_icon_shade_border").attr("d",function(d){ return "M "+(("right" == d._def.align) ?0:30)+" 1 l 0 "+(d.h-2)});
+
+                        
+                        thisNode.selectAll('.node_right_button').attr("transform",function(d){
+                                var x = d.w-6;
+                                if (d._def.button.toggle && !d[d._def.button.toggle]) {
+                                    x = x - 8;
+                                }
+                                return "translate("+x+",2)";
+                        });
+                        thisNode.selectAll('.node_right_button rect').attr("fill-opacity",function(d){
+                                if (d._def.button.toggle) {
+                                    return d[d._def.button.toggle]?1:0.2;
+                                }
+                                return 1;
+                        });
+
+                        //thisNode.selectAll('.node_right_button').attr("transform",function(d){return "translate("+(d.w - d._def.button.width.call(d))+","+0+")";}).attr("fill",function(d) {
+                        //         return typeof d._def.button.color  === "function" ? d._def.button.color.call(d):(d._def.button.color != null ? d._def.button.color : d._def.color)
+                        //});
+
+                        thisNode.selectAll('.node_badge_group').attr("transform",function(d){return "translate("+(d.w-40)+","+(d.h+3)+")";});
+                        thisNode.selectAll('text.node_badge_label').text(function(d,i) {
+                            if (d._def.badge) {
+                                if (typeof d._def.badge == "function") {
+                                    return d._def.badge.call(d);
+                                } else {
+                                    return d._def.badge;
+                                }
+                            }
+                            return "";
+                        });
+                        if (!showStatus || !d.status) {
+                            thisNode.selectAll('.node_status_group').style("display","none");
+                        } else {
+                            thisNode.selectAll('.node_status_group').style("display","inline").attr("transform","translate(3,"+(d.h+3)+")");
+                            var fill = status_colours[d.status.fill]; // Only allow our colours for now
+                            if (d.status.shape == null && fill == null) {
+                                thisNode.selectAll('.node_status').style("display","none");
+                            } else {
+                                var style;
+                                if (d.status.shape == null || d.status.shape == "dot") {
+                                    style = {
+                                        display: "inline",
+                                        fill: fill,
+                                        stroke: fill
+                                    };
+                                } else if (d.status.shape == "ring" ){
+                                    style = {
+                                        display: "inline",
+                                        fill: '#fff',
+                                        stroke: fill
+                                    }
+                                }
+                                thisNode.selectAll('.node_status').style(style);
+                            }
+                            if (d.status.text) {
+                                thisNode.selectAll('.node_status_label').text(d.status.text);
+                            } else {
+                                thisNode.selectAll('.node_status_label').text("");
+                            }
+                        }
+
+                        d.dirty = false;
+                    }
+            });
+        }
+
+        var link = vis.selectAll(".link").data(RED.nodes.links.filter(function(d) { return d.source.z == activeWorkspace && d.target.z == activeWorkspace }),function(d) { return d.source.id+":"+d.sourcePort+":"+d.target.id;});
+
+        var linkEnter = link.enter().insert("g",".node").attr("class","link");
+        
+        linkEnter.each(function(d,i) {
+            var l = d3.select(this);
+            l.append("svg:path").attr("class","link_background link_path")
+               .on("mousedown",function(d) {
+                    mousedown_link = d;
+                    clearSelection();
+                    selected_link = mousedown_link;
+                    updateSelection();
+                    redraw();
+                    d3.event.stopPropagation();
+                })
+                .on("touchstart",function(d) {
+                    mousedown_link = d;
+                    clearSelection();
+                    selected_link = mousedown_link;
+                    updateSelection();
+                    redraw();
+                    d3.event.stopPropagation();
+                });
+            l.append("svg:path").attr("class","link_outline link_path");
+            l.append("svg:path").attr("class","link_line link_path");
+        });
+
+        link.exit().remove();
+
+        var links = vis.selectAll(".link_path")
+        links.attr("d",function(d){
+                var numOutputs = d.source.outputs || 1;
+                var sourcePort = d.sourcePort || 0;
+                var y = -((numOutputs-1)/2)*13 +13*sourcePort;
+
+                var dy = d.target.y-(d.source.y+y);
+                var dx = (d.target.x-d.target.w/2)-(d.source.x+d.source.w/2);
+                var delta = Math.sqrt(dy*dy+dx*dx);
+                var scale = lineCurveScale;
+                var scaleY = 0;
+                if (delta < node_width) {
+                    scale = 0.75-0.75*((node_width-delta)/node_width);
+                }
+
+                if (dx < 0) {
+                    scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
+                    if (Math.abs(dy) < 3*node_height) {
+                        scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
+                    }
+                }
+
+                d.x1 = d.source.x+d.source.w/2;
+                d.y1 = d.source.y+y;
+                d.x2 = d.target.x-d.target.w/2;
+                d.y2 = d.target.y;
+
+                return "M "+(d.source.x+d.source.w/2)+" "+(d.source.y+y)+
+                    " C "+(d.source.x+d.source.w/2+scale*node_width)+" "+(d.source.y+y+scaleY*node_height)+" "+
+                    (d.target.x-d.target.w/2-scale*node_width)+" "+(d.target.y-scaleY*node_height)+" "+
+                    (d.target.x-d.target.w/2)+" "+d.target.y;
+        })
+
+        link.classed("link_selected", function(d) { return d === selected_link || d.selected; });
+        link.classed("link_unknown",function(d) { return d.target.type == "unknown" || d.source.type == "unknown"});
+
+        if (d3.event) {
+            d3.event.preventDefault();
+        }
+    }
+
+    RED.keyboard.add(/* z */ 90,{ctrl:true},function(){RED.history.pop();});
+    RED.keyboard.add(/* a */ 65,{ctrl:true},function(){selectAll();d3.event.preventDefault();});
+    RED.keyboard.add(/* = */ 187,{ctrl:true},function(){zoomIn();d3.event.preventDefault();});
+    RED.keyboard.add(/* - */ 189,{ctrl:true},function(){zoomOut();d3.event.preventDefault();});
+    RED.keyboard.add(/* 0 */ 48,{ctrl:true},function(){zoomZero();d3.event.preventDefault();});
+    RED.keyboard.add(/* v */ 86,{ctrl:true},function(){importNodes(clipboard);d3.event.preventDefault();});
+    RED.keyboard.add(/* e */ 69,{ctrl:true},function(){showExportNodesDialog();d3.event.preventDefault();});
+    RED.keyboard.add(/* i */ 73,{ctrl:true},function(){showImportNodesDialog();d3.event.preventDefault();});
+
+    // TODO: 'dirty' should be a property of RED.nodes - with an event callback for ui hooks
+    function setDirty(d) {
+        dirty = d;
+        if (dirty) {
+            $("#btn-deploy").removeClass("disabled");
+        } else {
+            $("#btn-deploy").addClass("disabled");
+        }
+    }
+
+    /**
+     * Imports a new collection of nodes from a JSON String.
+     *  - all get new IDs assigned
+     *  - all 'selected'
+     *  - attached to mouse for placing - 'IMPORT_DRAGGING'
+     */
+    function importNodes(newNodesStr,touchImport) {
+        try {
+            var result = RED.nodes.import(newNodesStr,true);
+            if (result) {
+                var new_nodes = result[0];
+                var new_links = result[1];
+                var new_workspaces = result[2];
+                
+                var new_ms = new_nodes.filter(function(n) { return n.z == activeWorkspace }).map(function(n) { return {n:n};});
+                var new_node_ids = new_nodes.map(function(n){ return n.id; });
+                
+                // TODO: pick a more sensible root node
+                if (new_ms.length > 0) {
+                    var root_node = new_ms[0].n;
+                    var dx = root_node.x;
+                    var dy = root_node.y;
+    
+                    if (mouse_position == null) {
+                        mouse_position = [0,0];
+                    }
+    
+                    var minX = 0;
+                    var minY = 0;
+                    var i;
+                    var node;
+                    
+                    for (i=0;i<new_ms.length;i++) {
+                        node = new_ms[i];
+                        node.n.selected = true;
+                        node.n.changed = true;
+                        node.n.x -= dx - mouse_position[0];
+                        node.n.y -= dy - mouse_position[1];
+                        node.dx = node.n.x - mouse_position[0];
+                        node.dy = node.n.y - mouse_position[1];
+                        minX = Math.min(node.n.x-node_width/2-5,minX);
+                        minY = Math.min(node.n.y-node_height/2-5,minY);
+                    }
+                    for (i=0;i<new_ms.length;i++) {
+                        node = new_ms[i];
+                        node.n.x -= minX;
+                        node.n.y -= minY;
+                        node.dx -= minX;
+                        node.dy -= minY;
+                    }
+                    if (!touchImport) {
+                        mouse_mode = RED.state.IMPORT_DRAGGING;
+                    }
+    
+                    RED.keyboard.add(/* ESCAPE */ 27,function(){
+                            RED.keyboard.remove(/* ESCAPE */ 27);
+                            clearSelection();
+                            RED.history.pop();
+                            mouse_mode = 0;
+                    });
+                    clearSelection();
+                    moving_set = new_ms;
+                }
+
+                RED.history.push({t:'add',nodes:new_node_ids,links:new_links,workspaces:new_workspaces,dirty:RED.view.dirty()});
+
+
+                redraw();
+            }
+        } catch(error) {
+            console.log(error.stack);
+            RED.notify("<strong>Error</strong>: "+error,"error");
+        }
+    }
+
+    function showExportNodesDialog() {
+        mouse_mode = RED.state.EXPORT;
+        var nns = RED.nodes.createExportableNodeSet(moving_set);
+        $("#dialog-form").html($("script[data-template-name='export-clipboard-dialog']").html());
+        $("#node-input-export").val(JSON.stringify(nns));
+        $("#node-input-export").focus(function() {
+                var textarea = $(this);
+                textarea.select();
+                textarea.mouseup(function() {
+                        textarea.unbind("mouseup");
+                        return false;
+                });
+        });
+        $( "#dialog" ).dialog("option","title","Export nodes to clipboard").dialog( "open" );
+        $("#node-input-export").focus();
+    }
+
+    function showExportNodesLibraryDialog() {
+        mouse_mode = RED.state.EXPORT;
+        var nns = RED.nodes.createExportableNodeSet(moving_set);
+        $("#dialog-form").html($("script[data-template-name='export-library-dialog']").html());
+        $("#node-input-filename").attr('nodes',JSON.stringify(nns));
+        $( "#dialog" ).dialog("option","title","Export nodes to library").dialog( "open" );
+    }
+
+    function showImportNodesDialog() {
+        mouse_mode = RED.state.IMPORT;
+        $("#dialog-form").html($("script[data-template-name='import-dialog']").html());
+        $("#node-input-import").val("");
+        $( "#dialog" ).dialog("option","title","Import nodes").dialog( "open" );
+    }
+
+    function showRenameWorkspaceDialog(id) {
+        var ws = RED.nodes.workspace(id);
+        $( "#node-dialog-rename-workspace" ).dialog("option","workspace",ws);
+
+        if (workspace_tabs.count() == 1) {
+            $( "#node-dialog-rename-workspace").next().find(".leftButton")
+                .prop('disabled',true)
+                .addClass("ui-state-disabled");
+        } else {
+            $( "#node-dialog-rename-workspace").next().find(".leftButton")
+                .prop('disabled',false)
+                .removeClass("ui-state-disabled");
+        }
+
+        $( "#node-input-workspace-name" ).val(ws.label);
+        $( "#node-dialog-rename-workspace" ).dialog("open");
+    }
+
+    $("#node-dialog-rename-workspace form" ).submit(function(e) { e.preventDefault();});
+    $( "#node-dialog-rename-workspace" ).dialog({
+        modal: true,
+        autoOpen: false,
+        width: 500,
+        title: "Rename sheet",
+        buttons: [
+            {
+                class: 'leftButton',
+                text: "Delete",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    $( this ).dialog( "close" );
+                    deleteWorkspace(workspace.id);
+                }
+            },
+            {
+                text: "Ok",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    var label = $( "#node-input-workspace-name" ).val();
+                    if (workspace.label != label) {
+                        workspace.label = label;
+                        var link = $("#workspace-tabs a[href='#"+workspace.id+"']");
+                        link.attr("title",label);
+                        link.text(label);
+                        RED.view.dirty(true);
+                    }
+                    $( this ).dialog( "close" );
+                }
+            },
+            {
+                text: "Cancel",
+                click: function() {
+                    $( this ).dialog( "close" );
+                }
+            }
+        ],
+        open: function(e) {
+            RED.keyboard.disable();
+        },
+        close: function(e) {
+            RED.keyboard.enable();
+        }
+    });
+    $( "#node-dialog-delete-workspace" ).dialog({
+        modal: true,
+        autoOpen: false,
+        width: 500,
+        title: "Confirm delete",
+        buttons: [
+            {
+                text: "Ok",
+                click: function() {
+                    var workspace = $(this).dialog('option','workspace');
+                    RED.view.removeWorkspace(workspace);
+                    var historyEvent = RED.nodes.removeWorkspace(workspace.id);
+                    historyEvent.t = 'delete';
+                    historyEvent.dirty = dirty;
+                    historyEvent.workspaces = [workspace];
+                    RED.history.push(historyEvent);
+                    RED.view.dirty(true);
+                    $( this ).dialog( "close" );
+                }
+            },
+            {
+                text: "Cancel",
+                click: function() {
+                    $( this ).dialog( "close" );
+                }
+            }
+        ],
+        open: function(e) {
+            RED.keyboard.disable();
+        },
+        close: function(e) {
+            RED.keyboard.enable();
+        }
+
+    });
+
+    return {
+        state:function(state) {
+            if (state == null) {
+                return mouse_mode
+            } else {
+                mouse_mode = state;
+            }
+        },
+        addWorkspace: function(ws) {
+            workspace_tabs.addTab(ws);
+            workspace_tabs.resize();
+        },
+        removeWorkspace: function(ws) {
+            workspace_tabs.removeTab(ws.id);
+        },
+        getWorkspace: function() {
+            return activeWorkspace;
+        },
+        showWorkspace: function(id) {
+            workspace_tabs.activateTab(id);
+        },
+        redraw:redraw,
+        dirty: function(d) {
+            if (d == null) {
+                return dirty;
+            } else {
+                setDirty(d);
+            }
+        },
+        importNodes: importNodes,
+        resize: function() {
+            workspace_tabs.resize();
+        },
+        status: function(s) {
+            showStatus = s;
+            RED.nodes.eachNode(function(n) { n.dirty = true;});
+            //TODO: subscribe/unsubscribe here
+            redraw();
+        },
+        
+        //TODO: should these move to an import/export module?
+        showImportNodesDialog: showImportNodesDialog,
+        showExportNodesDialog: showExportNodesDialog,
+        showExportNodesLibraryDialog: showExportNodesLibraryDialog
+    };
+})();
diff --git a/dgbuilder/public/red/validators.js b/dgbuilder/public/red/validators.js
new file mode 100644 (file)
index 0000000..5e74097
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+RED.validators = {
+    number: function(){return function(v) { return v!=='' && !isNaN(v);}},
+    regex: function(re){return function(v) { return re.test(v);}}
+};
diff --git a/dgbuilder/public/spin.svg b/dgbuilder/public/spin.svg
new file mode 100644 (file)
index 0000000..e609530
--- /dev/null
@@ -0,0 +1,41 @@
+<!-- 
+The MIT License (MIT)
+
+Copyright (c) 2014 Brent Jackson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+https://github.com/jxnblk/loading
+-->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="#999">
+  <path transform="translate(2)" d="M0 12 V20 H4 V12z"> 
+    <animate attributeName="d" values="M0 12 V20 H4 V12z; M0 4 V28 H4 V4z; M0 12 V20 H4 V12z; M0 12 V20 H4 V12z" dur="1.2s" repeatCount="indefinite" begin="0" keytimes="0;.2;.5;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.8 0.4 0.8" calcMode="spline"  />
+  </path>
+  <path transform="translate(8)" d="M0 12 V20 H4 V12z">
+    <animate attributeName="d" values="M0 12 V20 H4 V12z; M0 4 V28 H4 V4z; M0 12 V20 H4 V12z; M0 12 V20 H4 V12z" dur="1.2s" repeatCount="indefinite" begin="0.2" keytimes="0;.2;.5;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.8 0.4 0.8" calcMode="spline"  />
+  </path>
+  <path transform="translate(14)" d="M0 12 V20 H4 V12z">
+    <animate attributeName="d" values="M0 12 V20 H4 V12z; M0 4 V28 H4 V4z; M0 12 V20 H4 V12z; M0 12 V20 H4 V12z" dur="1.2s" repeatCount="indefinite" begin="0.4" keytimes="0;.2;.5;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.8 0.4 0.8" calcMode="spline" />
+  </path>
+  <path transform="translate(20)" d="M0 12 V20 H4 V12z">
+    <animate attributeName="d" values="M0 12 V20 H4 V12z; M0 4 V28 H4 V4z; M0 12 V20 H4 V12z; M0 12 V20 H4 V12z" dur="1.2s" repeatCount="indefinite" begin="0.6" keytimes="0;.2;.5;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.8 0.4 0.8" calcMode="spline" />
+  </path>
+  <path transform="translate(26)" d="M0 12 V20 H4 V12z">
+    <animate attributeName="d" values="M0 12 V20 H4 V12z; M0 4 V28 H4 V4z; M0 12 V20 H4 V12z; M0 12 V20 H4 V12z" dur="1.2s" repeatCount="indefinite" begin="0.8" keytimes="0;.2;.5;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.8 0.4 0.8" calcMode="spline" />
+  </path>
+</svg>
diff --git a/dgbuilder/public/style.css b/dgbuilder/public/style.css
new file mode 100644 (file)
index 0000000..3a1917b
--- /dev/null
@@ -0,0 +1,980 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+body {
+  font: 13px "Helvetica" !important;
+  padding-top: 100px;
+  background: url("pw_maze_white.png");
+}
+
+#header {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 40px;
+    background: #000;
+    box-sizing: border-box;
+    padding: 5px 0px 5px 20px;
+}
+
+#dropTarget {
+    position: absolute;
+    top: 0; bottom: 0;
+    left: 0; right: 0;
+    background: rgba(100,100,100,0.5);
+    display:table;
+    width: 100%;
+    height: 100%;
+    display: none;
+}
+#dropTarget div {
+    display: table-cell; 
+    vertical-align: middle;
+    text-align: center;
+    font-size: 40px;
+    color: #fff;
+}
+#dropTarget div i {
+    font-size: 80px;
+}
+div.btn-group, a.btn {
+    -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+span.logo {
+    pointer-events: none;
+    float: left;
+    font-size: 30px;
+    line-height: 30px;
+    text-decoration: none;
+    color: #ccc;
+}
+span.logo span {
+    vertical-align: middle;
+    font-size: 16px !important;
+}
+span.logo img {
+    height: 18px;
+}
+#header .button {
+    line-height: 22px;
+    display: inline-block;
+    font-size: 14px;
+    padding: 4px 12px;
+    text-decoration: none;
+    border-radius: 3px;
+    color: #ccc;
+    margin: auto 10px;
+    vertical-align: middle;
+}
+#header .button:not(.disabled):hover {
+    box-shadow: 0 0 2px #fff;
+}
+#btn-deploy:not(.disabled):hover {
+    background: #ca3f39;
+}
+
+#btn-deploy {
+    color: #fff !important;
+    background: #d24741;
+    box-shadow: 0 0 2px #fff;
+}
+#btn-deploy:not(.disabled):active {
+    background: #aa1f19 !important;
+    color: #ccc !important;
+    box-shadow: 0 0 2px #999;
+}
+#btn-deploy.disabled {
+    cursor: default;
+    background: #444 ;
+    color: #999 !important;
+}
+
+#btn-sidemenu {
+    font-size: 20px !important;
+}
+#btn-sidemenu:active, #btn-sidemenu.active {
+    background: #333 ;
+}
+#header .button:focus {
+    outline: none;
+}
+
+
+
+#workspace {
+   margin-left: 160px;
+   overflow: hidden;
+}
+
+#chart {
+   overflow: auto;
+   background: #e3e3e3;
+   position: absolute;
+   bottom:0px;
+   top: 30px;
+   left:0px;
+   right:0px;
+}
+
+#workspace-toolbar {
+    display: none;
+    position: absolute;
+    top: 30px;
+    left:0;
+    right: 18px;
+    padding: 5px;
+    background: #f3f3f3;
+}
+
+#chart-zoom-controls {
+    padding-top: 3px;
+    text-align: right;
+    float: right;
+}
+
+#palette {
+   background: #f3f3f3;
+   width: 140px;
+   text-align: center;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+.palette-scroll {
+    display: none;
+    position: absolute;
+    top: 0;
+    left:0;
+    right: 0;
+    bottom: 35px;
+    padding: 5px;
+    overflow-y: auto;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+}
+.palette-spinner {
+    padding-top: 40px;
+}
+#palette-search {
+    position: absolute;
+    display: none;
+    bottom: 0;
+    left:0;
+    right:0;
+    overflow: hidden;
+    background: #f3f3f3;
+    text-align: center;
+    height: 35px;
+    padding: 3px;
+    border-top: 1px solid #999;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+}
+#palette-search i.fa-search {
+    position: absolute;
+    pointer-events: none;
+    left: 4px;
+    top: 10px;
+}
+#palette-search i.fa-times {
+    position: absolute;
+    right: 6px;
+    top: 10px;
+}
+
+#palette-search-clear {
+    display: none;
+    color: #000;
+}
+
+#palette-search input {
+    border-radius: 0;
+    border: none;
+    width: 100%;
+    box-shadow: none;
+    -webkit-box-shadow: none;
+    padding: 3px 17px;
+    margin: 0px;
+    height: 30px;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+    
+}
+#palette-search input:focus {
+    border: none;
+    box-shadow: none;
+    -webkit-box-shadow: none;
+}
+
+.palette-category {
+    border: 1px solid #999;
+    border-radius: 3px;
+    margin-bottom: 5px;
+}
+.palette-content {
+    background: #fff;
+    border-top: 1px solid #aaa;
+    padding-bottom: 3px;
+}
+
+.palette-header {
+    background: #f3f3f3;
+    border-radius: 3px;
+    cursor: pointer;
+    text-align: left;
+    padding: 1px;
+}
+.palette-header i {
+    margin: 3px 4px 3px 3px;
+    -webkit-transition: all 0.2s ease-in-out;
+    -moz-transition: all 0.2s ease-in-out;
+    -o-transition: all 0.2s ease-in-out;
+    -webkit-transform: rotate(-90deg);
+    -moz-transform: rotate(-90deg);
+    -o-transform: rotate(-90deg);
+}
+.palette-header i.expanded {
+    -webkit-transform: rotate(0deg);
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+}
+.palette-header span {
+    clear: both;
+}
+.palette_label {
+   line-height: 25px;
+   text-align: center;
+
+}
+.palette_node {
+   cursor:move;
+   font-size:13px;
+   background: #ddd;
+   margin: 10px auto;
+   height: 25px;
+   border-radius: 6px;
+   border: 2px solid #999;
+   background-position: 5% 50%;
+   background-repeat: no-repeat;
+   width: 90px;
+   background-size: contain;
+   position: relative;
+}
+.palette_node:hover {
+  border-color: #ff7f0e;
+  background-color: #eee;
+}
+.palette_port {
+   position: absolute;
+   top:8px;
+   left: -5px;
+   box-sizing: border-box;
+    -moz-box-sizing: border-box;    
+   background:#d9d9d9;
+   border-radius: 3px;
+   width: 10px;
+   height: 10px;
+   border: 1px solid #999;
+}
+.palette_port_output {
+    left:85px;
+}
+
+.palette_node:hover .palette_port {
+  border-color: #999;
+  background-color: #eee;
+}
+
+#sidebar {
+    background: #fff;
+    box-sizing: border-box;
+    -moz-box-sizing: border-box;    
+}
+#sidebar.closing {
+    background: #eee;
+    border-color: #900;
+    border-style: dashed;
+}
+
+/* ---------- Layout ---------- */
+#main-container {
+    position: absolute;
+    top:50px; left:0; bottom: 0; right:0;
+    overflow:hidden;
+}
+#palette {
+    position: absolute;
+    top: 5px; left:10px; bottom: 10px;
+}
+#workspace {
+    position: absolute;
+    margin: 0;
+    top:5px; left:160px; bottom: 10px; right: 330px;
+}
+#chart-zoom-controls {
+    position: absolute;
+    bottom:30px; right: 350px;
+}
+#sidebar {
+    width: 305px;
+    position: absolute;
+    right: 10px; top: 5px; bottom:10px;
+}
+#sidebar-separator {
+    width: 15px;
+    background: url(grip.png) no-repeat 50% 50%;
+    position: absolute;
+    right: 316px; top: 5px; bottom:10px;
+    cursor: col-resize;
+}
+
+.sidebar-closed > #sidebar { display: none; }
+.sidebar-closed > #sidebar-separator { right: 0px !important; }
+.sidebar-closed > #workspace { right: 15px !important; }
+.sidebar-closed > #chart-zoom-controls { right: 35px !important; }
+
+.palette-bar-closed > #palette { display: none; }
+.palette-bar-closed > #workspace { margin-left: -140px !important; }
+/* ---------- end layout ---------- */
+
+.lasso {
+    stroke-width: 2px;
+    stroke: #ff7f0e;
+    fill: rgba(20,125,255,0.1);
+    stroke-dasharray: 10 5;
+}
+
+.group-box {
+    stroke-width: 1px;
+    stroke: #aaaaaa;
+    fill: rgba(208, 211, 238, 0.1);
+    stroke-dasharray: 3 3;
+}
+.group-box-active {
+    fill: #fff;
+    stroke: #ff7f0e;
+}
+
+.group_label {
+   stroke-width: 0;
+   fill: #999;
+   font-size: 11px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+.pull-right {
+    margin-left: 20px;
+}
+
+#workspace, #palette, #sidebar {
+   border: 1px solid #000;
+   border-radius: 3px;
+}
+#sidebar-content {
+    font-size: 1.2em;
+    overflow-y: auto;
+    position: absolute;
+    top: 30px; left: 0px; right: 0; bottom: 1px;
+}
+
+.node_label_italic {
+    font-style: italic;
+}
+.node_label_unknown {
+    font-style: italic;
+    fill: #e00 !important;
+}
+.node_label_white {
+  fill: #eee !important;
+}
+.node_label {
+   stroke-width: 0;
+   fill: #333;
+   font-size: 14px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+.function_label {
+   font-size: 12px;
+}
+.node {
+  stroke: #999;
+  cursor: move;
+  stroke-width: 2;
+}
+.node_unknown {
+    stroke-dasharray:10,4;
+    stroke: #f33;
+}
+.tool_arrow {
+   stroke-width: 1;
+   stroke: #999;
+   fill: #999;
+   cursor: pointer;
+}
+.node_tools {
+  fill: #ddd;
+  stroke: #999;
+  cursor: move;
+  stroke-width: 1;
+  cursor: pointer;
+}
+.node_tools_hovered {
+  stroke: #ff7f0e;
+  fill: #eee;
+}
+
+.node_button {
+    fill: inherit;
+
+}
+.port {
+   fill: #ddd;
+   cursor: crosshair;
+}
+.node_error {
+    stroke: #ff0000;
+    stroke-width: 2;
+    fill: #ff7f0e;
+}
+
+.node_badge {
+    stroke: rgb(93, 114, 145);
+    stroke-width: 1;
+    fill: rgb(190, 209, 255);
+}
+.node_badge_label {
+   stroke-width:0;
+   fill: #fff;
+   font-size: 11px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+
+}
+.node_invalid {
+   stroke: #ff0000;
+}
+.node_selected {
+   stroke: #ff7f0e;
+}
+.node_found {
+ stroke:blue;
+ /*
+  stroke-width :3;
+ stroke-dasharray:5,1;
+*/     
+}
+.text_found {
+ stroke:green;
+  stroke-width :3;
+ stroke-dasharray:5,1;
+}
+.node_highlighted {
+   stroke: #dd1616;
+   stroke-width: 3;
+   stroke-dasharray: 10, 4;
+}
+.node_hovered {
+}
+
+.port_hovered {
+  stroke: #ff7f0e;
+  fill:  #ff7f0e;
+}
+
+.drag_line {
+  stroke: #ff7f0e;
+  stroke-width: 5;
+  fill: none;
+  pointer-events: none;
+}
+
+.drag_line_hidden {
+  stroke: #ff7f0e;
+  stroke-width: 0;
+  pointer-events: none;
+  fill: none;
+}
+
+.link_line {
+  stroke: #7f7f7f;
+  stroke-width: 4;
+  fill: none;
+  pointer-events: none;
+}
+
+.link_outline {
+  stroke: #fff;
+  stroke-width: 6;
+  cursor: crosshair;
+  fill: none;
+  pointer-events: none;
+}
+.link_background {
+  stroke: #fff;
+  opacity: 0;
+  stroke-width: 25;
+  cursor: crosshair;
+  fill: none;
+}
+
+g.link_selected path.link_line {
+  stroke: #ff7f0e;
+}
+g.link_unknown path.link_line {
+   stroke: #f00;
+   stroke-width: 2;
+   stroke-dasharray: 10, 4;
+}
+
+#shade {
+   position: absolute;
+   top:0;
+   left:0;
+   width: 100%;
+   height: 100%;
+   background: rgba(0,0,0,0.5);
+   text-align: center;
+   display: none;
+}
+
+#dialog {
+}
+
+.container {
+}
+
+.notification {
+    position: absolute;
+}
+#notifications {
+    z-index: 10000;
+    width: 500px;
+    margin-left: -250px;
+    left: 50%;
+    position: absolute;
+    top: 1px;
+}
+#notifications .alert {
+    box-shadow: 0 0 1px 1px;
+    margin-bottom: 5px;
+}
+
+.form-row {
+    clear: both;
+    margin-bottom: 7px;
+}
+.form-row label {
+    display: inline-block;
+    width: 100px;
+}
+.form-row input {
+    width:70%;
+}
+
+input.input-append-left {
+    border-top-right-radius: 0px;
+    border-bottom-right-radius: 0px;
+}
+button.input-append-right {
+    border-top-left-radius: 0px !important;
+    border-bottom-left-radius: 0px !important;
+    border-top-right-radius: 4px !important;
+    border-bottom-right-radius: 4px !important;
+    margin-left: -1px !important;
+    padding-left: 4px !important;
+    padding-right: 4px !important;
+}
+
+.form-tips {
+    background: lightgoldenrodyellow;
+    font-size: 12px;
+    padding: 8px;
+    border-radius: 5px;
+    border: 1px solid #999;
+}
+.form-tips code {
+    border: none;
+    padding: auto;
+}
+
+.ui-tabs .ui-tabs-panel {
+    padding: 0px;
+}
+
+table.node-info {
+    margin: 5px;
+    width: 97%;
+}
+table.node-info tr {
+    border: 1px solid #ddd;
+}
+table.node-info tr.blank {
+    border: none;
+}
+table.node-info tr.blank td {
+    padding-top: 8px;
+    border: none;
+    font-weight: bold;
+    padding-left: 0px;
+}
+table.node-info td:first-child{
+    color: #000;
+    vertical-align: top;
+    width: 90px;
+    padding: 3px;
+    border-right: 1px solid #ddd;
+}
+table.node-info td:last-child{
+    padding-left: 5px;
+    color: #666;
+}
+
+div.node-info {
+    margin: 5px;
+}
+
+.input-error {
+    border-color: rgb(214, 97, 95) !important;
+}
+
+.hidden {
+    display: none;
+}
+/*
+.dropdown-menu {
+    font-size: 14px;
+    background: #000;
+}
+.dropdown-menu .divider {
+    background: #666;
+    border-bottom: #666;
+}
+.dropdown-menu>li>a {
+    color: #ddd;
+}
+.dropdown-submenu>ul {
+    border: 1px solid white;
+    border-radius: 6px !important;
+}
+.dropdown-menu li.disabled  a {
+    color: #666;
+}
+.dropdown-menu li.disabled  a:hover {
+    background: none;
+}  
+*/
+.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus, .dropdown-submenu:hover>a, .dropdown-submenu:focus>a {
+    background: #999;
+}
+
+.dropdown-menu * .fa-check {
+    display: none;
+    margin-right: -15px;
+    margin-top: 3px;
+}
+.dropdown-menu * a.active > .fa-check {
+    display: inline-block;
+}
+.dropdown-menu>li.disabled>a:hover>[class^="icon-"] {
+    background-image: url("bootstrap/img/glyphicons-halflings.png") !important;
+}
+/** Fix for unreachable dropdown menu **/
+.dropdown-menu  {
+    width: 200px !important;
+}
+.dropdown-menu > li > a > i {
+    width: 10px;
+    text-align: center;
+    margin-left: -8px;
+}
+.dropdown-menu > li > a {
+     padding-left: 38px ;
+     text-indent: -8px ;
+     white-space: normal !important;
+}
+
+.popover-title { display: none; }
+
+.ui-autocomplete {
+    max-height: 250px;
+    overflow-x: hidden;
+    overflow-y: scroll;
+}
+
+.leftButton {
+    margin-right: 200px !important;
+}
+#node-help {
+    width: 700px;
+}
+#node-help * td {
+    padding: 0.8em 0.5em;
+}
+#node-help * tr > td:first-child+td+td {
+    padding-left: 5em;
+}
+
+.help-key {
+    border: 1px solid #ddd;
+    padding: 4px;
+    border-radius: 3px;
+    background: #f6f6f6;
+    font-family: Courier, monospace;
+    box-shadow: #999 1px 1px 1px;
+}
+
+#helpcontent {
+    padding: 20px;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+
+    background: #fff;
+}
+#helpnavigation {
+    overflow: hidden;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    background: #fff;
+}
+#helpnavigation li a{
+    font-size: 1.2em;
+    padding: 10px;
+    border-bottom: 1px solid #ddd;
+}
+
+#node-select-library {
+    overflow: hidden;
+}
+#node-select-library ul {
+    list-style: none;
+    padding: 0px;
+    margin: 2px;
+}
+#node-select-library li {
+    cursor: pointer;
+}
+#node-select-library li.list-selected {
+    background: #eee;
+}
+#node-select-library li.list-hover {
+    background: #ffffd0;
+}
+.node-text-editor {
+    border:1px solid #ccc;
+    border-radius:5px;
+    overflow: hidden;
+}
+#workspace-tabs {
+    margin-right: 28px;
+}
+#workspace-add-tab {
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 29px;
+    width: 28px;
+    border-bottom: 1px solid #999;
+}
+#btn-workspace-add-tab {
+    display: inline-block;
+    width: 100%;
+    background: #e3e3e3;
+    height: 100%;
+    line-height: 30px;
+    text-align: center;
+    color: #000;
+}
+#btn-workspace-add-tab:hover {
+    background: #efefef;
+}
+
+ul.red-ui-tabs {
+    list-style-type: none;
+    padding:5px 2px 0px 5px;
+    margin: 0;
+    display: block;
+    height: 24px;
+    border-bottom: 1px solid #999;
+    background: #e3e3e3;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+ul.red-ui-tabs li {
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+    display: inline-block;
+    border-left: 1px solid  #999;
+    border-top: 1px solid   #999;
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
+    background: #e3e3e3;
+    margin: 0 5px 0 0;
+    height: 23px;
+    line-height: 17px;
+    max-width: 150px;
+    width: 14%;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+ul.red-ui-tabs li a.red-ui-tab-label {
+    display: block; 
+    padding: 3px 16px;
+    color: #666;
+}
+ul.red-ui-tabs li {
+    position: relative;
+}
+
+ul.red-ui-tabs li a.red-ui-tab-close {
+    background: rgba(227,227,227,0.8);
+    position: absolute;
+    right: 2px;
+    top: 2px;
+    display: block;
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+    text-align: center;
+    padding: 0px;
+    border-radius: 5px;
+    color: #666;
+}
+ul.red-ui-tabs li a.red-ui-tab-close:hover {
+    background: #bbb !important;
+}
+ul.red-ui-tabs li a:hover {
+    text-decoration: none;
+    background: #f0f0f0;
+}
+
+ul.red-ui-tabs li.active {
+    background: #fff;
+    border-bottom: 1px solid #fff;
+}
+ul.red-ui-tabs li.active a {
+    color: #333;
+}
+ul.red-ui-tabs li.active a.red-ui-tab-close {
+    background: rgba(255,255,255,0.8);
+}
+ul.red-ui-tabs li.active a.red-ui-tab-label:hover {
+    background: #fff;
+}
+ul.red-ui-tabs li.red-ui-add-tab {
+    width: 25px;
+    border-top-right-radius: 15px;
+    line-height: 22px;
+}
+ul.red-ui-tabs li.red-ui-add-tab a {
+    padding: 2px 4px;
+}
+
+ul.tab-config-list {
+    list-style-type: none;
+    padding: 3px;
+    margin: 0;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+ul.tab-config-list li {
+    max-width: 400px;
+    font-size: 13px;
+    background: #f3f3f3;
+    margin: 10px auto;
+    border-radius: 3px;
+    border: 1px solid #ccc;
+    padding: 3px 8px;
+}
+div.tab-config-list-type {
+}
+
+div.tab-config-list-entry {
+    position: relative;
+    margin: 4px 0;
+    padding: 8px 4px 8px 10px;
+    background: #fff;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    cursor: pointer;
+}
+div.tab-config-list-entry:hover {
+    background: #f6f6f6;
+}
+
+div.tab-config-list-label {
+}
+div.tab-config-list-users {
+    position: absolute;
+    right: 3px;
+    top: 3px;
+    bottom: 3px;
+    line-height: 27px;
+    font-size: 11px;
+    background: #f6f6f6;
+    float: right;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    padding: 1px 5px;
+}
+
+i.spinner {
+    display: inline-block;
+    width: 14px;
+    height: 14px;
+    line-height: 14px;
+    vertical-align: text-top;
+    margin-top: 0px;
+    background: url(spin.svg) no-repeat 50% 50%;
+    background-size: contain
+}
+    
+    
+
diff --git a/dgbuilder/public/style.css.orig b/dgbuilder/public/style.css.orig
new file mode 100644 (file)
index 0000000..8c37abf
--- /dev/null
@@ -0,0 +1,966 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+body {
+  font: 13px "Helvetica" !important;
+  padding-top: 100px;
+  background: url("pw_maze_white.png");
+}
+
+#header {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 40px;
+    background: #000;
+    box-sizing: border-box;
+    padding: 5px 0px 5px 20px;
+}
+
+#dropTarget {
+    position: absolute;
+    top: 0; bottom: 0;
+    left: 0; right: 0;
+    background: rgba(100,100,100,0.5);
+    display:table;
+    width: 100%;
+    height: 100%;
+    display: none;
+}
+#dropTarget div {
+    display: table-cell; 
+    vertical-align: middle;
+    text-align: center;
+    font-size: 40px;
+    color: #fff;
+}
+#dropTarget div i {
+    font-size: 80px;
+}
+div.btn-group, a.btn {
+    -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+span.logo {
+    pointer-events: none;
+    float: left;
+    font-size: 30px;
+    line-height: 30px;
+    text-decoration: none;
+    color: #ccc;
+}
+span.logo span {
+    vertical-align: middle;
+    font-size: 16px !important;
+}
+span.logo img {
+    height: 18px;
+}
+#header .button {
+    line-height: 22px;
+    display: inline-block;
+    font-size: 14px;
+    padding: 4px 12px;
+    text-decoration: none;
+    border-radius: 3px;
+    color: #ccc;
+    margin: auto 10px;
+    vertical-align: middle;
+}
+#header .button:not(.disabled):hover {
+    box-shadow: 0 0 2px #fff;
+}
+#btn-deploy:not(.disabled):hover {
+    background: #ca3f39;
+}
+
+#btn-deploy {
+    color: #fff !important;
+    background: #d24741;
+    box-shadow: 0 0 2px #fff;
+}
+#btn-deploy:not(.disabled):active {
+    background: #aa1f19 !important;
+    color: #ccc !important;
+    box-shadow: 0 0 2px #999;
+}
+#btn-deploy.disabled {
+    cursor: default;
+    background: #444 ;
+    color: #999 !important;
+}
+
+#btn-sidemenu {
+    font-size: 20px !important;
+}
+#btn-sidemenu:active, #btn-sidemenu.active {
+    background: #333 ;
+}
+#header .button:focus {
+    outline: none;
+}
+
+
+
+#workspace {
+   margin-left: 160px;
+   overflow: hidden;
+}
+
+#chart {
+   overflow: auto;
+   background: #e3e3e3;
+   position: absolute;
+   bottom:0px;
+   top: 30px;
+   left:0px;
+   right:0px;
+}
+
+#workspace-toolbar {
+    display: none;
+    position: absolute;
+    top: 30px;
+    left:0;
+    right: 18px;
+    padding: 5px;
+    background: #f3f3f3;
+}
+
+#chart-zoom-controls {
+    padding-top: 3px;
+    text-align: right;
+    float: right;
+}
+
+#palette {
+   background: #f3f3f3;
+   width: 140px;
+   text-align: center;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+.palette-scroll {
+    display: none;
+    position: absolute;
+    top: 0;
+    left:0;
+    right: 0;
+    bottom: 35px;
+    padding: 5px;
+    overflow-y: auto;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+}
+.palette-spinner {
+    padding-top: 40px;
+}
+#palette-search {
+    position: absolute;
+    display: none;
+    bottom: 0;
+    left:0;
+    right:0;
+    overflow: hidden;
+    background: #f3f3f3;
+    text-align: center;
+    height: 35px;
+    padding: 3px;
+    border-top: 1px solid #999;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+}
+#palette-search i.fa-search {
+    position: absolute;
+    pointer-events: none;
+    left: 4px;
+    top: 10px;
+}
+#palette-search i.fa-times {
+    position: absolute;
+    right: 6px;
+    top: 10px;
+}
+
+#palette-search-clear {
+    display: none;
+    color: #000;
+}
+
+#palette-search input {
+    border-radius: 0;
+    border: none;
+    width: 100%;
+    box-shadow: none;
+    -webkit-box-shadow: none;
+    padding: 3px 17px;
+    margin: 0px;
+    height: 30px;
+    box-sizing:border-box;
+    -moz-box-sizing: border-box;    
+    
+}
+#palette-search input:focus {
+    border: none;
+    box-shadow: none;
+    -webkit-box-shadow: none;
+}
+
+.palette-category {
+    border: 1px solid #999;
+    border-radius: 3px;
+    margin-bottom: 5px;
+}
+.palette-content {
+    background: #fff;
+    border-top: 1px solid #aaa;
+    padding-bottom: 3px;
+}
+
+.palette-header {
+    background: #f3f3f3;
+    border-radius: 3px;
+    cursor: pointer;
+    text-align: left;
+    padding: 1px;
+}
+.palette-header i {
+    margin: 3px 4px 3px 3px;
+    -webkit-transition: all 0.2s ease-in-out;
+    -moz-transition: all 0.2s ease-in-out;
+    -o-transition: all 0.2s ease-in-out;
+    -webkit-transform: rotate(-90deg);
+    -moz-transform: rotate(-90deg);
+    -o-transform: rotate(-90deg);
+}
+.palette-header i.expanded {
+    -webkit-transform: rotate(0deg);
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+}
+.palette-header span {
+    clear: both;
+}
+.palette_label {
+   line-height: 25px;
+   text-align: center;
+
+}
+.palette_node {
+   cursor:move;
+   font-size:13px;
+   background: #ddd;
+   margin: 10px auto;
+   height: 25px;
+   border-radius: 6px;
+   border: 2px solid #999;
+   background-position: 5% 50%;
+   background-repeat: no-repeat;
+   width: 90px;
+   background-size: contain;
+   position: relative;
+}
+.palette_node:hover {
+  border-color: #ff7f0e;
+  background-color: #eee;
+}
+.palette_port {
+   position: absolute;
+   top:8px;
+   left: -5px;
+   box-sizing: border-box;
+    -moz-box-sizing: border-box;    
+   background:#d9d9d9;
+   border-radius: 3px;
+   width: 10px;
+   height: 10px;
+   border: 1px solid #999;
+}
+.palette_port_output {
+    left:85px;
+}
+
+.palette_node:hover .palette_port {
+  border-color: #999;
+  background-color: #eee;
+}
+
+#sidebar {
+    background: #fff;
+    box-sizing: border-box;
+    -moz-box-sizing: border-box;    
+}
+#sidebar.closing {
+    background: #eee;
+    border-color: #900;
+    border-style: dashed;
+}
+
+/* ---------- Layout ---------- */
+#main-container {
+    position: absolute;
+    top:50px; left:0; bottom: 0; right:0;
+    overflow:hidden;
+}
+#palette {
+    position: absolute;
+    top: 5px; left:10px; bottom: 10px;
+}
+#workspace {
+    position: absolute;
+    margin: 0;
+    top:5px; left:160px; bottom: 10px; right: 330px;
+}
+#chart-zoom-controls {
+    position: absolute;
+    bottom:30px; right: 350px;
+}
+#sidebar {
+    width: 305px;
+    position: absolute;
+    right: 10px; top: 5px; bottom:10px;
+}
+#sidebar-separator {
+    width: 15px;
+    background: url(grip.png) no-repeat 50% 50%;
+    position: absolute;
+    right: 316px; top: 5px; bottom:10px;
+    cursor: col-resize;
+}
+
+.sidebar-closed > #sidebar { display: none; }
+.sidebar-closed > #sidebar-separator { right: 0px !important; }
+.sidebar-closed > #workspace { right: 15px !important; }
+.sidebar-closed > #chart-zoom-controls { right: 35px !important; }
+
+/* ---------- end layout ---------- */
+
+.lasso {
+    stroke-width: 2px;
+    stroke: #ff7f0e;
+    fill: rgba(20,125,255,0.1);
+    stroke-dasharray: 10 5;
+}
+
+.group-box {
+    stroke-width: 1px;
+    stroke: #aaaaaa;
+    fill: rgba(208, 211, 238, 0.1);
+    stroke-dasharray: 3 3;
+}
+.group-box-active {
+    fill: #fff;
+    stroke: #ff7f0e;
+}
+
+.group_label {
+   stroke-width: 0;
+   fill: #999;
+   font-size: 11px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+.pull-right {
+    margin-left: 20px;
+}
+
+#workspace, #palette, #sidebar {
+   border: 1px solid #000;
+   border-radius: 3px;
+}
+#sidebar-content {
+    font-size: 1.2em;
+    overflow-y: auto;
+    position: absolute;
+    top: 30px; left: 0px; right: 0; bottom: 1px;
+}
+
+.node_label_italic {
+    font-style: italic;
+}
+.node_label_unknown {
+    font-style: italic;
+    fill: #e00 !important;
+}
+.node_label_white {
+  fill: #eee !important;
+}
+.node_label {
+   stroke-width: 0;
+   fill: #333;
+   font-size: 14px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+.function_label {
+   font-size: 12px;
+}
+.node {
+  stroke: #999;
+  cursor: move;
+  stroke-width: 2;
+}
+.node_unknown {
+    stroke-dasharray:10,4;
+    stroke: #f33;
+}
+.tool_arrow {
+   stroke-width: 1;
+   stroke: #999;
+   fill: #999;
+   cursor: pointer;
+}
+.node_tools {
+  fill: #ddd;
+  stroke: #999;
+  cursor: move;
+  stroke-width: 1;
+  cursor: pointer;
+}
+.node_tools_hovered {
+  stroke: #ff7f0e;
+  fill: #eee;
+}
+
+.node_button {
+    fill: inherit;
+
+}
+.port {
+   fill: #ddd;
+   cursor: crosshair;
+}
+.node_error {
+    stroke: #ff0000;
+    stroke-width: 2;
+    fill: #ff7f0e;
+}
+
+.node_badge {
+    stroke: rgb(93, 114, 145);
+    stroke-width: 1;
+    fill: rgb(190, 209, 255);
+}
+.node_badge_label {
+   stroke-width:0;
+   fill: #fff;
+   font-size: 11px;
+   pointer-events: none;
+   -webkit-touch-callout: none;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+
+}
+.node_invalid {
+   stroke: #ff0000;
+}
+.node_selected {
+   stroke: #ff7f0e;
+}
+.node_highlighted {
+   stroke: #dd1616;
+   stroke-width: 3;
+   stroke-dasharray: 10, 4;
+}
+.node_hovered {
+}
+
+.port_hovered {
+  stroke: #ff7f0e;
+  fill:  #ff7f0e;
+}
+
+.drag_line {
+  stroke: #ff7f0e;
+  stroke-width: 5;
+  fill: none;
+  pointer-events: none;
+}
+
+.drag_line_hidden {
+  stroke: #ff7f0e;
+  stroke-width: 0;
+  pointer-events: none;
+  fill: none;
+}
+
+.link_line {
+  stroke: #7f7f7f;
+  stroke-width: 4;
+  fill: none;
+  pointer-events: none;
+}
+
+.link_outline {
+  stroke: #fff;
+  stroke-width: 6;
+  cursor: crosshair;
+  fill: none;
+  pointer-events: none;
+}
+.link_background {
+  stroke: #fff;
+  opacity: 0;
+  stroke-width: 25;
+  cursor: crosshair;
+  fill: none;
+}
+
+g.link_selected path.link_line {
+  stroke: #ff7f0e;
+}
+g.link_unknown path.link_line {
+   stroke: #f00;
+   stroke-width: 2;
+   stroke-dasharray: 10, 4;
+}
+
+#shade {
+   position: absolute;
+   top:0;
+   left:0;
+   width: 100%;
+   height: 100%;
+   background: rgba(0,0,0,0.5);
+   text-align: center;
+   display: none;
+}
+
+#dialog {
+}
+
+.container {
+}
+
+.notification {
+    position: absolute;
+}
+#notifications {
+    z-index: 10000;
+    width: 500px;
+    margin-left: -250px;
+    left: 50%;
+    position: absolute;
+    top: 1px;
+}
+#notifications .alert {
+    box-shadow: 0 0 1px 1px;
+    margin-bottom: 5px;
+}
+
+.form-row {
+    clear: both;
+    margin-bottom: 7px;
+}
+.form-row label {
+    display: inline-block;
+    width: 100px;
+}
+.form-row input {
+    width:70%;
+}
+
+input.input-append-left {
+    border-top-right-radius: 0px;
+    border-bottom-right-radius: 0px;
+}
+button.input-append-right {
+    border-top-left-radius: 0px !important;
+    border-bottom-left-radius: 0px !important;
+    border-top-right-radius: 4px !important;
+    border-bottom-right-radius: 4px !important;
+    margin-left: -1px !important;
+    padding-left: 4px !important;
+    padding-right: 4px !important;
+}
+
+.form-tips {
+    background: lightgoldenrodyellow;
+    font-size: 12px;
+    padding: 8px;
+    border-radius: 5px;
+    border: 1px solid #999;
+}
+.form-tips code {
+    border: none;
+    padding: auto;
+}
+
+.ui-tabs .ui-tabs-panel {
+    padding: 0px;
+}
+
+table.node-info {
+    margin: 5px;
+    width: 97%;
+}
+table.node-info tr {
+    border: 1px solid #ddd;
+}
+table.node-info tr.blank {
+    border: none;
+}
+table.node-info tr.blank td {
+    padding-top: 8px;
+    border: none;
+    font-weight: bold;
+    padding-left: 0px;
+}
+table.node-info td:first-child{
+    color: #000;
+    vertical-align: top;
+    width: 90px;
+    padding: 3px;
+    border-right: 1px solid #ddd;
+}
+table.node-info td:last-child{
+    padding-left: 5px;
+    color: #666;
+}
+
+div.node-info {
+    margin: 5px;
+}
+
+.input-error {
+    border-color: rgb(214, 97, 95) !important;
+}
+
+.hidden {
+    display: none;
+}
+/*
+.dropdown-menu {
+    font-size: 14px;
+    background: #000;
+}
+.dropdown-menu .divider {
+    background: #666;
+    border-bottom: #666;
+}
+.dropdown-menu>li>a {
+    color: #ddd;
+}
+.dropdown-submenu>ul {
+    border: 1px solid white;
+    border-radius: 6px !important;
+}
+.dropdown-menu li.disabled  a {
+    color: #666;
+}
+.dropdown-menu li.disabled  a:hover {
+    background: none;
+}  
+*/
+.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus, .dropdown-submenu:hover>a, .dropdown-submenu:focus>a {
+    background: #999;
+}
+
+.dropdown-menu * .fa-check {
+    display: none;
+    margin-right: -15px;
+    margin-top: 3px;
+}
+.dropdown-menu * a.active > .fa-check {
+    display: inline-block;
+}
+.dropdown-menu>li.disabled>a:hover>[class^="icon-"] {
+    background-image: url("bootstrap/img/glyphicons-halflings.png") !important;
+}
+/** Fix for unreachable dropdown menu **/
+.dropdown-menu  {
+    width: 200px !important;
+}
+.dropdown-menu > li > a > i {
+    width: 10px;
+    text-align: center;
+    margin-left: -8px;
+}
+.dropdown-menu > li > a {
+     padding-left: 38px ;
+     text-indent: -8px ;
+     white-space: normal !important;
+}
+
+.popover-title { display: none; }
+
+.ui-autocomplete {
+    max-height: 250px;
+    overflow-x: hidden;
+    overflow-y: scroll;
+}
+
+.leftButton {
+    margin-right: 200px !important;
+}
+#node-help {
+    width: 700px;
+}
+#node-help * td {
+    padding: 0.8em 0.5em;
+}
+#node-help * tr > td:first-child+td+td {
+    padding-left: 5em;
+}
+
+.help-key {
+    border: 1px solid #ddd;
+    padding: 4px;
+    border-radius: 3px;
+    background: #f6f6f6;
+    font-family: Courier, monospace;
+    box-shadow: #999 1px 1px 1px;
+}
+
+#helpcontent {
+    padding: 20px;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+
+    background: #fff;
+}
+#helpnavigation {
+    overflow: hidden;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    background: #fff;
+}
+#helpnavigation li a{
+    font-size: 1.2em;
+    padding: 10px;
+    border-bottom: 1px solid #ddd;
+}
+
+#node-select-library {
+    overflow: hidden;
+}
+#node-select-library ul {
+    list-style: none;
+    padding: 0px;
+    margin: 2px;
+}
+#node-select-library li {
+    cursor: pointer;
+}
+#node-select-library li.list-selected {
+    background: #eee;
+}
+#node-select-library li.list-hover {
+    background: #ffffd0;
+}
+.node-text-editor {
+    border:1px solid #ccc;
+    border-radius:5px;
+    overflow: hidden;
+}
+#workspace-tabs {
+    margin-right: 28px;
+}
+#workspace-add-tab {
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 29px;
+    width: 28px;
+    border-bottom: 1px solid #999;
+}
+#btn-workspace-add-tab {
+    display: inline-block;
+    width: 100%;
+    background: #e3e3e3;
+    height: 100%;
+    line-height: 30px;
+    text-align: center;
+    color: #000;
+}
+#btn-workspace-add-tab:hover {
+    background: #efefef;
+}
+
+ul.red-ui-tabs {
+    list-style-type: none;
+    padding:5px 2px 0px 5px;
+    margin: 0;
+    display: block;
+    height: 24px;
+    border-bottom: 1px solid #999;
+    background: #e3e3e3;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+ul.red-ui-tabs li {
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
+    display: inline-block;
+    border-left: 1px solid  #999;
+    border-top: 1px solid   #999;
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
+    background: #e3e3e3;
+    margin: 0 5px 0 0;
+    height: 23px;
+    line-height: 17px;
+    max-width: 150px;
+    width: 14%;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+ul.red-ui-tabs li a.red-ui-tab-label {
+    display: block; 
+    padding: 3px 16px;
+    color: #666;
+}
+ul.red-ui-tabs li {
+    position: relative;
+}
+
+ul.red-ui-tabs li a.red-ui-tab-close {
+    background: rgba(227,227,227,0.8);
+    position: absolute;
+    right: 2px;
+    top: 2px;
+    display: block;
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+    text-align: center;
+    padding: 0px;
+    border-radius: 5px;
+    color: #666;
+}
+ul.red-ui-tabs li a.red-ui-tab-close:hover {
+    background: #bbb !important;
+}
+ul.red-ui-tabs li a:hover {
+    text-decoration: none;
+    background: #f0f0f0;
+}
+
+ul.red-ui-tabs li.active {
+    background: #fff;
+    border-bottom: 1px solid #fff;
+}
+ul.red-ui-tabs li.active a {
+    color: #333;
+}
+ul.red-ui-tabs li.active a.red-ui-tab-close {
+    background: rgba(255,255,255,0.8);
+}
+ul.red-ui-tabs li.active a.red-ui-tab-label:hover {
+    background: #fff;
+}
+ul.red-ui-tabs li.red-ui-add-tab {
+    width: 25px;
+    border-top-right-radius: 15px;
+    line-height: 22px;
+}
+ul.red-ui-tabs li.red-ui-add-tab a {
+    padding: 2px 4px;
+}
+
+ul.tab-config-list {
+    list-style-type: none;
+    padding: 3px;
+    margin: 0;
+   -webkit-user-select: none;
+   -khtml-user-select: none;
+   -moz-user-select: none;
+   -ms-user-select: none;
+   user-select: none;
+}
+
+ul.tab-config-list li {
+    max-width: 400px;
+    font-size: 13px;
+    background: #f3f3f3;
+    margin: 10px auto;
+    border-radius: 3px;
+    border: 1px solid #ccc;
+    padding: 3px 8px;
+}
+div.tab-config-list-type {
+}
+
+div.tab-config-list-entry {
+    position: relative;
+    margin: 4px 0;
+    padding: 8px 4px 8px 10px;
+    background: #fff;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    cursor: pointer;
+}
+div.tab-config-list-entry:hover {
+    background: #f6f6f6;
+}
+
+div.tab-config-list-label {
+}
+div.tab-config-list-users {
+    position: absolute;
+    right: 3px;
+    top: 3px;
+    bottom: 3px;
+    line-height: 27px;
+    font-size: 11px;
+    background: #f6f6f6;
+    float: right;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    padding: 1px 5px;
+}
+
+i.spinner {
+    display: inline-block;
+    width: 14px;
+    height: 14px;
+    line-height: 14px;
+    vertical-align: text-top;
+    margin-top: 0px;
+    background: url(spin.svg) no-repeat 50% 50%;
+    background-size: contain
+}
+    
+    
+
diff --git a/dgbuilder/public/util/css/validateNodeXml.css b/dgbuilder/public/util/css/validateNodeXml.css
new file mode 100644 (file)
index 0000000..895ad7f
--- /dev/null
@@ -0,0 +1,86 @@
+#error-list-div{
+overflow:scroll;
+color:brown;
+width:480px;
+height:300px;
+}
+
+#node-validate-result a{
+  text-decoration: underline;
+  color:blue;
+  cursor:pointer;
+}
+
+table#errTable tr td:first-child {
+  border-left: 0px solid #e5e5e5;
+  text-align: center;
+}
+
+table#errTable tr td:last-child {
+  border-right: 0px solid #e5e5e5;
+}
+table#errTable tr:nth-of-type(odd) {
+  background-color: #FFF0F0;
+}
+
+table#errTable  tr td {
+  border-width: 0px 0px 0px 0px;
+  border-style: solid;
+  border-color: #fff;
+  text-align: center;
+  font-size: 1.0em;
+}
+
+#sli-values-div{
+overflow:auto;
+color:blue;
+width:850px;
+height:600px;
+}
+
+#sli-values-div input[type="text"] {
+  padding: 1px;
+  border: solid 1px grey;
+  /*border: solid 1px #dcdcdc;*/
+  width:800px;
+  transition: box-shadow 0.3s, border 0.3s;
+  box-shadow: 0 0 5px 1px #969696;
+  cursor:pointer;
+}
+
+.valueBoxDiv {
+  border-width: 1px 2px 1px 1px;
+  border-style: solid;
+  /*border-color: #9999FF;*/
+  border-color: grey;
+  /*border-color: #fff;*/
+  font-size: 1.0em;
+   border-left: 1px solid #fff;
+   border-right: 1px solid #fff;
+   border-top: 1px solid #fff;
+   border-bottom: 1px solid #fff;
+ padding-left: 5px;
+  padding-right: 5px;
+  padding-top: 5px;
+  padding-bottom: 5px;
+  /*background-color:#FFE6E6;*/
+  background-color:#fff;
+}
+
+/*#sli-values-div input[type="text"]:focus,
+
+#sli-values-div input[type="text"].focus {
+  border: solid 1px #707070;
+  box-shadow: 0 0 5px 1px #969696;
+}
+*/
+/*
+#getFixed {
+  color: #c00;
+  font: bold 15px arial;
+  padding: 10px;
+  margin: 10px;
+  border: 1px solid #c00;
+  width: 200px;
+}
+*/
diff --git a/dgbuilder/public/util/js/dgeToXml.js b/dgbuilder/public/util/js/dgeToXml.js
new file mode 100644 (file)
index 0000000..7582d27
--- /dev/null
@@ -0,0 +1,1328 @@
+function getDgStartNode(nodeList){
+               for(var i=0;i<nodeList.length;i++){
+                       if(nodeList[i].type == 'dgstart' && nodeList[i].wires != null &&  nodeList[i].wires != undefined){
+                               return nodeList[i];
+                       }       
+               }
+               RED.notify("DGSTART node not found.");
+               return null;
+}
+
+
+var loopDetectionEnabled = true;
+
+function detectLoopPrev(){
+               var activeWorkspace=RED.view.getWorkspace();
+               /*
+               RED.nodes.links.filter(function(d) {
+                        if(d.source.z == activeWorkspace && d.target.z == activeWorkspace){
+                                console.log(d.source.id+":"+d.sourcePort+":"+d.target.id);
+                        }
+               });
+               */      
+               //console.dir(RED.nodes.links);
+               var nSet=[];
+               
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               nSet.push({'n':n});
+                       }
+               });
+
+               var nodeSet = RED.nodes.createExportableNodeSet(nSet);
+               //console.dir(nodeSet);
+               
+               //console.log("nodeSet length:" + nodeSet.length);
+
+               var isLoopDetected = false;     
+               var dgStartNode = getDgStartNode(nodeSet);
+               if(dgStartNode == null || dgStartNode == undefined) {
+                       console.log("dgstart node not linked.");
+                       return true;
+               }
+
+               var wires = dgStartNode.wires;
+               var nodesInPath = {};
+               var dgStartNodeId = dgStartNode.id;
+               if(wires != null && wires != undefined && wires[0] != undefined){
+                       for(var k=0;k<wires[0].length;k++){
+                               var val = wires[0][k];
+                               nodesInPath[dgStartNodeId + "->" + val] = "";
+                       }
+               }else{
+                               nodesInPath[dgStartNodeId + "->" + ""] = "";
+               }
+                       
+               //console.dir(nodesInPath);
+               var loopDetectedObj = {};
+               /* the nodes will not be order so will need to loop thru again */
+       for(var m=0;nodeSet != null && m<nodeSet.length;m++){
+               for(var i=0;nodeSet != null && i<nodeSet.length;i++){
+                       var link=nodeSet[i].id;
+                       //console.log("NAME:" + nodeSet[i].name + ":" + link);
+                       if(link == dgStartNodeId) continue;
+                       var wires = nodeSet[i].wires;
+                       //console.log("link:" + link);
+                       var delKeys = [];
+                       if(wires != null && wires != undefined && wires[0] != undefined){
+                               for(var k=0;k<wires[0].length;k++){
+                                       var val = (wires[0])[k];
+                                       var keys = Object.keys(nodesInPath);
+                                       //console.log("keys:" + keys);
+                                       for (var j=0;j<keys.length;j++){
+                                               //console.log("key:" + keys[j]);
+                                               //console.log("val:" + val);
+                                               var index = -1;
+                                               if(keys[j] != null){
+                                                       index = keys[j].indexOf("->" + link);
+                                               }
+                                               var lastIndex = keys[j].lastIndexOf("->");
+                                               if(index != -1 && index == lastIndex){
+                                                       //delete nodesInPath[key];
+                                                       var previousNodeId = keys[j].substr(lastIndex +2);
+                                                       var indexOfArrow = -1;
+                                                       if(previousNodeId != ""){
+                                                               indexOfArrow = previousNodeId.indexOf("->");
+                                                       }
+                                                       if(previousNodeId != null && indexOfArrow != -1){
+                                                               previousNodeId = previousNodeId.substr(0,indexOfArrow);
+                                                       }       
+                                                       nodesInPath[keys[j] + "->" + val] = "";
+                                                       //console.log("keys[j]:" + keys[j]);
+                                                       delKeys.push(keys[j]);
+                                                       var prevNodeIdIndex = keys[j].indexOf("->" + previousNodeId);
+                                                       var priorOccurence = keys[j].indexOf(val + "->");
+                                                       if(priorOccurence != -1 && priorOccurence<prevNodeIdIndex){
+                                                               //console.log("previousNodeId:" + previousNodeId);
+                                                               //console.log("val:" + val);
+                                                               var n1 = getNode(nodeSet,previousNodeId);
+                                                               var n2 = getNode(nodeSet,val);
+                                                               //console.log("loop detected for node " + n1.name + " and " + n2.name); 
+                                                               loopDetectedObj[n1.name + "->" + n2.name] ="looped";
+                                                               //console.dir(loopDetectedObj);
+                                                               isLoopDetected = true;
+                                                       }               
+                                               } 
+                                       }
+                               }
+                       }
+                       for(var l=0;delKeys != null && l<delKeys.length;l++){
+                               delete nodesInPath[delKeys[l]];
+                       }
+               }
+
+
+       }       
+       if(loopDetectedObj != null ){ 
+               var msg = "";
+               for(var key in loopDetectedObj){
+                       if(loopDetectedObj.hasOwnProperty(key)) {
+                               console.log("Loop detected  " + key);
+                               msg += "<strong>Loop detected for:" + key + "</strong><br>";
+                       }
+               }
+               if(msg != ""){
+                       isLoopDetected = true;
+                       RED.notify(msg);
+               }
+       }       
+/*
+               for(var i=0;nodeSet != null && i<nodeSet.length;i++){
+                       var foundCount=0;
+                       var nodeId = nodeSet[i].id;
+                       var nodeName = nodeSet[i].name;
+                       for(var j=0;nodeSet != null && j<nodeSet.length;j++){
+                               var node = nodeSet[j];
+                               if(node.id == nodeId){
+                                        continue;
+                               }
+                               var wires = node.wires;
+                               console.log(node.type + ":wires:" + wires);
+                               for(var k=0;wires != null && wires != undefined && wires[0] != undefined && k<wires[0].length;k++){
+                                       var id = (wires[0])[k];
+                                       console.log(nodeName + ":" + nodeId + ":" + id);
+                                       if(id == nodeId ){
+                                               foundCount++;
+                                               if(foundCount>1){
+                                                       console.log("Loop detected for node " + nodeName + "with node:" + node.name);
+                                                       RED.notify("<strong>Flow error detected for node '" + nodeName + "' with node '" + node.name + "'</strong>");
+                                                       //RED.nodes.eachLink(function(d){
+                                                       //      if(d.source.id == nodeSet[i] || d.target.id == nodeSet[j]){
+                                                       //              d.selected = true;
+                                                       //      }else if(d.source.id == nodeSet[j] || d.target.id == nodeSet[i]){
+                                                       //              d.selected = true;
+                                                       //      }
+                                                       //});
+                                                       //RED.view.redraw();
+                                                       isLoopDetected = true;
+                                                       return true;
+                                               }
+                                       }
+                               }
+                               
+                       }
+               }
+*/
+               //console.log("isLoopDetected:" + isLoopDetected);
+               return isLoopDetected;
+}
+
+function generateNodePath(nodeIdToNodeObj,nodeId,pathStr,nodesInPath,errList){
+               var node = nodeIdToNodeObj[nodeId];
+               var wires = node.wires;
+               if(wires != null && wires != undefined && wires[0] != undefined){
+                       for(var k=0;k<wires[0].length;k++){
+                               var val = wires[0][k];
+                               if(pathStr.indexOf(val + "->") != -1){
+                                       //console.log("pathStr:" + pathStr);
+                                       var n1= nodeIdToNodeObj[nodeId].name;
+                                       var n2= nodeIdToNodeObj[val].name;
+                                       errList.push("Loop detected between nodes '" +  n1 + "' and " + "'" +  n2 + "'");
+                               }else{
+                                       pathStr += "->" + val ;
+                                       generateNodePath(nodeIdToNodeObj,val,pathStr,nodesInPath,errList);
+                               }
+                       }
+               }else{
+                               //pathStr += nodeId + "->" + "";
+                               nodesInPath.push(pathStr);
+               }
+}
+
+function detectLoop(){
+               var activeWorkspace=RED.view.getWorkspace();
+               var nSet=[];
+               var nodeIdToNodeObj = {};       
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               nSet.push({'n':n});
+                       }
+               });
+
+               var nodeSet = RED.nodes.createExportableNodeSet(nSet);
+               nodeIdToNodeObj = getNodeIdToNodeMap(nodeSet);
+               var isLoopDetected = false;     
+               //var dgStartNode = getDgStartNode(nodeSet);
+               var dgStartNode = nodeIdToNodeObj["dgstart"];
+               var errList = [];
+               var dgStartNodeId = dgStartNode.id;
+               var nodesInPathArr = [];
+               generateNodePath(nodeIdToNodeObj,dgStartNodeId,dgStartNodeId,nodesInPathArr,errList);
+               if(errList != null && errList != undefined && errList.length  > 0){
+                       isLoopDetected = true;
+                       var htmlStr="<div id='loop-detect-err-list-div'><table id='loopErrListTable' border='1'><tr><th>Error List</th></tr>";  
+                       for(var j=0;errList != null && j<errList.length;j++){
+                               var errSeq = j+1;
+                               htmlStr += "<tr><td>" + errSeq + ")"  + errList[j] + "</td></tr>"; 
+                       }
+                       htmlStr += "</table></div>";
+
+                       $("#loop-detection-dialog").dialog({
+                             autoOpen : false,
+                              modal: true,
+                              title: "DG Flow validation Error List ",
+                              width: 500,
+                              buttons: {
+                                Close: function () {
+                                  $("#loop-detection-dialog").dialog("close");
+                                }
+                              }
+                         }).dialog("open").html(htmlStr); // end dialog div
+               }
+               nodesInPathArr=null;
+               nodeSet ={};
+               nodeIdToNodeObj={};
+               return isLoopDetected;
+}
+
+
+var xmlNumberCnt = 0;
+function processForXmlNumbers(nodeSet,node){
+       if( node != null && node.type != 'dgstart'){
+               if(node.xmlnumber != null && node.xmlnumber){
+                       node.xmlnumber.push(++xmlNumberCnt);
+               }else{
+                       node.xmlnumber =  [++xmlNumberCnt];
+               }
+       }
+
+       if(node != null && node.wires != null && node.wires.length>0){
+               var wiredNodes=node.wires[0];
+               var wiredNodesArr=[];
+               for(var k=0;wiredNodes != undefined && wiredNodes != null && k<wiredNodes.length;k++){
+                       wiredNodesArr.push(getNode(nodeSet,wiredNodes[k]));
+               }
+
+               //use this sort to sort by y position
+               wiredNodesArr.sort(function(a, b){
+                       return a.y-b.y;
+               });
+
+               for(var k=0;k<wiredNodesArr.length;k++){
+                       var n = wiredNodesArr[k];
+                       processForXmlNumbers(nodeSet,n);
+               }
+       }
+}
+
+function updateXmlNumbers(){
+       xmlNumberCnt = 0;
+       var nodeSet = getCurrentFlowNodeSet();
+       if(nodeSet == null && nodeSet.length >0){
+               nodeSet.forEach(function(n){
+                       if(n.xmlnumber){
+                               delete n.xmlnumber;
+                       }
+               });
+       }
+       var dgStartNode = getDgStartNode(nodeSet);
+       processForXmlNumbers(nodeSet,dgStartNode);
+       var activeWorkspace=RED.view.getWorkspace();
+       RED.nodes.eachNode(function(n) {
+               //console.log("Node processed in eachNode");
+            if (n.z == activeWorkspace) {
+               if(n != null){
+                       var updatedNode = getNode(nodeSet,n.id);
+                       //console.log("updated Node processed in eachNode");
+                       //console.dir(updatedNode);
+                       
+                        if (n.id == updatedNode.id) {
+                               n.xmlnumber = updatedNode.xmlnumber;
+                               n.dirty = true;
+                        }
+               }
+           }   
+        });
+}
+
+function getOutcomeValue(node){
+       var xmlStr = "";
+       if(node != null && node.xml != undefined && node.xml !=""){
+               xmlStr = node.xml + "</outcome>";
+       }
+       var xmlDoc;
+               if (window.DOMParser){
+               try{
+                               var parser=new DOMParser();
+                       xmlDoc=parser.parseFromString(xmlStr,'text/xml');
+                       //console.log("Not IE");
+                       var n = xmlDoc.documentElement.nodeName;
+                       if(n == "html"){
+                               resp=false;
+                               console.log("Error parsing");
+                               return resp;
+                       }
+               }catch(e){
+                       console.log("xmlStr:" + xmlStr);
+                       console.log("Error parsing" +e);
+                       return null;
+               }
+        }else{ 
+               try{
+                       //console.log("IE");
+                       // code for IE
+                       xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
+                       xmlDoc.async=false;
+                       xmlDoc.loadXMLString(xmlStr); 
+               }catch(e){
+                       console.log("xmlStr:" + xmlStr);
+                       console.log("Error parsing" +e);
+                       return null;
+               }
+        } 
+       if(xmlDoc != null){
+               var xmlNode = xmlDoc.documentElement;
+               //console.dir(xmlNode);
+               var processedNode = xmlNode.nodeName;
+               //console.log("processedNode:" + processedNode);
+               var attrs = xmlNode.attributes;
+               for(var i=0;i<attrs.length;i++){
+                       if(attrs[i].nodeName == "value"){
+                               return  attrs[i].value;
+                       }
+               }
+       }
+       return null;
+}
+
+var dgNumberCnt = 0;
+function processForDgNumbers(nodeSet,node){
+               var outcomeTypes = [ "already-active", "failure", "not-found", "other", "outcomeFalse", "outcome", "outcomeTrue", "success" ];
+       if( node != null && node.type != 'dgstart' && node.type != 'service-logic' && node.type != 'method' ){
+               //console.log("child of " + parentNodeType + " :" + nodeType);
+               //check if NOT outcome node
+               if(outcomeTypes.indexOf(node.type) == -1){
+                       if(node.type == "GenericXML"){
+                               if(node.xml != undefined && node.xml !=  null && node.xml.indexOf("<outcome ") != -1){
+                                       //this GenericXML node is used for outcome , so need to skip
+                               }else{
+                                       if(node.dgnumber != undefined && node.dgnumber != null && node.dgnumber){
+                                               node.dgnumber.push(++dgNumberCnt);
+                                       }else{
+                                               node.dgnumber =  [++dgNumberCnt];
+                                       }
+                               }
+                       
+                       }else{
+                               if(node.dgnumber != undefined && node.dgnumber != null && node.dgnumber){
+                                       node.dgnumber.push(++dgNumberCnt);
+                               }else{
+                                       node.dgnumber =  [++dgNumberCnt];
+                               }
+                       }
+               }
+       }
+       
+       var hasOutcomeNodes = false;
+       if(node != null && node.wires != null && node.wires.length>0){
+               var wiredNodes=node.wires[0];
+               var wiredNodesArr=[];
+               for(var k=0;wiredNodes != undefined && wiredNodes != null && k<wiredNodes.length;k++){
+                       var wiredNode = getNode(nodeSet,wiredNodes[k]);
+                       //check if outcome node
+                       if(outcomeTypes.indexOf(wiredNode.type) != -1){
+                               hasOutcomeNodes = true;
+                       }
+                       if(wiredNode.type == "GenericXML"){
+                               if( node.xml != undefined && node.xml != null && node.xml.indexOf("<outcome ") != -1){
+                                       //this GenericXML node is used for outcome 
+                                       hasOutcomeNodes = true;
+                               }
+                       }
+                       wiredNodesArr.push(wiredNode);
+
+               }
+
+               //use this sort to sort by y position
+               wiredNodesArr.sort(function(a, b){
+                       return a.y-b.y;
+               });
+
+               /*
+               //USE THIS LOGIC TO SORT BY OUTCOME VALUE FOR SPECIFIC NODES            
+               var parentNodeType = node.type;
+               if(hasOutcomeNodes && parentNodeType != 'switchNode' && parentNodeType != 'block'  && parentNodeType != 'configure' ){  
+                       //use the value of outcome to sort the wired nodes
+                       wiredNodesArr.sort(function(a, b){
+                               var val1 = getOutcomeValue(a);
+                               var val2 = getOutcomeValue(b);
+                               //console.log("val1:" + val1);
+                               //console.log("val2:" + val2);
+                               if ( val1 < val2 ){
+                                       return -1;
+                               }else if ( val1 > val2 ){
+                                       return 1;
+                               }else{
+                                       return 0;
+                               }
+                       });
+               }else{
+                       //use this sort to sort by y position
+                       wiredNodesArr.sort(function(a, b){
+                               return a.y-b.y;
+                       });
+               }
+
+               */
+
+               for(var k=0;k<wiredNodesArr.length;k++){
+                       var n = wiredNodesArr[k];
+                       processForDgNumbers(nodeSet,n);
+               }
+       }
+}
+
+function updateDgNumbers(){
+       dgNumberCnt = 0;
+       var nodeSet = getCurrentFlowNodeSet();
+       if(nodeSet == null && nodeSet.length >0){
+               nodeSet.forEach(function(n){
+                       if(n.dgnumber){
+                               delete n.dgnumber;
+                       }
+               });
+       }
+       var dgStartNode = getDgStartNode(nodeSet);
+       processForDgNumbers(nodeSet,dgStartNode);
+       var activeWorkspace=RED.view.getWorkspace();
+       RED.nodes.eachNode(function(n) {
+               //console.log("Node processed in eachNode");
+            if (n.z == activeWorkspace) {
+               if(n != null){
+                       var updatedNode = getNode(nodeSet,n.id);
+                       //console.log("updated Node processed in eachNode");
+                       //console.dir(updatedNode);
+                       
+                        if (n.id == updatedNode.id) {
+                               //console.log(n.type + ":" + updatedNode.dgnumber);
+                               n.dgnumber = updatedNode.dgnumber;
+                               n.dirty = true;
+                        }
+               }
+           }   
+        });
+       return nodeSet; 
+}
+
+function customValidation(currNodeSet){
+       //validation to make sure there a block node infront of mutiple dgelogic nodes
+       flowDesignErrors=[];
+       var dgStartCnt=0;
+       var serviceLogicCnt=0;
+       var methodCnt=0;
+       for(var i=0;currNodeSet != null && i<currNodeSet.length;i++){
+               var node = currNodeSet[i];
+               var parentNodeName = node.name;
+               var parentNodeType = node.type;
+               var dgNumber = node.dgnumber;
+               if(parentNodeType == 'dgstart'){
+                       dgStartCnt++;   
+               }
+               if(parentNodeType == 'service-logic'){
+                       serviceLogicCnt++;      
+               }
+               if(parentNodeType == 'method'){
+                       methodCnt++;    
+               }
+               if(parentNodeType == "GenericXML"){
+                       if( node.xml != undefined && node.xml != null && node.xml.indexOf("<service-logic ") != -1 ){
+                               //this GenericXML node is used for service-logic 
+                               serviceLogicCnt++;
+                       }else if( node.xml != undefined && node.xml != null &&  node.xml.indexOf("<method ") != -1 ){
+                               //this GenericXML node is used for method
+                               methodCnt++;
+                       }else if( node.xml != undefined && node.xml != null &&  node.xml.indexOf("<block") != -1 ){
+                               //this GenericXML node is used for block
+                               parentNodeType = "block";
+                       }
+               }
+               if(node != null && node.wires != null && node.wires.length>0){
+                       var wiredNodes=node.wires[0];
+                       var wiredNodesArr=[];
+                       for(var k=0;wiredNodes != undefined && wiredNodes != null && k<wiredNodes.length;k++){
+                               wiredNodesArr.push(getNode(currNodeSet,wiredNodes[k]));
+                       }
+                       var countChildLogicNodes =0;
+                       for(var k=0;k<wiredNodesArr.length;k++){
+                               var n = wiredNodesArr[k];
+                               var nodeType = n.type;
+                               var outcomeTypes = [ "already-active", "failure", "not-found", "other", "outcomeFalse", "outcome", "outcomeTrue", "success" ];
+                               var isOutcomeOrSetNode = false;
+                               if(nodeType == "GenericXML"){
+                                       if( n.xml != undefined &&  n.xml != null &&  (n.xml.indexOf("<outcome ") != -1 || n.xml.indexOf("<set ") != -1)){
+                                               //this GenericXML node is used for outcome 
+                                               isOutcomeOrSetNode = true;
+                                       }
+                               }
+                               //console.log("child of " + parentNodeType + " :" + nodeType);
+                               if(outcomeTypes.indexOf(nodeType) > -1 ||nodeType == 'set' || isOutcomeOrSetNode){
+                                       //its a outcome or set node
+                               }else{
+                                       countChildLogicNodes++;
+                               }
+
+                               //console.log("parentNodeType:" + parentNodeType);
+                               if(countChildLogicNodes >1 && parentNodeType != 'block' && parentNodeType != 'for' ){
+                                       if(node.dgnumber != undefined &&  node.dgnumber){
+                                               flowDesignErrors.push("Warning:May need a block Node after Node. <br><span style='color:red'>Node Name:</span>" + node.name + "<br><span style='color:red'>DG Number:</span>" + node.dgnumber[0] );
+                                       }else{
+                                               flowDesignErrors.push("Warning:May need a block Node after Node <br><span style='color:red'>Node name:</span>" + parentNodeName);
+                                       }
+                                       break;
+                               }
+                       }
+               }
+       }
+       if(dgStartCnt > 1){
+               flowDesignErrors.push("Error:There should  only be 1 dgstart Node in the current workspace.");
+       }
+
+       if(serviceLogicCnt > 1){
+               flowDesignErrors.push("Error:There should  only be 1 service-logic Node in the current workspace.");
+       }
+
+       if(methodCnt > 1){
+               flowDesignErrors.push("Error:There should  only be 1 method Node in the current workspace.");
+       }
+
+       if(flowDesignErrors != null && flowDesignErrors.length >0){
+               return false;
+       }
+       return true;
+}
+
+var flowDesignErrors = [];
+function showFlowDesignErrorBox(){
+       if(flowDesignErrors != null && flowDesignErrors.length >0){
+               var htmlStr="<div id='flowpath-err-list-div'><table id='fpeTable' border='1'><tr><th>Error List</th></tr>";     
+               for(var j=0;flowDesignErrors != null && j<flowDesignErrors.length;j++){
+                       var errSeq = j+1;
+                       htmlStr += "<tr><td>" + errSeq + ")"  + flowDesignErrors[j] + "</td></tr>"; 
+               }
+               htmlStr += "</table></div>";
+
+               //$('<div></div>').dialog({
+
+               $('#flow-design-err-dialog').dialog({
+                              modal: true,
+                              title: "Flow design Error List ",
+                              width: 500,
+                              /*open: function () {
+                                $(this).html(htmlStr);
+                              },*/
+                              buttons: {
+                                Close: function () {
+                                  $(this).dialog("close");
+                                }
+                              }
+                            }).html(htmlStr); // end dialog div
+       }
+}
+
+
+function getCurrentFlowNodeSet(){
+               var nodeSet=[];
+               //console.dir(RED);
+               //RED.view.dirty();
+               //RED.view.redraw();
+               var activeWorkspace=RED.view.getWorkspace();
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               nodeSet.push({'n':n});
+                       }
+               });
+
+               var exportableNodeSet = RED.nodes.createExportableNodeSet(nodeSet);
+               //console.dir(exportableNodeSet);
+               //console.log(JSON.stringify(exportableNodeSet));
+               return exportableNodeSet;
+}
+
+function getNode(nodeSet,id){
+               for(var i=0;i<nodeSet.length;i++){
+                       if(nodeSet[i].id == id){
+                               return nodeSet[i];
+                       }       
+               }
+               return null;
+}
+function getNodeIdToNodeMap(nodeSet){
+               var nodeIdToNodeMap ={};        
+               for(var i=0;i<nodeSet.length;i++){
+                               nodeIdToNodeMap[nodeSet[i].id] = nodeSet[i];
+                               if(nodeSet[i].type == "dgstart"){
+                                       nodeIdToNodeMap["dgstart"] =  nodeSet[i];
+                               }
+               }
+               return nodeIdToNodeMap;
+}
+
+function validateEachNodeXml(){
+               var activeWorkspace=RED.view.getWorkspace();
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               var xml = n.xml;        
+                               if( xml != null && xml != ''){
+                                 var validationSuccess = validateXML(n.xml);
+                                       if(validationSuccess){
+                                               n.status = {fill:"green",shape:"dot",text:"OK"};
+                                       }else{
+                                               n.status = {fill:"red",shape:"dot",text:"ERROR"};
+                                       }
+                               }
+                       }
+               });
+}
+
+
+function getNodeToXml(inputNodeSet){
+               var exportableNodeSet; 
+       //uses inputNodeSet if passed otherwise build the latest nodeSet
+       
+       //$("#btn-deploy").removeClass("disabled");
+
+
+               function getNode(id){
+                       for(var i=0;i<exportableNodeSet.length;i++){
+                               if(exportableNodeSet[i].id == id){
+                                       return exportableNodeSet[i];
+                               }       
+                       }
+                       return null;
+               }
+
+               function getStartTag(node){
+                       var startTag="";
+                       var xmlStr="";
+                       if(node != null && node.type != 'dgstart'){
+                               xmlStr=node.xml;
+                               var regex = /(<)([\w-]+)(.*)?/;
+                               var match = regex.exec(xmlStr);
+                               if(match != null){
+                                       if(match[1] != undefined && match[2] != undefined){
+                                               startTag = match[2];
+                                       }
+                               }else{
+                                       console.log("startTag not found.");
+                               }       
+                       }
+                       return startTag;
+               }
+
+               if(inputNodeSet == null || inputNodeSet == undefined){  
+                       exportableNodeSet = getCurrentFlowNodeSet();
+               }else{
+                       exportableNodeSet = JSON.parse(inputNodeSet);
+               }
+               var dgstartNode = getDgStartNode(exportableNodeSet);
+
+               var level=0;
+               var fullXmlStr="";
+
+               printXml(dgstartNode);
+               
+
+               function printXml(node){
+                       var xmlStr="";
+                       var startTag = "";
+                       if(node != null && node.type != 'dgstart'){
+                               var comments=node.comments;
+                               if(comments != null && comments != ""){
+                                       //if xml comments field already has the <!-- and --> remove them 
+                                       comments=comments.replace("<!--","");
+                                       comments=comments.replace("-->","");
+                                       xmlStr="<!--" + comments + "-->";
+                               }       
+                               xmlStr+=node.xml;
+                               startTag = getStartTag(node);
+                               fullXmlStr +=xmlStr;
+                               /*
+                               if(level > 0){
+                                       var spacing = Array(level).join("  ");  
+                                       xmlStr=xmlStr.replace(/\n/g,spacing);
+                                       fullXmlStr +=xmlStr;
+                                       
+                                       console.log(xmlStr);
+                               }else{
+                                       fullXmlStr +=xmlStr;
+                                       console.log(xmlStr);
+                               }
+                               */
+                       }
+
+                       //console.log("startTag:" + startTag);
+       
+                       var wiredNodes = [];
+                       var wiredNodesArr = [];
+                       if(node != null && node.wires != null && node.wires[0] != null &&  node.wires[0] != undefined && node.wires[0].length >0 ){
+                               wiredNodes=node.wires[0];
+                               //console.log("Before sort");
+                               for(var k=0;wiredNodes != undefined && wiredNodes != null && k<wiredNodes.length;k++){
+                                       wiredNodesArr.push(getNode(wiredNodes[k]));
+                               }
+                               //console.dir(wiredNodesArr);
+                               //sort based on y position
+                               wiredNodesArr.sort(function(a, b){
+                                       return a.y-b.y;
+                               });
+                               //console.log("After sort");
+                               //console.dir(wiredNodesArr);
+                       }
+
+                       for(var k=0;wiredNodesArr != null && k<wiredNodesArr.length;k++){
+                               level++;
+                               var nd = wiredNodesArr[k];
+                               printXml(nd);
+                       }
+
+                       //append end tag
+                       if(startTag != ""){
+                               fullXmlStr += "</" + startTag + ">";
+                               /*
+                               if(level >0){
+                                       var spacing = Array(level).join("  ");  
+                                       fullXmlStr += spacing + "</" + startTag + ">";
+                                       console.log(spacing + "</" + startTag + ">");
+                               }else{
+                                       fullXmlStr += "</" + startTag + ">";
+                                       console.log("</" + startTag + ">");
+                               }
+                               */
+                       }       
+
+                       /*if(level>0){
+                               level=level-1;
+                       }
+                       */
+                       //console.log("endTag:" + startTag);
+                       //console.log("xml:" + fullXmlStr);
+               }
+               //console.log("fullXmlStr:" + fullXmlStr);
+       return fullXmlStr;
+}
+
+function showFlow(filePath){
+var jqxhr = $.post( "/getSharedFlow",{"filePath":filePath})
+  .done(function(data) {
+       $( "#dgflow-browser-dialog").dialog("close");
+       var migratedNodes = migrateNodes(data);
+       //RED.view.importNodes(data)
+       RED.view.importNodes(JSON.stringify(migratedNodes));
+    //console.log( "import done");
+  })
+  .fail(function() {
+       RED.notify("Could not import user flow .");     
+       $( "#dgflow-browser-dialog").dialog("close");
+     console.log( "error occured importing flow.");
+  })
+  .always(function() {
+    //console.log( "complete" );
+  });
+}
+
+function showFlowXml(filePath){
+var jqxhr = $.post( "/getSharedFlow",{"filePath":filePath})
+  .done(function(data) {
+       //console.dir(data);
+       var xmlStr=getNodeToXml(data);
+       showImportedXml(xmlStr,this);
+  })
+  .fail(function() {
+       RED.notify("Could not convert to XML.");        
+       $( "#dgflow-browser-dialog").dialog("close");
+     console.log( "error occured importing flow.");
+  })
+  .always(function() {
+    //console.log( "complete" );
+  });
+}
+
+function showFlowFiles(userName){
+               //var divStyle="color:#07c; margin-bottom: 1.2em; font-size: 16px;";
+               //var divStyle="<style>#data-container a { color: #067ab4; font-size: 0.75em;} #data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } </style>";
+               var divStyle="<style>#data-container a { color: #067ab4; font-size: 0.75em;} #data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+
+               var htmlStr=divStyle + "<div class='header'>List of Flow files of User " + userName + "</div><div id='data-container'><ul>" ;
+                $.post( "/getFiles/" + userName)
+                         .done(function( data ) {
+                                //console.dir(data);
+                               //console.log("found " + data.length + " files");
+                               if(data != null && data.length != undefined && data.length != 0){
+                                       if(data != null && data.length>0){
+                                               for(var k=0;k<data.length;k++){
+                                                       htmlStr += "<li><a href=\"#\" onclick=\"showFlow('" +data[k].filePath + "')\">" + data[k].name + "</a></li>";
+                                               /*
+                                                       //Use this code to display the View Xml Link 
+                                                       htmlStr += "<li><a href=\"#\" onclick=\"showFlow('" +data[k].filePath + "')\">" + data[k].name + "</a><span style=\"margin-left:15px;color:blue\"><a href=\#\" onclick=\"showFlowXml('" +data[k].filePath + "')\">[View Xml]</a></span></li>";
+                       */
+                                               }
+                                               htmlStr+="</ul></div>";
+                                       }
+                                       $( "#dgflow-browser-dialog").html(htmlStr);
+                               }else{
+                                       //console.log("no flow files found for user " + userName);
+                                       var noFlowFilesHtml = divStyle + "<div id='data-container'><p>No downloaded Flow files found in " + userName + " directory</p><a href='#' onclick='javascript:closeAndShowFlowShareUsers()'>Back to List.</a></div>";
+                                       $( "#dgflow-browser-dialog").html(noFlowFilesHtml);
+                               }
+                         })
+                         .fail(function(err) {
+                                 console.log( "error" + err );
+                         })
+                         .always(function() {
+                               //console.log("done");
+                         });
+       
+}
+
+       function  closeAndShowFlowShareUsers(){
+                $("#dgflow-browser-dialog").dialog( "close" );
+               var divStyle="<style>#data-container a { color: #067ab4; font-size: 0.75em;} #data-container a:hover { text-decoration: underline; padding: -15px -15px -15px 15px; } .header { height: 40px; border-bottom: 1px solid #EEE; background-color: #ffffff; height: 40px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; } .footer { height: 40px; background-color: whiteSmoke; border-top: 1px solid #DDD; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }</style>";
+               $.get( "/flowShareUsers")
+                               .done(function( data ) {
+                                       
+                                       var header="<div class='header'>List of downloaded DG Flows </div>";
+                                       var html=  divStyle + header +  "<div id='data-container'>";
+                                       html+="<ul>";
+                                       if(data != null){
+                                               var users=data.flowShareUsers;
+                                               users.sort(function (a,b){
+                                                        if(a.name > b.name){
+                                                                return 1;
+                                                        }else if(a.name <  b.name){
+                                                                return -1;
+                                                        }else{
+                                                                return 0;
+                                                        }
+                                                });
+                                               for(var i=0;users != null && i<users.length;i++){
+                                                       html+="<li><a href=\"#\" onclick=\"showFlowFiles('" + users[i].rootDir + "')\">" + users[i].name + "</a></li>";
+                                               }
+                                       }
+                                       html+="</ul>";
+                                       html+="</div>";
+                                       $( "#dgflow-browser-dialog" ).dialog({
+                                       title: "Dowloaded DG Flow Browser",
+                                       modal: true,
+                                       autoOpen: true,
+                                       width: 530,
+                                       height: 530,
+                                       buttons: [
+                                               {
+                                                       text: "Close",
+                                                       click: function() {
+                                                               $( this ).dialog( "close" );
+                                                       }
+                                               }
+                                               ]
+                                       }).html(html);
+                                       $("#dgflow-browser-dialog").show();
+                               })
+                                .fail(function(err) {
+                                         RED.notify("Failed to get users.");
+                                })
+                                 .always(function() {
+                               });
+       }
+
+function showImportedXml(xmlStr,dialogBox){
+       var formattedXml=vkbeautify.xml(xmlStr);
+       var that = dialogBox;
+                require(["orion/editor/edit"], function(edit) {
+                that.editor = edit({
+                    parent:document.getElementById('dgflow-browser-dialog'),
+                    lang:"html",
+                    readonly:true,
+                    contents: formattedXml
+                });
+                RED.library.create({
+                    url:"functions", // where to get the data from
+                    type:"function", // the type of object the library is for
+                    editor:that.editor, // the field name the main text body goes to
+                    fields:['name','outputs']
+                });
+                });
+}
+
+function getTag(xmlStr){
+        var tag= null ;
+       if(xmlStr != null){
+               xmlStr = xmlStr.trim();
+       }
+        try{
+                var regex = new RegExp("(<)([^ >]+)");
+                var match = regex.exec(xmlStr);
+                if(match != null){
+                        if(match[1] != undefined && match[2] != undefined){
+                                tag = match[2];
+                        }
+                }
+        }catch(e){
+                console.log(e);
+        }
+       return tag;
+
+}
+
+function getAttributeValue(xmlStr,attribute){
+
+       var attrVal=null;
+       try{
+               var myRe = new RegExp(attribute + "[\s+]?=[\s+]?['\"]([^'\"]+)['\"]","m");
+               var myArray = myRe.exec(xmlStr);
+               if(myArray != null && myArray[1] != null){
+                       attrVal=myArray[1];
+               }
+       }catch(err){
+               console.log(err);
+       }
+       return attrVal;
+}
+
+function showOrHideTab(checkbox,idVal){
+
+       var activeWorkspace=RED.view.getWorkspace();
+       var table = $("#ftab02");
+       $('td input:checkbox',table).each(function(i){
+               console.log(this.checked);
+       });
+       //console.dir($('td input:checkbox',table).prop('checked',this.checked));
+
+        $(".red-ui-tabs li a").each(function(i){
+               var id=$(this).attr("href").replace('#','');
+               if(id == idVal){
+                       $(this).parent().toggle();
+                       var isVisible = $(this).parent().is(":visible"); 
+                       if(isVisible){
+                               checkbox.checked = true;
+                       }else{
+                               checkbox.checked = false;
+                       }
+                       if(activeWorkspace == id){
+                               //$("#chart").hide();
+                               //var li = ul.find("a[href='#"+id+"']").parent();
+                               var li = $(this).parent();
+                               if (li.hasClass("active")) {
+                                       li.removeClass("active");
+                                       if(li.parent().children().size() != 0){
+                                       }
+                                       console.log("has Class active");
+                                       var tab = li.prev();
+                                       if (tab.size() === 0) {
+                                               console.log("li prev size 0");
+                                               tab = li.next();
+                                       }
+                                       if(tab.is(":visible")){
+                                               console.log("added active");
+                                               tab.addClass("active");
+                                               tab.click();
+                                               //tab.trigger("click");
+                                       }
+                                       //console.dir(tab);
+                                       //tab.parent().addClass("active");
+                                       //tab.click();
+                               }
+                       }else{
+                                               console.log("added active id" +id);
+                                               if(isVisible){
+                                                       var li = $(this).parent();
+                                                       li.addClass("active");
+                                                       li.click();
+                                                       //console.dir(li);
+                                               }else{
+                                                       var li = $(this).parent();
+                                                       li.removeClass("active");
+                                               }
+                       }
+               }
+       });
+/*
+        $(".red-ui-tabs li a").each(function(i){
+               var id=$(this).attr("href").replace('#','');
+               if(id != idVal){
+                       $(this).trigger("click");
+                       if(activeWorkspace == idVal){
+                               $("#chart").show();
+                       }
+                       return false;
+               }
+       });
+*/
+}
+
+function performGitCheckout(){
+       $("#responseId").text("");
+        if(!event) event = window.event;
+         var target = $(event.target);
+         target.val("Processing");
+         target.css({ "background-image": "url('images/page-loading.gif')" });
+         target.css({ "background-repeat": "no-repeat" });
+         target.css({ "background-size": "25px 25px" });
+
+       var branch = document.getElementById("branchId").value.trim();
+       var statusObj = document.getElementById("responseId");
+       if(branch == null || branch == ''){
+               statusObj.innerText = "Branch is required.";
+               return;
+       }
+       var urlVal = "/gitcheckout?branch=" + branch;
+       $.get(urlVal)
+               .done(function( data ) {
+                       var output = data.output;
+                       if(output != null){
+                               output=output.replace(/\n/g,"<br>");
+                               statusObj.innerHTML = output;
+                       }
+                })
+               .fail(function(err) {
+                       statusObj.innerText = "Failed to do git checkout.";
+               })
+               .always(function() {
+                       $("#responseId").show();
+                        target.val("Checkout");
+                         target.css({ "background-image": "none" });
+                });
+}
+
+function performGitPull(){
+       $("#responseId").text("");
+        if(!event) event = window.event;
+         var target = $(event.target);
+         target.val("Processing");
+         target.css({ "background-image": "url('images/page-loading.gif')" });
+         target.css({ "background-repeat": "no-repeat" });
+         target.css({ "background-size": "25px 25px" });
+
+       var statusObj = document.getElementById("responseId");
+       var urlVal = "/gitpull";
+       $.get(urlVal)
+               .done(function( data ) {
+                       var output = data.output;
+                       if(output != null){
+                               output=output.replace(/\n/g,"<br>");
+                               statusObj.innerHTML = output;
+                       }
+                })
+               .fail(function(err) {
+                       statusObj.innerText = "Failed to do git pull.";
+               })
+               .always(function() {
+                       $("#responseId").show();
+                        target.val("Pull");
+                         target.css({ "background-image": "none" });
+                });
+}
+
+
+function activateClickedTab(idVal) {
+
+       $("#filter-tabs-dialog").dialog( "close" );
+       var ul = $("#workspace-tabs");
+       ul.children().each(function(){
+               var li = $(this);
+               var link =li.find("a");
+               var href = link.prop("href");
+               var hrefId = href.split("#");
+               if(hrefId[1] == idVal){
+                link.trigger("click");
+               }
+       });
+}
+
+function deleteOrRenameTab(idVal) {
+       $("#filter-tabs-dialog").dialog( "close" );
+       var ul = $("#workspace-tabs");
+       ul.children().each(function(){
+               var li = $(this);
+               var link =li.find("a");
+               var href = link.prop("href");
+               var hrefId = href.split("#");
+               if(hrefId[1] == idVal){
+                       link.trigger("click");
+                       link.trigger("dblclick");
+               }
+       });
+}
+
+function deleteSelectedTab(idVal,title,_module,rpc,version){
+       var dgInfo = "<div><table width='100%' border='1'><tr style='background-color:#65a9d7;color:white;' ><th>Tab Title</th><th>Module</th><th>RPC</th><th>Version</th></tr><tr style='background-color:white'><td>" + title + "</td><td>" + _module +"</td><td>" + rpc + "</td><td>" +version +  "</td></tr></table></div><br>";
+       var alertMsg = dgInfo + "<p>Are you sure you want to Delete this Tab ?</p>"; 
+
+$( "#tabAlertDialog" ).dialog({
+  dialogClass: "no-close",
+  modal:true,
+  draggable : true,
+  /*dialogClass: "alert",*/
+  title: "Confirm Tab sheet Delete",
+  width: 600,
+  buttons: [
+    {
+      text: "Delete",
+      class:"alertDialogButton",
+      click: function() {
+               var ws = RED.nodes.workspace(idVal);
+               RED.view.removeWorkspace(ws);
+               var historyEvent = RED.nodes.removeWorkspace(idVal);
+               historyEvent.t = 'delete';
+               historyEvent.dirty = true;
+               historyEvent.workspaces = [ws];
+               RED.history.push(historyEvent);
+               RED.view.dirty(true);
+               $( this ).dialog( "close" );
+               $("#filter-tabs-dialog").dialog( "close" );
+               $("#btn-manage-tabs").trigger("click");
+       }
+    },
+    {
+      text: "Cancel",
+      class:"alertDialogButton",
+      click: function() {
+        $( this ).dialog( "close" );
+      }
+    }
+  ]
+}).html(alertMsg);
+}
+
+function renameSelectedTab(idVal,title,_module,rpc,version){
+       var dgInfo = "<div><table width='100%' border='1'><tr style='background-color:#65a9d7;color:white;' ><th>Tab Title</th><th>Module</th><th>RPC</th><th>Version</th></tr><tr style='background-color:white'><td><input id='tab-name-" + idVal + "' type='text' value='" + title + "'></td><td>" + _module +"</td><td>" + rpc + "</td><td>" +version +  "</td></tr></table></div><br>";
+       var alertMsg = dgInfo + "<p>Change the title and click Rename.</p>"; 
+
+$( "#tabAlertDialog" ).dialog({
+  dialogClass: "no-close",
+  modal:true,
+  draggable : true,
+  /*dialogClass: "alert",*/
+  title: "Rename Tab sheet",
+  width: 600,
+  buttons: [
+    {
+      text: "Rename",
+      class:"alertDialogButton",
+      click: function() {
+               var ws = RED.nodes.workspace(idVal);
+               var label = document.getElementById("tab-name-" + idVal).value; 
+               //console.log("label:" +label);
+               //console.log("ws.label:" + ws.label);
+               if (ws.label != label) {
+                        ws.label = label;
+                        var link = $("#workspace-tabs a[href='#"+idVal+"']");
+                        link.attr("title",label);
+                        link.text(label);
+                        RED.view.dirty(true);
+                }
+               $("#tabAlertDialog").dialog('destroy').remove();
+               //$(this).dialog( "close" );
+               $("#filter-tabs-dialog").dialog( "close" );
+               $("#btn-manage-tabs").trigger("click");
+       }
+    },
+    {
+      text: "Cancel",
+      class:"alertDialogButton",
+      click: function() {
+        $( this ).dialog( "close" );
+      }
+    }
+  ]
+}).html(alertMsg);
+}
+
+function performGitStatus(){
+       $("#responseId").text("");
+        if(!event) event = window.event;
+         var target = $(event.target);
+         target.val("Processing");
+         target.css({ "background-image": "url('images/page-loading.gif')" });
+         target.css({ "background-repeat": "no-repeat" });
+         target.css({ "background-size": "25px 25px" });
+
+       var statusObj = document.getElementById("responseId");
+       var urlVal = "/gitstatus";
+       $.get(urlVal)
+               .done(function( data ) {
+                       var output = data.output;
+                       if(output != null){
+                               output=output.replace(/\n/g,"<br>");
+                               statusObj.innerHTML = output;
+                       }
+                       //statusObj.innerText = data.output;
+                })
+               .fail(function(err) {
+                       statusObj.innerText = "Failed to do git status.";
+               })
+               .always(function() {
+                       $("#responseId").show();
+                        target.val("Status");
+                         target.css({ "background-image": "none" });
+                });
+}
+
+function migrateNodes(jsonStr){
+       var nodes = JSON.parse(jsonStr);
+       nodes.forEach( function(node) {
+               if( node.xml != undefined && node.xml != null && node.xml.indexOf("<service-logic") != -1){
+                       //console.log(node.xml);
+                       var module="";
+                       var version="";
+                       module=getAttributeValue(node.xml,"module");
+                       /*
+                       var myRe = new RegExp("module=\"(.*)\" ", "m");
+                       var myArray = myRe.exec(node.xml);
+                       if(myArray != null && myArray[1] != null){
+                               module=myArray[1];
+                       }
+                       myRe = new RegExp("version=\"(.*)\">", "m");
+                        myArray = myRe.exec(node.xml);
+                       if(myArray != null && myArray[1] != null){
+                               version=myArray[1];
+                               //console.dir(myArray);
+                       }
+                       */
+                       version=getAttributeValue(node.xml,"version");
+                       node.type="service-logic";
+                       //node.category="DGEmain";
+                       node.module=module;
+                       node.version=version;
+                       if(module != null && version != null){
+                               node.name=module+ " " + version;
+                       }
+                       console.log("module=" + module);
+                       console.log("version=" + version);
+               }else if( node.xml != undefined && node.xml != null && node.xml.indexOf("<method") != -1){
+                       var rpc=getAttributeValue(node.xml,"rpc");
+                       node.type="method";
+                       if(rpc != null){
+                               node.name=rpc;
+                       }
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<outcome") != -1){
+                        var uxml = node.xml.toUpperCase();
+                       if(uxml.indexOf("FAILURE") != -1){
+                               node.type="failure";
+                       }else if(uxml.indexOf("SUCCESS") != -1){
+                               node.type="success";
+                       }else if(uxml.indexOf("TRUE") != -1){
+                               node.type="outcomeTrue";
+                       }else if(uxml.indexOf("FALSE") != -1){
+                               node.type="outcomeFalse";
+                       }else if(uxml.indexOf("ALREADY-ACTIVE") != -1){
+                               node.type="already-active";
+                       }else if(uxml.indexOf("NOT-FOUND") != -1){
+                               node.type="not-found";
+                       }else{
+                               node.type="other";
+                       }
+               }else if( node.xml != undefined &&node.xml != null && node.xml.indexOf("<return") != -1){
+                        var uxml = node.xml.toUpperCase();
+                       if(uxml.indexOf("FAILURE") != -1){
+                               node.type="returnFailure";
+                       }else if(uxml.indexOf("SUCCESS") != -1){
+                               node.type="returnSuccess";
+                       }
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<exists") != -1){
+                       node.type="exists";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<block") != -1){
+                       node.type="block";
+                       var atomic=getAttributeValue(node.xml,"atomic");
+                       
+                       if(atomic=='true'){
+                               node.atomic="true";
+                               node.name="block : atomic";
+                       }else{
+                               node.atomic="false";
+                               node.name="block";
+                       }
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<save") != -1){
+                       node.type="save";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<switch") != -1){
+                       node.type="switchNode";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<record") != -1){
+                       node.type="record";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<call") != -1){
+                       node.type="call";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<release") != -1){
+                       node.type="release";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<set") != -1){
+                       node.type="set";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<for") != -1){
+                       node.type="for";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<is-available") != -1){
+                       node.type="is-available";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<reserve") != -1){
+                       node.type="reserve";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<get-resource") != -1){
+                       node.type="get-resource";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<configure") != -1){
+                       node.type="configure";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<delete") != -1){
+                       node.type="delete";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<execute") != -1){
+                       node.type="execute";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<notify") != -1){
+                       node.type="notify";
+               }else if(node.xml != undefined && node.xml != null && node.xml.indexOf("<update") != -1){
+                       node.type="update";
+               }
+               //console.dir(node);
+       });     
+       return nodes;
+}
diff --git a/dgbuilder/public/util/js/dgeToXml.js.imp b/dgbuilder/public/util/js/dgeToXml.js.imp
new file mode 100644 (file)
index 0000000..199b1c6
--- /dev/null
@@ -0,0 +1,147 @@
+function getNodeToXml(){
+               var nodeSet=[];
+               var activeWorkspace=RED.view.getWorkspace();
+               RED.nodes.eachNode(function(n) {
+                       if (n.z == activeWorkspace) {
+                               nodeSet.push({n:n});
+                       }
+               });
+
+               var exportableNodeSet = RED.nodes.createExportableNodeSet(nodeSet);
+               console.dir(exportableNodeSet);
+               console.log(JSON.stringify(exportableNodeSet));
+
+               function getDgStartNode(nodeList){
+                       for(var i=0;i<nodeList.length;i++){
+                               if(nodeList[i].type == 'dgstart'){
+                                       return nodeList[i];
+                               }       
+                       }
+                       return null;
+               }
+               function getNode(id){
+                       for(var i=0;i<exportableNodeSet.length;i++){
+                               if(exportableNodeSet[i].id == id){
+                                       return exportableNodeSet[i];
+                               }       
+                       }
+                       return null;
+               }
+
+               function getStartTag(node){
+                       var startTag="";
+                       var xmlStr="";
+                       if(node != null && node.type != 'dgstart'){
+                               xmlStr=node.xml;
+                               var regex = /(<)([\w-]+)(.*)?/;
+                               var match = regex.exec(xmlStr);
+                               if(match != null){
+                                       if(match[1] != undefined && match[2] != undefined){
+                                               startTag = match[2];
+                                       }
+                               }else{
+                                       console.log("startTag not found.");
+                               }       
+                       }
+                       return startTag;
+               }
+
+               var dgstartNode = getDgStartNode(exportableNodeSet);
+
+               var level=0;
+               var fullXmlStr="";
+
+               printXml(dgstartNode);
+               
+
+               function printXml(node){
+                       var xmlStr="";
+                       var startTag = "";
+                       if(node != null && node.type != 'dgstart'){
+                               xmlStr=node.xml;
+                               startTag = getStartTag(node);
+                               if(level > 0){
+                                       var spacing = Array(level).join("  ");  
+                                       xmlStr=xmlStr.replace(/\n/g,spacing);
+                                       fullXmlStr +=xmlStr;
+                                       
+                                       console.log(xmlStr);
+                               }else{
+                                       fullXmlStr +=xmlStr;
+                                       console.log(xmlStr);
+                               }
+                       }
+
+                       //console.log("startTag:" + startTag);
+       
+                       var wiredNodes = [];
+                       if(node != null && node.wires != null && node.wires[0] != null &&  node.wires[0] != undefined && node.wires[0].length >0 ){
+                               wiredNodes=node.wires[0];
+                               //sort based on y position
+                               wiredNodes.sort(function(a, b){
+                                       return a.y-b.y;
+                               });
+                       }
+
+                       for(var k=0;wiredNodes != null && k<wiredNodes.length;k++){
+                               level++;
+                               var nd = getNode(wiredNodes[k]);
+                               printXml(nd);
+                       }
+
+                       //append end tag
+                       if(startTag != ""){
+                               if(level >0){
+                                       var spacing = Array(level).join("  ");  
+                                       fullXmlStr += spacing + "</" + startTag + ">";
+                                       console.log(spacing + "</" + startTag + ">");
+                               }else{
+                                       fullXmlStr += "</" + startTag + ">";
+                                       console.log("</" + startTag + ">");
+                               }
+                       }       
+
+                       if(level>0){
+                               level=level-1;
+                       }
+                       console.log("endTag:" + startTag);
+                       //console.log("xml:" + fullXmlStr);
+               }
+               console.log("fullXmlStr:" + fullXmlStr);
+
+               /*
+               for (var link in allLinks){
+                       var nd = RED.nodes.node(link);
+                       console.dir(nd);                                                 
+                       var obj = RED.nodes.getNodeSet(RED.view.getWorkspace());
+                       console.dir(obj);
+               }
+               */
+
+
+               //console.dir(RED.nodes.getAllFlowNodes());
+               //console.dir(RED.nodes.getType());
+               /*
+               console.dir(RED.nodes.nodes);
+               RED.nodes.nodes.forEach(function (node){
+                       console.dir(node);
+               });
+               */
+
+           /*var map = {68: false, 69: false, 86: false};
+           $("#node-input-validate").keydown(function(e) {
+               if (e.keyCode in map) {
+                       map[e.keyCode] = true;
+                       if (map[68] && map[69] && map[86]) {
+                               // FIRE EVENT
+                               return "abcd";
+                        }
+               }
+               }).keyup(function(e) {
+                       if (e.keyCode in map) {
+                               map[e.keyCode] = false;
+                       }
+               });
+       */      
+       return fullXmlStr;
+}
diff --git a/dgbuilder/public/util/js/jsonTool.js b/dgbuilder/public/util/js/jsonTool.js
new file mode 100644 (file)
index 0000000..f4d0de3
--- /dev/null
@@ -0,0 +1,67 @@
+var obj={};
+function dotToJson(str,value,obj){
+    //var objArr = path.split("."), part;
+    var objArr = str.split(".");
+       var prevStr;
+       var currObj;
+       var prevObj;
+       console.log(str);
+       for(var i=0;i<objArr.length -1;i++){
+               var subStr= objArr[i] ;
+               //console.log("subStr:" + subStr);
+               if(i==0 && obj[subStr] == undefined ){
+                       obj[subStr] = {};
+                       currObj= obj[subStr];
+               }else if(i==0 && obj[subStr] != undefined ){
+                       currObj=obj[subStr];
+                       //console.log("in gkjgjkg");
+               }else{
+                       if(i == 1){
+                               prevObj=obj[prevStr];
+                               if(prevObj[subStr] == undefined){
+                                       prevObj[subStr] = {};
+                                       currObj = prevObj[subStr];
+                               }else{
+                                       currObj = prevObj[subStr];
+                               }
+                       }else{
+                               if(prevObj[subStr] == undefined){
+                                       prevObj[subStr] = {};
+                                       currObj = prevObj[subStr];
+                               }else{
+                                       currObj = prevObj[subStr];
+                               }
+                       }
+                       //console.dir(currObj);
+               }
+               prevStr=subStr;
+               if(i <objArr.length-2){
+                       prevObj=currObj;        
+               }
+       }
+       var lastStr = objArr[objArr.length-1];
+       currObj[lastStr] = value;
+       //prevObj[lastStr] = value;
+       //console.dir(currObj);
+       return obj;
+}
+n=dotToJson('abcfdfghdghdghdghdhdhd.efhfjhfjhfjhfjhfjhfjhfbg.hfjhfjhfjhfjhfjhfjh.l',"1234",obj);
+//console.dir(n);
+JSON.stringify(n,undefined,2);
+m=dotToJson('abc.ebg.h.n',"5678",n);
+console.dir(m);
+function printObj(obj){
+for( j in obj){
+       console.log(j + ":" + obj[j]);
+       if(typeof obj[j] == "object" ){
+               printObj(obj[j]);
+       }
+
+}
+}
+printObj(m);
+a=JSON.parse(JSON.stringify(m,null,2));
+console.dir(a);
+
+
+//console.log (stringToObj('abc.ebg.h',"",{}));
diff --git a/dgbuilder/public/util/js/migrateFlow.js b/dgbuilder/public/util/js/migrateFlow.js
new file mode 100644 (file)
index 0000000..399db60
--- /dev/null
@@ -0,0 +1,184 @@
+fs=require('fs');
+_=require('lodash');
+//extras=require("/home/users/schinthakayala/nodered/sheshi/dgxml/extras");
+//puts=extras.puts;
+var path = require('path');
+var appDir = path.dirname(require.main.filename);
+
+var dgjson = [];
+var level = 0;
+
+function getJSON() {
+var filename = process.argv[2]; 
+  console.log("reading json from flows file" + filename);
+  //flowsJson=fs.readFileSync(appDir + "/flows_ss4nj01dev01.localdomain.json").toString();
+  flowsJson=fs.readFileSync(filename).toString();
+  // Let's make a backup while we're here...
+  ts=Date.now().toString();
+  flows=JSON.parse(flowsJson);
+  //console.log("returning flows");
+  return(flows);
+}
+
+function getStartTag(xmlStr){
+        var startTag= null ;
+       if(xmlStr != null){
+               xmlStr = xmlStr.trim();
+       }
+        try{
+                var regex = new RegExp("(<)([^ >]+)");
+                var match = regex.exec(xmlStr);
+                if(match != null){
+                        if(match[1] != undefined && match[2] != undefined){
+                                startTag = match[2];
+                        }
+                }
+        }catch(e){
+                console.log(e);
+        }
+       return startTag;
+
+}
+
+function getAttributeValue(xmlStr,attribute){
+       var attrVal=null;
+       try{
+               var myRe = new RegExp(attribute + "=['\"](.*)['\"] ","m");
+               var myArray = myRe.exec(xmlStr);
+               if(myArray != null && myArray[1] != null){
+                       attrVal=myArray[1];
+               }
+       }catch(err){
+               console.log(err);
+       }
+       return attrVal;
+}
+
+function processNodes(){
+       var nodes = getJSON();
+       //console.dir(nodes);
+
+       nodes.forEach( function(node) {
+               if( node.xml != null && node.xml.indexOf("<service-logic") != -1){
+                       //console.log(node.xml);
+                       var module="";
+                       var version="";
+                       module=getAttributeValue(node.xml,"module");
+                       /*
+                       var myRe = new RegExp("module=\"(.*)\" ", "m");
+                       var myArray = myRe.exec(node.xml);
+                       if(myArray != null && myArray[1] != null){
+                               module=myArray[1];
+                       }
+                       myRe = new RegExp("version=\"(.*)\">", "m");
+                        myArray = myRe.exec(node.xml);
+                       if(myArray != null && myArray[1] != null){
+                               version=myArray[1];
+                               //console.dir(myArray);
+                       }
+                       */
+                       version=getAttributeValue(node.xml,"version");
+                       node.type="service-logic";
+                       //node.category="DGEmain";
+                       node.module=module;
+                       node.version=version;
+                       if(module != null && version != null){
+                               node.name=module+ "_" + version;
+                       }
+                       console.log("module=" + module);
+                       console.log("version=" + version);
+               }else if( node.xml != null && node.xml.indexOf("<method") != -1){
+                       var rpc=getAttributeValue(node.xml,"rpc");
+                       node.type="method";
+                       if(rpc != null){
+                               node.name=rpc;
+                       }
+               }else if( node.xml != null && node.xml.indexOf("<outcome") != -1){
+                        var uxml = node.xml.toUpperCase();
+                       if(uxml.indexOf("FAILURE") != -1){
+                               node.type="failure";
+                       }else if(uxml.indexOf("SUCCESS") != -1){
+                               node.type="success";
+                       }else if(uxml.indexOf("TRUE") != -1){
+                               node.type="outcomeTrue";
+                       }else if(uxml.indexOf("FALSE") != -1){
+                               node.type="outcomeFalse";
+                       }else if(uxml.indexOf("ALREADY-ACTIVE") != -1){
+                               node.type="already-active";
+                       }else if(uxml.indexOf("NOT-FOUND") != -1){
+                               node.type="not-found";
+                       }else{
+                               node.type="other";
+                       }
+               }else if( node.xml != null && node.xml.indexOf("<return") != -1){
+                        var uxml = node.xml.toUpperCase();
+                       if(uxml.indexOf("FAILURE") != -1){
+                               node.type="returnFailure";
+                       }else if(uxml.indexOf("SUCCESS") != -1){
+                               node.type="returnSuccess";
+                       }
+               }else if( node.xml != null && node.xml.indexOf("<exists") != -1){
+                       node.type="exists";
+               }else if( node.xml != null && node.xml.indexOf("<block") != -1){
+                       node.type="block";
+                       var atomic=getAttributeValue(node.xml,"atomic");
+                       
+                       if(atomic=='true'){
+                               node.atomic="true";
+                               node.name="block : atomic";
+                       }else{
+                               node.atomic="false";
+                               node.name="block";
+                       }
+               }else if( node.xml != null && node.xml.indexOf("<save") != -1){
+                       node.type="save";
+               }else if( node.xml != null && node.xml.indexOf("<switch") != -1){
+                       node.type="switchNode";
+               }else if( node.xml != null && node.xml.indexOf("<record") != -1){
+                       node.type="record";
+               }else if( node.xml != null && node.xml.indexOf("<call") != -1){
+                       node.type="call";
+               }else if( node.xml != null && node.xml.indexOf("<release") != -1){
+                       node.type="release";
+               }else if( node.xml != null && node.xml.indexOf("<set") != -1){
+                       node.type="set";
+               }else if( node.xml != null && node.xml.indexOf("<for") != -1){
+                       node.type="for";
+               }else if( node.xml != null && node.xml.indexOf("<is-available") != -1){
+                       node.type="is-available";
+               }else if( node.xml != null && node.xml.indexOf("<reserve") != -1){
+                       node.type="reserve";
+               }else if( node.xml != null && node.xml.indexOf("<get-resource") != -1){
+                       node.type="get-resource";
+               }else if( node.xml != null && node.xml.indexOf("<configure") != -1){
+                       node.type="configure";
+               }else if( node.xml != null && node.xml.indexOf("<delete") != -1){
+                       node.type="delete";
+               }else if( node.xml != null && node.xml.indexOf("<execute") != -1){
+                       node.type="execute";
+               }
+               //console.dir(node);
+       });     
+/*
+       var moduleName = "service-logic";
+       var methodName = "method";
+        for(var i=0;nodes != null && i<nodes.length;i++){
+                        if(nodes[i].type == "service-logic"){
+                                moduleName = nodes[i].name;
+                        }
+                        if(nodes[i].type == "method"){
+                                methodName = nodes[i].name;
+                        }
+        }
+       var fName = moduleName + "_" + methodName + ".json";
+       fName = fName.replace(/\s/g, "_");
+
+       var newFilename = process.argv[3];
+       var filename =   newFilename + "/" + fName;
+       console.log("filename" + filename);
+        fs.writeFileSync(filename, JSON.stringify(nodes,null,4));
+       */
+}
+
+
+processNodes();
diff --git a/dgbuilder/public/util/js/sliValues.js b/dgbuilder/public/util/js/sliValues.js
new file mode 100644 (file)
index 0000000..eae1060
--- /dev/null
@@ -0,0 +1,763 @@
+var global_editor ; 
+function addParam(idVal){
+       //console.log(val);
+       //console.log(global_editor.getText());
+       if(global_added_obj["a" + idVal] != undefined &&  global_added_obj["a" + idVal] != null){
+               global_added_obj["a" + idVal]= global_added_obj["a" + idVal]+1;
+               $("#addCnt" +  + idVal).text("added " + global_added_obj["a" + idVal] + " times");
+       }else{
+               global_added_obj["a" + idVal]= 1;
+               $("#addCnt" +  + idVal).text("added " + global_added_obj["a" + idVal] + " time");
+       }
+       var nameVal = document.getElementById("a" + idVal).value;
+       var valueBoxVal = document.getElementById("valbox" + idVal).value;
+       //$("#btn" + idVal).val('Added');
+       //$("#btn" + idVal).attr('disabled','disabled'); 
+       //console.dir(nameVal);
+       //console.dir(valueBoxVal);
+
+
+       var paramElement = "<parameter name='" + nameVal + "' value='" + valueBoxVal + "'/>\n";
+       global_editor.setText(global_editor.getText() + paramElement);
+}
+
+var g_currValuesObj={};
+
+function filterValues(filterVal){
+       global_added_obj={};
+       var matchedCnt =0;
+       var valuesObj = g_currValuesObj;
+       var newValuesObj ={};
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       //console.log("filterVal:" + filterVal);
+       if(searchValues != null && searchValues != undefined){  
+               for (var key in valuesObj) {
+                       if (valuesObj.hasOwnProperty(key)) {
+                               var newArrObj = [];
+                               if(Array.isArray(valuesObj[key])){
+                                       var arrObj=valuesObj[key];
+                                       var cnt=1;
+                                       for(var i=0;i<arrObj.length;i++){
+                                               var foundCount = 0;
+                                               for(var k=0;k<searchValues.length;k++){
+                                                       if(arrObj[i].indexOf(searchValues[k]) != -1){
+                                                               foundCount++;
+                                                       }
+                                               }
+                                               if(foundCount == searchValues.length){
+                                                       matchedCnt++;
+                                                       newArrObj.push(arrObj[i]);
+                                               }
+                                       }       
+                                       newValuesObj[key] =  newArrObj;
+                               }               
+                       }
+               }
+               $("#matchedCntId").html(matchedCnt);
+       }else{
+               newValuesObj = valuesObj;
+       }
+       var valuesHtml=buildValuesHtml(newValuesObj);   
+        valuesHtml+="</div>";
+       $("#sli-values-div").html(valuesHtml);
+}
+
+function buildValuesHtml(valuesObj){
+       var idCounter=0;
+       var htmlVal = "";
+       
+        for (var key in valuesObj) {
+             if (valuesObj.hasOwnProperty(key)) {
+                   var v = "<div style='font-weight:bold;font-size:1.0em;'><label>" + key + "<b/label>";
+                   if(Array.isArray(valuesObj[key])){
+                      var arrObj=valuesObj[key];
+                       var cnt=1;
+                      for(var i=0;i<arrObj.length;i++){
+                               var idVal = idCounter++;
+                        var addBtn = "<input id='btn" + idVal + "' type='button' style='background-color:#D6EBFF;' value='Add as Parameter'" + "onclick='addParam(\"" + idVal + "\")'><div style='float:right' id='addCnt" + idVal + "'></div>";
+                       var variableBox = "";
+                       var valBox = "<input id='valbox" + idVal + "' type='text' style='width:500px;height:30px;' value=''>";
+                       if(arrObj[i] != undefined && arrObj[i].length <150){
+                               //v += "<div style='width:1150px;background:aliceblue;border-color:aliceblue' class='valueBoxDiv' id='valueBoxDiv" + idVal +  "'>"  + "<input style='width:1125px;background:rgb(223, 191, 191);color:rgb(32, 45, 87);' type='text' readonly='1'  id='a" + idVal + "' onclick='selectText(\"" + idVal+"\",\"" + key + "\")' value='" +arrObj[i] + "' title='" + arrObj[i] + "' >" ;
+                               v += "<div style='width:1150px;background:aliceblue;border-color:aliceblue' class='valueBoxDiv' id='valueBoxDiv" + idVal +  "'>"  + "<input style='width:1125px;background:aliceblue;color:rgb(32, 45, 87);' type='text' readonly='1'  id='a" + idVal + "' onclick='selectText(\"" + idVal+"\",\"" + key + "\")' value='" +arrObj[i] + "' title='" + arrObj[i] + "' >" ;
+                               variableBox = "<input style='width:1125px' id='variableBox" + idVal + "' type='text' value='`$" + arrObj[i] + "`'>";
+                       }else{
+                               v+= "<div style='width:1150px;background:aliceblue;border-color:aliceblue' class='valueBoxDiv' id='valueBoxDiv" + idVal +  "'>"  + "<textarea style='width:1125px;background:aliceblue;color:rgb(32, 45, 87);' readonly='1'  id='a" + idVal + "' onclick='selectText(\"" + idVal+"\",\"" + key + "\")' title='" + arrObj[i] + "' >"  + arrObj[i] + "</textarea>";
+                               variableBox = "<textarea style='width:1125px' id='variableBox" + idVal + "' >`$" + arrObj[i] + "`'</textarea>";
+                       }
+                         v += "<div id='valAddDiv" +  idVal + "' style='display:none;'>" +  valBox + "&nbsp;&nbsp;" + addBtn + "</div>" +
+                          "<div id='variableBoxDiv" + idVal + "' style='display:none;color:rgb(32, 45, 87);'>Display as a variable<br>" + variableBox + "</div>" + "</div>";
+                       cnt++;
+                      }
+                      htmlVal+= v + "</div>";
+                                }
+                   }
+             }
+       return htmlVal;
+}
+
+function getModuleName(){
+       var activeWorkspace=RED.view.getWorkspace();
+       var moduleName="";
+       RED.nodes.eachNode(function(n) {
+               if (n.z == activeWorkspace) {
+                       if(n.type == 'service-logic'){
+                               //console.log("getModuleName():<" + n.module + ">");
+                               moduleName=n.module;
+                       }
+                       }
+               });
+       return moduleName;
+}
+var global_added_obj={};
+var displayingRpcs = false;
+function showRpcsValuesBox(editor,valuesObj){
+       displayingRpcs = true;
+       showValuesBox(editor,valuesObj);
+}
+
+function showValuesBox(editor,valuesObj){
+       var moduleName = getModuleName();       
+       var obj = valuesObj[moduleName];
+       //console.dir(valuesObj);
+       //console.dir(obj);
+       var moduleObj ={};
+       if(obj == undefined){
+               moduleObj[moduleName] = ["No SLI values setup for this module " + moduleName + ".Upload the yang file for this module or if already uploaded ,load it from the Available Modules from the Menu."];      
+       }else{
+               moduleObj[moduleName] = obj;
+       }
+       showValuesBoxForModule(editor,moduleObj,moduleName);    
+}
+
+function showValuesBoxForModule(editor,valuesObj,moduleName){
+       global_editor=editor;
+       g_currValuesObj = valuesObj;
+       //console.log(editor.getText());
+       //populate the valid SLI values
+       var valuesHtml="<style>.color-dialog {background:aliceblue;border-color:lightgrey;border-width:3px;border-style:solid; }</style><div style='float:left;width:1200px;background:aliceblue'><input style='width:1125px' id='filter-id' type='text' value='' placeholder='To filter the values type words seperated by space in this box' onkeyup='filterValues(this.value)'></div><div style='float:left;color:green;font-size:0.8em' id='matchedCntId'></div><div style='clear:both'></div><div id='sli-values-div' style='width:1200px;'>" ;
+       valuesHtml+=buildValuesHtml(valuesObj); 
+       valuesHtml+="</div>";
+       global_added_obj={};
+
+       
+ var title = "SLI Values for Module " + moduleName;    
+       if(displayingRpcs){
+               title = "RPCs for Module " + moduleName;
+       }
+       $('#sli-values-dialog').dialog({
+                       modal: false,
+                       title: title,
+                       width: 1200,
+                      height: 500,
+                      dialogClass: 'color-dialog',
+                       open: function () {
+                               $("#sli-values-dialog").dialog("widget").find(".ui-dialog-buttonpane").css({'background': 'aliceblue'});
+                                $(this).html(valuesHtml);
+                       },
+                       buttons: {
+                           Close: function () {
+                               displayingRpcs = false;
+                              //$(this).dialog("close");
+                              $(this).dialog("destroy");
+                           }
+                       },
+                       close: function(ev,ui){
+                               displayingRpcs = false;
+                               $(this).dialog("destroy");
+                       }
+        }); // end dialog div
+}
+
+function showCommentsBox(){
+       var comments = $("#node-input-comments").val();
+       var commentsBoxHtml="<div><textarea style='font-size:18px;height:150px;width:390px;' id='taCommentId'>" + comments + "</textarea></div>" ;
+
+       var nodeName=$("#node-input-name").val();
+       $('#comments-dialog').dialog({
+                       modal: true,
+                       title: "Add comments for Node " + nodeName,
+                       width: 450,
+                      height: 300,     
+                       /*      
+                       open: function () {
+                                $(this).html(commentsBoxHtml);
+                       },
+                       */
+                       buttons: {
+                           "Save Comments": function () {
+                               var v=$("#taCommentId").val();
+                               if(v != null){
+                                       v = v.trim();
+                                       if(v != ''){
+                                               $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+                                       }else{
+                                               $("#node-input-btnComments").html("<b>Add Comments</b>");
+                                       }
+                               }
+                               //console.log("value from text area" + v);
+                               $("#node-input-comments").val(v);
+                               $(this).dialog("close");
+                              //$(this).dialog("destroy");
+                           },
+                           Cancel: function () {
+                               var v=$("#taCommentId").val();
+                               if(v != null){
+                                       v = v.trim();
+                                       if(v != ''){
+                                               $("#node-input-btnComments").html("<span style='color:blue;'><b>View Comments</b></span>");
+                                       }else{
+                                               $("#node-input-btnComments").html("<b>Add Comments</b>");
+                                       }
+                               }
+                               $(this).dialog("close");
+                              //$(this).dialog("destroy");
+                           }
+                       },
+                       close: function(ev,ui){
+                               //console.log("closing..");
+                               $(this).dialog("destroy");
+                       }
+        }).html(commentsBoxHtml);
+
+       //console.log("done");
+/*     
+       function functionDialogResize(ev,ui) {
+               console.log("ui.size.height:" + ui.size.height);
+                $(this).css("height",(ui.size.height-275)+"px");
+        };
+
+        $( this ).on("dialogresize", functionDialogResize);
+
+
+       $( this ).one("dialogopen", function(ev) {
+                var size = $( "#sliValDiv" ).dialog('option','sizeCache-function');
+                if (size) {
+                    functionDialogResize(null,{size:size});
+                }
+         });
+*/
+
+}
+
+function selectText(objId,groupVal){
+       //console.log(objId + groupVal);        
+       //console.log(objId + groupVal);        
+       $(document).ready(function(){
+               //console.log("doc ready");
+               //console.dir($('#valAddDiv' +  objId));
+               if ($('#valAddDiv' +  objId).is(":visible")) {
+                       $("#variableBoxDiv" +  objId ).hide("slow");
+                       //$("#a" +  objId ).css({"background": "rgb(223, 191, 191)",
+                       //                      "color": "rgb(32, 45, 87)"});
+                       $("#a" +  objId ).css({"background": "aliceblue",
+                                               "color": "rgb(32, 45, 87)"});
+                                               /*"color": "rgb(32, 45, 87)"});*/
+                       $("#valAddDiv" +  objId ).hide("slow");
+                       $("#valueBoxDiv" +objId).css({"border-color": "aliceblue",
+                                                       "border-width":"1px", 
+                                                       "background-color":"aliceblue",
+                                                       "border-style":"solid"});
+                       //$("#valAddDiv" +  objId ).fadeOut("slow");
+               } else{
+                       $("#variableBoxDiv" +  objId ).show("slow");
+                       $("#valAddDiv" +  objId).show("slow");
+                       /*$("#valueBoxDiv" +objId).css({"border-color": "rgb(75, 111, 147)",
+                                                       "border-width":"5px", 
+                                                       "background-color": "rgb(223, 191, 191)",
+                                                       "border-style":"solid",
+                                                       "border-bottom": "5px solid rgb(75, 111, 147)"});
+                       */
+                       $("#valueBoxDiv" +objId).css({"border-color": "rgb(75, 111, 147)",
+                                                       "border-width":"3px", 
+                                                       "background-color": "aliceblue",
+                                                       "border-style":"solid",
+                                                       "border-bottom": "3px solid rgb(75, 111, 147)"});
+                       /*$("#a" +  objId ).css({"background": "rgb(223, 191, 191)",
+                                               "color": "rgb(75, 111, 147)"});
+                       */
+                       $("#a" +  objId ).css({"background": "aliceblue",
+                                               "color": "rgb(75, 111, 147)"});
+               }
+               $("#a" +  objId).select();
+       });
+       //console.log("group-heading" + objId);
+//     var obj= document.getElementById("group-heading" +  objId);
+//     obj.innerText = groupVal;
+//     obj.style.color = "blue";
+//     console.dir(obj);
+}
+
+function hidePrevGroup(objId){
+//     console.log("mouseout" );
+//     var obj= document.getElementById("group-heading" +  objId);
+//     obj.innerText = "";
+}
+/*
+function fixDiv() {
+    var $cache = $('#getFixed');
+    if ($(window).scrollTop() > 100)
+      $cache.css({
+        'position': 'fixed',
+        'top': '10px'
+      });
+    else
+      $cache.css({
+        'position': 'relative',
+        'top': 'auto'
+      });
+ }
+
+$(window).scroll(fixDiv);
+
+function isScrolledIntoView(elem)
+{
+    var $elem = $(elem);
+    var $window = $(window);
+
+    var docViewTop = $window.scrollTop();
+    var docViewBottom = docViewTop + $window.height();
+
+    var elemTop = $elem.offset().top;
+    var elemBottom = elemTop + $elem.height();
+
+    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
+}
+*/
+
+function getCommits(filePath){
+var urlPath="/getCommitsInfo";
+$.get(urlPath,{"filePath" : filePath })
+       .done(function( data ) {
+               if(data != undefined && data != null){
+                       //console.log(data.stdout);
+                       var jsonObj = JSON.parse(data.stdout);
+                       var codeCloudFilesHtmlStr = $( "#codecloud-browser-dialog" ).html();
+                       var htmlStr = getCCFileHtmlStr(filePath,jsonObj,codeCloudFilesHtmlStr);
+                       $( "#codecloud-browser-dialog" ).html(htmlStr);
+                       /*
+                       for(var i=0;i<jsonObj.length;i++){
+                               console.log("commit:" + jsonObj[i].commit);     
+                               console.log("date:" + jsonObj[i].date); 
+                               console.log("author:" + jsonObj[i].author);     
+                               console.log("comment:" + jsonObj[i].comment);   
+                       }
+                       */
+               }
+       })
+       .fail(function(err) {
+       })
+       .always(function() {
+       });
+}
+
+
+function getCCFileHtmlStr(filePath,rows,codeCloudFilesHtmlStr){
+       var styleStr = "<style> " + 
+                       "table#cct01 { width:100%; } \n" +
+                               "table#cct01 th,table#cct01 td { border: 1px solid black; border-collapse: collapse; } \n" +
+                               "table#cct01 th,table#cct01 td { padding: 5px; text-align: left; } \n" +
+                               "table#cct01 tr:nth-child(even) { background-color: #eee; }\n" +
+                               "table#cct01 tr:nth-child(odd) { background-color:#fff; }\n" +
+                               "table#cct01 th { background-color: #65a9d7; color: white; }\n" +
+                               "table#cct01 a { color: #337ab7; }\n" +
+                               "table#cct01 a:link { color: #65a9d7; }\n" +
+                               "table#cct01 a:visited { color: #636; }\n" + 
+                               "table#cct01 a:hover { color: #3366CC; cursor: pointer }\n" + 
+                               "table#cct01 a:active { color: #65a9d7 }\n" +
+                               "table#cct01 caption { display: table-caption; text-align: center;  background: #eee; font-weight: bold; font-size: 1.1em; border: 1px solid black; }\n" + 
+                               "</style>";
+                       var htmlStr="";
+                       //console.dir(rows);    
+                       if(rows != null && rows.length >0){
+                               var alertDialog = '<div id="ccAlertdialog"></div>';
+                               htmlStr= alertDialog +  "<div style='width:1050;height:650'>" + styleStr;
+                               htmlStr += "<table id='cct01' >";
+                               htmlStr += "<caption id='ccCaptionId'>" + filePath + "</caption>";
+                               htmlStr += "<tr>";
+                               htmlStr += "<th>Commit ID</th>" ;
+                               htmlStr += "<th>Date</th>" ;
+                               htmlStr += "<th>Author</th>" ;
+                               htmlStr += "<th>Comment</th>" ;
+                               htmlStr += "</tr>";
+                               if(rows != null && rows.length == 0){
+                                       htmlStr += "<tr>";
+                                       htmlStr += "<td><b>No rows found</b></td>";
+                                       htmlStr += "</tr></table></div>";
+                                       return htmlStr;
+                               }
+                               for(var i=0;i<rows.length;i++){
+                                       var row = rows[i];
+                                       var _commitId = row.commit;
+                                       var dt = row.date;
+                                       var author = row.author;
+                                       var comment = row.comment;
+                                       htmlStr += "<tr>";
+                                       htmlStr += "<td><a onclick=\"javascript:importCCFlow('" + _commitId + "','" + filePath + "')\">" + _commitId + "</a></td>";
+                                       htmlStr += "<td>" + dt + "</td>";
+                                       htmlStr += "<td>" + author + "</td>";
+                                       htmlStr += "<td>" + comment + "</td>"; 
+                                       htmlStr += "</tr>";
+                               }
+                               htmlStr += "</table>";
+                               htmlStr += "</div>";
+                       }
+       //console.log(htmlStr);
+       return htmlStr;
+}
+
+
+var gitLocalFlowFiles=[];
+function filterGitLocalFlows(filterVal){
+       
+       var matchedCnt =0;
+       var valuesObj = gitLocalFlowFiles;
+       //console.dir(codeCloudFlowFiles);
+       var updatedValuesObj =[];
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       //console.log("filterVal:" + filterVal);
+       //console.dir(searchValues);
+       if(searchValues != null && searchValues != undefined){  
+               var foundCount = 0;
+               for(var k=0;k<searchValues.length;k++){
+                       if(foundCount >0){
+                               valuesObj=updatedValuesObj;
+                       }
+                       updatedValuesObj=[];
+                       for(var i=0;i<valuesObj.length;i++){
+                               var patt = new RegExp(searchValues[k],"gi");
+                               if(patt.test(valuesObj[i])){
+                                       foundCount++;
+                                       updatedValuesObj.push(valuesObj[i]);
+                               }
+                       }
+               }
+       }else{
+               updatedValuesObj = valuesObj;
+       }
+       //console.dir(updatedValuesObj);
+       var html="<ul>";
+       if(updatedValuesObj != null){
+               var files=updatedValuesObj;
+               //console.dir(files);
+               files.sort(function (a,b){
+                       if(a > b){
+                               return 1;
+                       }else if(a <  b){
+                               return -1;
+                       }else{  
+                               return 0;
+                       }
+               });
+               for(var i=0;files != null && i<files.length;i++){
+                       html+="<li><a href=\"#\" onclick=\"importGitLocalFlow('" + files[i] + "')\">" + files[i] + "</a></li>";
+               }
+       }
+                                       html+="</ul>";
+                                       html+="</div>";
+       $( "#gitlocal-data-container" ).html(html);
+}
+
+var codeCloudFlowFiles=[];
+function filterFlows(filterVal){
+       
+       var matchedCnt =0;
+       var valuesObj = codeCloudFlowFiles;
+       //console.dir(codeCloudFlowFiles);
+       var updatedValuesObj =[];
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       //console.log("filterVal:" + filterVal);
+       //console.dir(searchValues);
+       if(searchValues != null && searchValues != undefined){  
+               var foundCount = 0;
+               for(var k=0;k<searchValues.length;k++){
+                       for(var i=0;i<valuesObj.length;i++){
+                               var patt = new RegExp(searchValues[k],"gi");
+                               if(patt.test(valuesObj[i])){
+                                       foundCount++;
+                                       updatedValuesObj.push(valuesObj[i]);
+                               }
+                       }
+               }
+       }else{
+               updatedValuesObj = valuesObj;
+       }
+       //console.dir(updatedValuesObj);
+       var html="<ul>";
+       if(updatedValuesObj != null){
+               var files=updatedValuesObj;
+               //console.dir(files);
+               files.sort(function (a,b){
+                       if(a > b){
+                               return 1;
+                       }else if(a <  b){
+                               return -1;
+                       }else{  
+                               return 0;
+                       }
+               });
+               for(var i=0;files != null && i<files.length;i++){
+                       html+="<li><a href=\"#\" onclick=\"getCommits('" + files[i] + "')\">" + files[i] + "</a></li>";
+               }
+       }
+                                       html+="</ul>";
+                                       html+="</div>";
+       $( "#codecloud-data-container" ).html(html);
+}
+
+var yangFilesList=[];
+/*
+function filterYangFiles(filterVal){
+       
+       var matchedCnt =0;
+       var valuesObj = yangFilesList;
+       var updatedValuesObj =[];
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       if(searchValues != null && searchValues != undefined){  
+               var foundCount = 0;
+               for(var k=0;k<searchValues.length;k++){
+                       for(var i=0;i<valuesObj.length;i++){
+                               var patt = new RegExp(searchValues[k],"gi");
+                               if(patt.test(valuesObj[i])){
+                                       foundCount++;
+                                       updatedValuesObj.push(valuesObj[i]);
+                               }
+                       }
+               }
+       }else{
+               updatedValuesObj = valuesObj;
+       }
+       //console.dir(updatedValuesObj);
+       var html="<ul>";
+       if(updatedValuesObj != null){
+               var files=updatedValuesObj;
+               //console.dir(files);
+               files.sort(function (a,b){
+                       if(a > b){
+                               return 1;
+                       }else if(a <  b){
+                               return -1;
+                       }else{  
+                               return 0;
+                       }
+               });
+               for(var i=0;files != null && i<files.length;i++){
+                       html+="<li><a href=\"#\" onclick=\"getYangFile('" + files[i] + "')\">" + files[i] + "</a></li>";
+               }
+       }
+                                       html+="</ul>";
+                                       html+="</div>";
+       $( "#list-yang-data-container" ).html(html);
+}
+*/
+
+function filterYangFiles(filterVal){
+       var matchedCnt =0;
+       var valuesObj = yangFilesList;
+       var updatedValuesObj =[];
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       if(searchValues != null && searchValues != undefined){  
+               var foundCount = 0;
+               for(var k=0;k<searchValues.length;k++){
+                       for(var i=0;i<valuesObj.length;i++){
+                               var patt = new RegExp(searchValues[k],"gi");
+                               if(patt.test(valuesObj[i])){
+                                       foundCount++;
+                                       updatedValuesObj.push(valuesObj[i]);
+                               }
+                       }
+               }
+       }else{
+               updatedValuesObj = valuesObj;
+       }
+       //console.dir(updatedValuesObj);
+       var html="<table id='yang-file-list-table'  border=1>";
+            html+="<tr>";
+            html+="<th>File</th>";
+            html+="<th>Delete</th>";
+            html+="</tr>";
+       
+       if(updatedValuesObj != null){
+               var files=updatedValuesObj;
+               //console.dir(files);
+               files.sort(function (a,b){
+                       if(a > b){
+                               return 1;
+                       }else if(a <  b){
+                               return -1;
+                       }else{  
+                               return 0;
+                       }
+               });
+               for(var i=0;files != null && i<files.length;i++){
+                        html+="<tr><td><a href=\"#\" onclick=\"getYangFile('" + files[i] + "')\">" + files[i] + "</a></td><td>" + "<input type='button'  onclick='deleteYangFile(\"" + files[i]  + "\")' value='Delete'></td></td></td></tr>";
+               }
+       }
+       html+="</table>";
+        html+="</div>";
+
+       $( "#yang-files-data-container" ).html(html);
+}
+
+function getYangFile(fileName){
+       $("#dwnldYangFormId").remove();
+        //using form to submit
+        var form = $('<form id="dwnldYangFormId" method="POST" action="/downloadYang"></form>');
+        form.append('<input type="hidden" name="fileName" value="' + fileName + '"/>');
+        form.appendTo('body');
+        $("#dwnldYangFormId").submit();
+
+}
+function deleteYangFile(fileName){
+       var reqData= {"fileName":fileName};
+        $.post( "/deleteYangFile",reqData )
+                      .done(function( data ) {
+                      })
+                      .fail(function(err) {
+                          console.log( "error" + err );
+                       })
+                       .always(function() {
+                              $("#list-yang-browser-dialog").dialog("close");
+                               $("#btn-list-yang-files").trigger("click");
+                       });
+}
+
+function importCCFlow(commitId,filePath){
+var urlPath="/importCodeCloudFlow";
+$.get(urlPath,{"commitId" : commitId,"filePath" : filePath })
+       .done(function( data ) {
+               if(data != undefined && data != null){
+                       //console.log(data.stdout);
+                       var jsonObj = JSON.parse(data.stdout);
+                       $( "#codecloud-browser-dialog" ).dialog("close");
+                       RED.view.importNodes(JSON.stringify(jsonObj));
+               }
+       })
+       .fail(function(err) {
+               RED.notify("Could not import flow from code cloud.");   
+               $( "#codecloud-browser-dialog").dialog("close");
+               console.log( "error occured importing flow.");
+       })
+       .always(function() {
+       });
+}
+
+function importGitLocalFlow(filePath){
+var urlPath="/importGitLocalFlow";
+$.get(urlPath,{"filePath" : filePath })
+       .done(function( data ) {
+               if(data != undefined && data != null){
+                       //console.log(data.stdout);
+                       var jsonObj;
+                       try{
+                               jsonObj = JSON.parse(data.stdout);
+                               $( "#gitlocal-browser-dialog" ).dialog("close");
+                               RED.view.importNodes(JSON.stringify(jsonObj));
+                       }catch(err){
+                               RED.notify("Could not import flow from Local Git Repository."); 
+                               $( "#gitlocal-browser-dialog").dialog("close");
+                               console.log( "error occured importing flow." + err);
+                       }
+               }else{
+                       RED.notify("Could not import flow from Local Git Repository."); 
+                       $( "#gitlocal-browser-dialog").dialog("close");
+                       console.log( "error occured importing flow." + err);
+               }
+       })
+       .fail(function(err) {
+               RED.notify("Could not import flow from Local Git Repository."); 
+               $( "#gitlocal-browser-dialog").dialog("close");
+               console.log( "error occured importing flow.");
+       })
+       .always(function() {
+       });
+}
+
+var availableYangModules=[];
+function filterYangModules(filterVal){
+       
+       var matchedCnt =0;
+       var valuesObj = availableYangModules ;
+       //console.dir(codeCloudFlowFiles);
+       var updatedValuesObj =[];
+       var searchValues =[];
+       if(filterVal != null && filterVal != undefined){
+               filterVal=filterVal.trim();
+       }       
+       searchValues = filterVal.split(/ /);
+       //console.log("filterVal:" + filterVal);
+       //console.dir(searchValues);
+       if(searchValues != null && searchValues != undefined){  
+               var foundCount = 0;
+               for(var k=0;k<searchValues.length;k++){
+                       if(foundCount >0){
+                               valuesObj=updatedValuesObj;
+                       }
+                       updatedValuesObj=[];
+                       for(var i=0;i<valuesObj.length;i++){
+                               var patt = new RegExp(searchValues[k],"gi");
+                               if(patt.test(valuesObj[i])){
+                                       foundCount++;
+                                       updatedValuesObj.push(valuesObj[i]);
+                               }
+                       }
+               }
+       }else{
+               updatedValuesObj = valuesObj;
+       }
+       //console.dir(updatedValuesObj);
+       var html="";
+       html+="<table border=1>";
+        html+="<tr>";
+        html+="<th>#</th>";
+        html+="<th>Load</th>";
+        html+="<th>Module</th>";
+        html+="</tr>";
+
+       if(updatedValuesObj != null){
+               var files=updatedValuesObj;
+               //console.dir(files);
+               files.sort(function (a,b){
+                       if(a > b){
+                               return 1;
+                       }else if(a <  b){
+                               return -1;
+                       }else{  
+                               return 0;
+                       }
+               });
+               var count=1;
+               for(var i=0;files != null && i<files.length;i++){
+                       var val = files[i].replace(/:.*/,"");
+                       if(files[i].indexOf(":checked") != -1){
+                               html+="<tr><td>" + count +  "</td><td><input type='checkbox' checked value='" + val + "'></td><td>" + val + "</td></tr>";
+                        }else{
+                                html+="<tr><td>" + count +   "</td><td><input type='checkbox' value='" + val + "'></td><td>" + val + "</td></tr>";
+                        }
+                       count++;
+               }
+       }
+       html+="</table>";
+       html+="</div>";
+       $( "#yang-modules-data-container" ).html(html);
+}
diff --git a/dgbuilder/public/util/js/validateNodeXml.js b/dgbuilder/public/util/js/validateNodeXml.js
new file mode 100644 (file)
index 0000000..2291d86
--- /dev/null
@@ -0,0 +1,325 @@
+function resetStatus(){
+       showMsg("","green");
+}
+
+function showMsg(msg,color){
+     $("#node-validate-result").html(msg);
+     $("#node-validate-result")
+                               .css('color', '')
+                               .css('color', color);
+}
+
+function getAttributeValue(xmlStr,attribute){
+
+       var attrVal=null;
+       try{
+               if(xmlStr != null){
+                       var myRe = new RegExp(attribute + "[\s+]?=[\s+]?['\"]([^'\"]+)['\"]","m");
+                       var myArray = myRe.exec(xmlStr);
+                       if(myArray != null && myArray[1] != null){
+                               attrVal=myArray[1];
+                       }
+               }
+       }catch(err){
+               console.log(err);
+       }
+       return attrVal;
+}
+
+
+var resp = true;
+var processedNode = "";
+var errList=[];
+var elementCount=0;
+function processNode(xmlNode){
+       if(xmlNode == null) return;
+       if(xmlNode.nodeName != "parsererror" && xmlNode.nodeName != "#text"){
+                       processedNode = xmlNode.nodeName;
+       }
+       //console.log("processedNode:" + processedNode);
+       switch(xmlNode.nodeType){
+               case 1:
+                       elementCount++;
+                       //ELEMENT_NODE
+                       //console.log(xmlNode.nodeName);
+                       //console.dir(xmlNode.nodeName);
+                       if(xmlNode.nodeName == "parsererror"){
+                               //var nearNode = xmlNode.previousSibling != null ?xmlNode.previousSibling.nodeName : xmlNode.parentNode.nodeName;
+                               console.log("Error parsing xml after node " + processedNode);
+                               var msg = "error parsing XML after element &lt;" + processedNode + "&gt; Element#" + elementCount;
+                               errList.push(msg);
+                               resp = false;
+                               return;
+                       }       
+                       processedNode = xmlNode.nodeName;
+                       var attrs = xmlNode.attributes;
+                       for(var i=0;i<attrs.length;i++){
+                               //console.log("Attribute:" + attrs[i].nodeName);
+                               //console.log("Value:" + attrs[i].value);
+                               if(attrs[i].nodeName != "value" && attrs[i].value == ""){
+                                       var msg="";
+                                       /*
+                                       var prevSibling = xmlNode.previousSibling;
+                                       if(prevSibling != null && prevSibling != undefined){
+                                               msg = "element &lt;" + xmlNode.nodeName  + "&gt; attribute '" + attrs[i].nodeName + "' is not set. Element#" + elementCount;
+                                       }else{
+                                               msg = "element &lt;" + xmlNode.nodeName  + "&gt; attribute '" + attrs[i].nodeName + "' is not set. Element#" + elementCount;
+                                       }
+                                       */
+                                       msg = "element &lt;" + xmlNode.nodeName  + "&gt; attribute '" + attrs[i].nodeName + "' is not set. Element#" + elementCount;
+                                       errList.push(msg);
+                                       //console.log("element <" +  xmlNode.nodeName + "> attribute '" + attrs[i].nodeName + "' is not set.Element#" + elementCount);
+                                       resp = false;
+                               }
+                       }
+                       var childNodes = xmlNode.childNodes;
+                       for(var k=0;k<childNodes.length;k++){
+                               processNode(childNodes[k]);
+                       }
+                       break;
+               case 2:
+                       //ATTRIBUTE_NODE
+                       //console.log(xmlNode.nodeName);
+                       break;
+               case 3:
+                       //TEXT_NODE
+                       //console.log(xmlNode.nodeValue);
+                       break;
+               case 4:
+                       //CDATA_SECTION_NODE
+                       console.log("CDATA_SECTION_NODE");
+                       break;
+               case 5:
+                       //ENTITY_REFERENCE_NODE
+                       console.log("ENTITY_REFERENCE_NODE");
+                       break;
+               case 6:
+                       //ENTITY_NODE
+                       console.log("ENTITY_NODE");
+                       break;
+               case 7:
+                       //PROCESSING_INSTRUCTION_NODE
+                       console.log("PROCESSING_INSTRUCTION_NODE");
+                       break;
+               case 8:
+                       //COMMENT_NODE
+                       console.log("COMMENT_NODE");
+                       break;
+               case 9:
+                       //DOCUMENT_NODE
+                       console.log("DOCUMENT_NODE");
+                       break;
+               case 10:
+                       //DOCUMENT_TYPE_NODE
+                       console.log("DOCUMENT_TYPE_NODE");
+                       break;
+               case 11:
+                       //DOCUMENT_TYPE_NODE
+                       console.log("DOCUMENT_FRAGMENT_NODE");
+                       break;
+               case 12:
+                       //NOTATION_NODE
+                       console.log("DOCUMENT_FRAGMENT_NODE");
+                       break;
+       }
+}
+
+function validateFinalXML(xmlStr){
+
+       //console.dir(RED);
+       processedNode="";
+       resp=true;
+       errList=[];
+       elementCount=0;
+       //console.log("In validateXML xmlStr:" + xmlStr);
+       if(xmlStr == null || xmlStr == "") return true;
+       xmlStr = xmlStr.trim();
+       try{
+               var xmlDoc;
+               if (window.DOMParser){
+                       try{
+                               var parser=new DOMParser();
+                               xmlDoc=parser.parseFromString(xmlStr,'text/xml');
+                               //console.log("Not IE");
+                               var n = xmlDoc.documentElement.nodeName;
+                               if(n == "html"){
+                                       resp=false;
+                                       console.log("Error parsing");
+                                       return resp;
+                               }
+                       }catch(e){
+                               console.log("Error parsing" +e);
+                               return false;
+                       }
+               }else{ 
+                       try{
+                               //console.log("IE");
+                               // code for IE
+                               xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
+                               xmlDoc.async=false;
+                               xmlDoc.loadXMLString(xmlStr); 
+                       }catch(e){
+                               console.log("Error parsing" +e);
+                               return false;
+                       }
+               } 
+
+               //console.dir(xmlDoc);
+               processNode(xmlDoc.documentElement);
+               
+               if(resp){
+                       console.log("Validation Successful");
+                       RED.notify("<strong>XML validation</strong>: SUCCESS","success");
+               }else{
+                       console.log("Errors found. ");
+                       RED.notify("<strong>XML validation</strong>: FAILED","error");
+               }
+       }catch(e){
+               console.log("error:" +e);
+               RED.notify("<strong>XML validation</strong>: FAILED","error");
+               resp=false;
+               return resp;
+       }
+       return resp;
+}
+
+function validateXML(xmlStr){
+
+       //console.dir(RED);
+       processedNode="";
+       resp=true;
+       errList=[];
+       elementCount=0;
+       //console.log("In validateXML xmlStr:" + xmlStr);
+        //var xmlStr = $("#node-input-xml-editor").text();
+       if(xmlStr == null || xmlStr == undefined){
+               xmlStr = $("#node-input-xml-editor").text();
+       }
+       if(xmlStr == undefined) return false;
+       //console.dir($("#node-input-xml-editor"));
+       //console.log("xmlStr:" +  xmlStr);
+       xmlStr = xmlStr.trim();
+       var startTag ;
+       var endTag ;
+       try{
+               var re = /^[0-9]+/;
+               xmlStr = xmlStr.replace(re,'');
+               var regex = /(<)([\w-]+)(.*)?/;
+               var match = regex.exec(xmlStr);
+               if(match != null){
+                       if(match[1] != undefined && match[2] != undefined){ 
+                               startTag = match[2];
+                       }
+               }else{
+                       resp=false;
+                       showMsg("startTag not found.","red");
+                       return resp;
+               }
+       }catch(e){
+               console.log(e);
+               return false;
+       }
+       //console.log(xmlStr);  
+       if(xmlStr == ""){
+               resp=false;
+               showMsg("XML not found","red");
+               return resp;
+       }
+       endTag = "</" + startTag + ">";
+
+       if(xmlStr.indexOf(endTag) != -1){
+               resp=false;
+               showMsg("Error: End tag &lt;/" + startTag + "&gt; must not be included.","red");
+               console.log("End tag " + endTag + " must not be included.");
+               return resp;
+       }
+       try{
+               //var xmlTopStr = "<?xml version='1.0' encoding='UTF-8'?>\n" ;
+               //xmlStr = xmlTopStr + xmlStr;
+               //xmlStr = xmlStr.replace(/'/g,"\"");
+               xmlStr+= "\n" +  endTag;
+               xmlStr = xmlStr.trim();
+               //console.log("xmlStr:" + xmlStr);
+               var xmlDoc;
+               if (window.DOMParser){
+                       try{
+                               var parser=new DOMParser();
+                               xmlDoc=parser.parseFromString(xmlStr,'text/xml');
+                               //console.log("Not IE");
+                               var n = xmlDoc.documentElement.nodeName;
+                               if(n == "html"){
+                                       resp=false;
+                                       showMsg("Error parsing","red");
+                                       console.log("Error parsing");
+                                       return resp;
+                               }
+                       }catch(e){
+                               console.log("Error parsing" +e);
+                               return false;
+                       }
+               }else{ 
+                       try{
+                               //console.log("IE");
+                               // code for IE
+                               xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
+                               xmlDoc.async=false;
+                               xmlDoc.loadXMLString(xmlStr); 
+                       }catch(e){
+                               console.log("Error parsing" +e);
+                               return false;
+                       }
+               } 
+
+               //console.dir(xmlDoc);
+               processNode(xmlDoc.documentElement);
+               if(resp){
+                       showMsg("Validation Successful","green");
+               }else{
+                       showMsg("Errors found. <a onclick='javascript:showErrors()'>show errors</a>","red");
+                       console.log("Errors found. ");
+               }
+       }catch(e){
+               console.log("error:" +e);
+               showMsg(e,"red");
+               resp=false;
+               return resp;
+       }
+       return resp;
+}
+
+function showErrors() {
+                //var sourceField = event != null ?event.srcElement:event.target;
+                //console.dir(sourceField);
+                //sourceField.style.backgroundColor="skyblue";
+                //var leftVal = event.target.offsetLeft  ; 
+                //alert(topVal + ":" + leftVal);
+                /*left:leftVal,*/
+                //var pos = event.target;
+                //var topVal = event.target.offsetTop + topPosition ;
+                //var topVal = event.target.offsetTop +75;
+               var htmlStr="<div id='error-list-div'><table id='errTable' border='1'><tr><th>Error List</th></tr>";    
+               for(var i=0;errList != null && i<errList.length;i++){
+                       var errSeq = i+1;
+                       htmlStr += "<tr><td>" + errSeq + ")"  + errList[i] + "</td></tr>"; 
+               }
+               htmlStr += "</table></div>";
+               //var prevHtml = $("#tab-info").html();
+               //htmlStr += "<input type='button' value='Hide Errors' onclick=\"closeShowErrors('" + prevHtml + "')\" >";
+                //$('#show-errors-div').html(htmlStr);
+               //$("#tab-info").html(prevHtml + htmlStr);
+
+               //$('<div></div>').dialog({
+               $('#show-errors-dialog').dialog({
+                              modal: true,
+                              title: "XML Error List ",
+                              width: 500,
+                              open: function () {
+                                $(this).html(htmlStr);
+                              },
+                              buttons: {
+                                Close: function () {
+                                  $(this).dialog("close");
+                                }
+                              }
+                            }); // end dialog div
+}
diff --git a/dgbuilder/public/util/js/vkbeautify.0.99.00.beta.js b/dgbuilder/public/util/js/vkbeautify.0.99.00.beta.js
new file mode 100644 (file)
index 0000000..13cee3a
--- /dev/null
@@ -0,0 +1,358 @@
+/**
+* vkBeautify - javascript plugin to pretty-print or minify text in XML, JSON, CSS and SQL formats.
+*  
+* Version - 0.99.00.beta 
+* Copyright (c) 2012 Vadim Kiryukhin
+* vkiryukhin @ gmail.com
+* http://www.eslinstructor.net/vkbeautify/
+* 
+* Dual licensed under the MIT and GPL licenses:
+*   http://www.opensource.org/licenses/mit-license.php
+*   http://www.gnu.org/licenses/gpl.html
+*
+*   Pretty print
+*
+*        vkbeautify.xml(text [,indent_pattern]);
+*        vkbeautify.json(text [,indent_pattern]);
+*        vkbeautify.css(text [,indent_pattern]);
+*        vkbeautify.sql(text [,indent_pattern]);
+*
+*        @text - String; text to beatufy;
+*        @indent_pattern - Integer | String;
+*                Integer:  number of white spaces;
+*                String:   character string to visualize indentation ( can also be a set of white spaces )
+*   Minify
+*
+*        vkbeautify.xmlmin(text [,preserve_comments]);
+*        vkbeautify.jsonmin(text);
+*        vkbeautify.cssmin(text [,preserve_comments]);
+*        vkbeautify.sqlmin(text);
+*
+*        @text - String; text to minify;
+*        @preserve_comments - Bool; [optional];
+*                Set this flag to true to prevent removing comments from @text ( minxml and mincss functions only. )
+*
+*   Examples:
+*        vkbeautify.xml(text); // pretty print XML
+*        vkbeautify.json(text, 4 ); // pretty print JSON
+*        vkbeautify.css(text, '. . . .'); // pretty print CSS
+*        vkbeautify.sql(text, '----'); // pretty print SQL
+*
+*        vkbeautify.xmlmin(text, true);// minify XML, preserve comments
+*        vkbeautify.jsonmin(text);// minify JSON
+*        vkbeautify.cssmin(text);// minify CSS, remove comments ( default )
+*        vkbeautify.sqlmin(text);// minify SQL
+*
+*/
+
+(function() {
+
+function createShiftArr(step) {
+
+       var space = '    ';
+       
+       if ( isNaN(parseInt(step)) ) {  // argument is string
+               space = step;
+       } else { // argument is integer
+               switch(step) {
+                       case 1: space = ' '; break;
+                       case 2: space = '  '; break;
+                       case 3: space = '   '; break;
+                       case 4: space = '    '; break;
+                       case 5: space = '     '; break;
+                       case 6: space = '      '; break;
+                       case 7: space = '       '; break;
+                       case 8: space = '        '; break;
+                       case 9: space = '         '; break;
+                       case 10: space = '          '; break;
+                       case 11: space = '           '; break;
+                       case 12: space = '            '; break;
+               }
+       }
+
+       var shift = ['\n']; // array of shifts
+       for(ix=0;ix<100;ix++){
+               shift.push(shift[ix]+space); 
+       }
+       return shift;
+}
+
+function vkbeautify(){
+       this.step = '    '; // 4 spaces
+       this.shift = createShiftArr(this.step);
+};
+
+vkbeautify.prototype.xml = function(text,step) {
+
+       var ar = text.replace(/>\s{0,}</g,"><")
+                                .replace(/</g,"~::~<")
+                                .replace(/\s*xmlns\:/g,"~::~xmlns:")
+                                .replace(/\s*xmlns\=/g,"~::~xmlns=")
+                                .split('~::~'),
+               len = ar.length,
+               inComment = false,
+               deep = 0,
+               str = '',
+               ix = 0,
+               shift = step ? createShiftArr(step) : this.shift;
+
+               for(ix=0;ix<len;ix++) {
+                       // start comment or <![CDATA[...]]> or <!DOCTYPE //
+                       if(ar[ix].search(/<!/) > -1) { 
+                               str += shift[deep]+ar[ix];
+                               inComment = true; 
+                               // end comment  or <![CDATA[...]]> //
+                               if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1 ) { 
+                                       inComment = false; 
+                               }
+                       } else 
+                       // end comment  or <![CDATA[...]]> //
+                       if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) { 
+                               str += ar[ix];
+                               inComment = false; 
+                       } else 
+                       // <elm></elm> //
+                       if( /^<\w/.exec(ar[ix-1]) && /^<\/\w/.exec(ar[ix]) &&
+                               /^<[\w:\-\.\,]+/.exec(ar[ix-1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/','')) { 
+                               str += ar[ix];
+                               if(!inComment) deep--;
+                       } else
+                        // <elm> //
+                       if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1 ) {
+                               str = !inComment ? str += shift[deep++]+ar[ix] : str += ar[ix];
+                       } else 
+                        // <elm>...</elm> //
+                       if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) {
+                               str = !inComment ? str += shift[deep]+ar[ix] : str += ar[ix];
+                       } else 
+                       // </elm> //
+                       if(ar[ix].search(/<\//) > -1) { 
+                               str = !inComment ? str += shift[--deep]+ar[ix] : str += ar[ix];
+                       } else 
+                       // <elm/> //
+                       if(ar[ix].search(/\/>/) > -1 ) { 
+                               str = !inComment ? str += shift[deep]+ar[ix] : str += ar[ix];
+                       } else 
+                       // <? xml ... ?> //
+                       if(ar[ix].search(/<\?/) > -1) { 
+                               str += shift[deep]+ar[ix];
+                       } else 
+                       // xmlns //
+                       if( ar[ix].search(/xmlns\:/) > -1  || ar[ix].search(/xmlns\=/) > -1) { 
+                               str += shift[deep]+ar[ix];
+                       } 
+                       
+                       else {
+                               str += ar[ix];
+                       }
+               }
+               
+       return  (str[0] == '\n') ? str.slice(1) : str;
+}
+
+vkbeautify.prototype.json = function(text,step) {
+
+       var step = step ? step : this.step;
+       
+       if (typeof JSON === 'undefined' ) return text; 
+       
+       if ( typeof text === "string" ) return JSON.stringify(JSON.parse(text), null, step);
+       if ( typeof text === "object" ) return JSON.stringify(text, null, step);
+               
+       return text; // text is not string nor object
+}
+
+vkbeautify.prototype.css = function(text, step) {
+
+       var ar = text.replace(/\s{1,}/g,' ')
+                               .replace(/\{/g,"{~::~")
+                               .replace(/\}/g,"~::~}~::~")
+                               .replace(/\;/g,";~::~")
+                               .replace(/\/\*/g,"~::~/*")
+                               .replace(/\*\//g,"*/~::~")
+                               .replace(/~::~\s{0,}~::~/g,"~::~")
+                               .split('~::~'),
+               len = ar.length,
+               deep = 0,
+               str = '',
+               ix = 0,
+               shift = step ? createShiftArr(step) : this.shift;
+               
+               for(ix=0;ix<len;ix++) {
+
+                       if( /\{/.exec(ar[ix]))  { 
+                               str += shift[deep++]+ar[ix];
+                       } else 
+                       if( /\}/.exec(ar[ix]))  { 
+                               str += shift[--deep]+ar[ix];
+                       } else
+                       if( /\*\\/.exec(ar[ix]))  { 
+                               str += shift[deep]+ar[ix];
+                       }
+                       else {
+                               str += shift[deep]+ar[ix];
+                       }
+               }
+               return str.replace(/^\n{1,}/,'');
+}
+
+//----------------------------------------------------------------------------
+
+function isSubquery(str, parenthesisLevel) {
+       return  parenthesisLevel - (str.replace(/\(/g,'').length - str.replace(/\)/g,'').length )
+}
+
+function split_sql(str, tab) {
+
+       return str.replace(/\s{1,}/g," ")
+
+                               .replace(/ AND /ig,"~::~"+tab+tab+"AND ")
+                               .replace(/ BETWEEN /ig,"~::~"+tab+"BETWEEN ")
+                               .replace(/ CASE /ig,"~::~"+tab+"CASE ")
+                               .replace(/ ELSE /ig,"~::~"+tab+"ELSE ")
+                               .replace(/ END /ig,"~::~"+tab+"END ")
+                               .replace(/ FROM /ig,"~::~FROM ")
+                               .replace(/ GROUP\s{1,}BY/ig,"~::~GROUP BY ")
+                               .replace(/ HAVING /ig,"~::~HAVING ")
+                               //.replace(/ SET /ig," SET~::~")
+                               .replace(/ IN /ig," IN ")
+                               
+                               .replace(/ JOIN /ig,"~::~JOIN ")
+                               .replace(/ CROSS~::~{1,}JOIN /ig,"~::~CROSS JOIN ")
+                               .replace(/ INNER~::~{1,}JOIN /ig,"~::~INNER JOIN ")
+                               .replace(/ LEFT~::~{1,}JOIN /ig,"~::~LEFT JOIN ")
+                               .replace(/ RIGHT~::~{1,}JOIN /ig,"~::~RIGHT JOIN ")
+                               
+                               .replace(/ ON /ig,"~::~"+tab+"ON ")
+                               .replace(/ OR /ig,"~::~"+tab+tab+"OR ")
+                               .replace(/ ORDER\s{1,}BY/ig,"~::~ORDER BY ")
+                               .replace(/ OVER /ig,"~::~"+tab+"OVER ")
+
+                               .replace(/\(\s{0,}SELECT /ig,"~::~(SELECT ")
+                               .replace(/\)\s{0,}SELECT /ig,")~::~SELECT ")
+                               
+                               .replace(/ THEN /ig," THEN~::~"+tab+"")
+                               .replace(/ UNION /ig,"~::~UNION~::~")
+                               .replace(/ USING /ig,"~::~USING ")
+                               .replace(/ WHEN /ig,"~::~"+tab+"WHEN ")
+                               .replace(/ WHERE /ig,"~::~WHERE ")
+                               .replace(/ WITH /ig,"~::~WITH ")
+                               
+                               //.replace(/\,\s{0,}\(/ig,",~::~( ")
+                               //.replace(/\,/ig,",~::~"+tab+tab+"")
+
+                               .replace(/ ALL /ig," ALL ")
+                               .replace(/ AS /ig," AS ")
+                               .replace(/ ASC /ig," ASC ")     
+                               .replace(/ DESC /ig," DESC ")   
+                               .replace(/ DISTINCT /ig," DISTINCT ")
+                               .replace(/ EXISTS /ig," EXISTS ")
+                               .replace(/ NOT /ig," NOT ")
+                               .replace(/ NULL /ig," NULL ")
+                               .replace(/ LIKE /ig," LIKE ")
+                               .replace(/\s{0,}SELECT /ig,"SELECT ")
+                               .replace(/\s{0,}UPDATE /ig,"UPDATE ")
+                               .replace(/ SET /ig," SET ")
+                                                       
+                               .replace(/~::~{1,}/g,"~::~")
+                               .split('~::~');
+}
+
+vkbeautify.prototype.sql = function(text,step) {
+
+       var ar_by_quote = text.replace(/\s{1,}/g," ")
+                                                       .replace(/\'/ig,"~::~\'")
+                                                       .split('~::~'),
+               len = ar_by_quote.length,
+               ar = [],
+               deep = 0,
+               tab = this.step,//+this.step,
+               inComment = true,
+               inQuote = false,
+               parenthesisLevel = 0,
+               str = '',
+               ix = 0,
+               shift = step ? createShiftArr(step) : this.shift;;
+
+               for(ix=0;ix<len;ix++) {
+                       if(ix%2) {
+                               ar = ar.concat(ar_by_quote[ix]);
+                       } else {
+                               ar = ar.concat(split_sql(ar_by_quote[ix], tab) );
+                       }
+               }
+               
+               len = ar.length;
+               for(ix=0;ix<len;ix++) {
+                       
+                       parenthesisLevel = isSubquery(ar[ix], parenthesisLevel);
+                       
+                       if( /\s{0,}\s{0,}SELECT\s{0,}/.exec(ar[ix]))  { 
+                               ar[ix] = ar[ix].replace(/\,/g,",\n"+tab+tab+"")
+                       } 
+                       
+                       if( /\s{0,}\s{0,}SET\s{0,}/.exec(ar[ix]))  { 
+                               ar[ix] = ar[ix].replace(/\,/g,",\n"+tab+tab+"")
+                       } 
+                       
+                       if( /\s{0,}\(\s{0,}SELECT\s{0,}/.exec(ar[ix]))  { 
+                               deep++;
+                               str += shift[deep]+ar[ix];
+                       } else 
+                       if( /\'/.exec(ar[ix]) )  { 
+                               if(parenthesisLevel<1 && deep) {
+                                       deep--;
+                               }
+                               str += ar[ix];
+                       }
+                       else  { 
+                               str += shift[deep]+ar[ix];
+                               if(parenthesisLevel<1 && deep) {
+                                       deep--;
+                               }
+                       } 
+                       var junk = 0;
+               }
+
+               str = str.replace(/^\n{1,}/,'').replace(/\n{1,}/g,"\n");
+               return str;
+}
+
+
+vkbeautify.prototype.xmlmin = function(text, preserveComments) {
+
+       var str = preserveComments ? text
+                                                          : text.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g,"")
+                                                                        .replace(/[ \r\n\t]{1,}xmlns/g, ' xmlns');
+       return  str.replace(/>\s{0,}</g,"><"); 
+}
+
+vkbeautify.prototype.jsonmin = function(text) {
+
+       if (typeof JSON === 'undefined' ) return text; 
+       
+       return JSON.stringify(JSON.parse(text), null, 0); 
+                               
+}
+
+vkbeautify.prototype.cssmin = function(text, preserveComments) {
+       
+       var str = preserveComments ? text
+                                                          : text.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g,"") ;
+
+       return str.replace(/\s{1,}/g,' ')
+                         .replace(/\{\s{1,}/g,"{")
+                         .replace(/\}\s{1,}/g,"}")
+                         .replace(/\;\s{1,}/g,";")
+                         .replace(/\/\*\s{1,}/g,"/*")
+                         .replace(/\*\/\s{1,}/g,"*/");
+}
+
+vkbeautify.prototype.sqlmin = function(text) {
+       return text.replace(/\s{1,}/g," ").replace(/\s{1,}\(/,"(").replace(/\s{1,}\)/,")");
+}
+
+window.vkbeautify = new vkbeautify();
+
+})();
+
diff --git a/dgbuilder/red.js b/dgbuilder/red.js
new file mode 100644 (file)
index 0000000..14f6d38
--- /dev/null
@@ -0,0 +1,224 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var http = require('http');
+var https = require('https');
+var util = require("util");
+var express = require("express");
+var crypto = require("crypto");
+var nopt = require("nopt");
+var path = require("path");
+var RED = require("./red/red.js");
+
+var server;
+var app = express();
+
+var settingsFile = "./settings";
+var flowFile;
+
+var knownOpts = {
+    "settings":[path],
+    "v": Boolean,
+    "help": Boolean
+};
+var shortHands = {
+    "s":["--settings"],
+    "?":["--help"]
+};
+nopt.invalidHandler = function(k,v,t) {
+    // TODO: console.log(k,v,t);
+}
+
+var parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
+
+if (parsedArgs.help) {
+    console.log("Node-RED v"+RED.version());
+    console.log("Usage: node red.js [-v] [-?] [--settings settings.js] [flows.json]");
+    console.log("");
+    console.log("Options:");
+    console.log("  -s, --settings FILE  use specified settings file");
+    console.log("  -v                   enable verbose output");
+    console.log("  -?, --help           show usage");
+    console.log("");
+    console.log("Documentation can be found at http://nodered.org");
+    process.exit();
+}
+if (parsedArgs.argv.remain.length > 0) {
+    flowFile = parsedArgs.argv.remain[0];
+}
+
+if (parsedArgs.settings) {
+    settingsFile = parsedArgs.settings;
+}
+try {
+    var settings = require(settingsFile);
+} catch(err) {
+    if (err.code == 'MODULE_NOT_FOUND') {
+        console.log("Unable to load settings file "+settingsFile);
+    } else {
+        console.log(err);
+    }
+    process.exit();
+}
+
+if (parsedArgs.v) {
+    settings.verbose = true;
+}
+
+if (settings.https) {
+    server = https.createServer(settings.https,function(req,res){app(req,res);});
+} else {
+    server = http.createServer(function(req,res){app(req,res);});
+}
+server.setMaxListeners(0);
+
+function formatRoot(root) {
+    if (root[0] != "/") {
+        root = "/" + root;
+    }
+    if (root.slice(-1) != "/") {
+        root = root + "/";
+    }
+    return root;
+}
+
+if (settings.httpRoot === false) {
+    settings.httpAdminRoot = false;
+    settings.httpNodeRoot = false;
+} else {
+    settings.httpRoot = settings.httpRoot||"/";
+    settings.disableEditor = settings.disableEditor||false;
+}
+
+if (settings.httpAdminRoot !== false) {
+    settings.httpAdminRoot = formatRoot(settings.httpAdminRoot || settings.httpRoot || "/");
+    settings.httpAdminAuth = settings.httpAdminAuth || settings.httpAuth;
+} else {
+    settings.disableEditor = true;
+}
+
+if (settings.httpNodeRoot !== false) {
+    settings.httpNodeRoot = formatRoot(settings.httpNodeRoot || settings.httpRoot || "/");
+    settings.httpNodeAuth = settings.httpNodeAuth || settings.httpAuth;
+}
+
+settings.uiPort = settings.uiPort||1880;
+settings.uiHost = settings.uiHost||"0.0.0.0";
+var appDir = path.dirname(require.main.filename);
+if (settings.flowFile != null && settings.flowFile.indexOf(appDir) != -1){
+       settings.flowFile = flowFile || settings.flowFile;
+}else{
+       settings.flowFile = flowFile || appDir + "/" + settings.flowFile;
+}
+
+RED.init(server,settings);
+
+if (settings.httpAdminRoot !== false && settings.httpAdminAuth) {
+    app.use(settings.httpAdminRoot,
+        express.basicAuth(function(user, pass) {
+            return user === settings.httpAdminAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpAdminAuth.pass;
+        })
+    );
+}
+if (settings.httpNodeRoot !== false && settings.httpNodeAuth) {
+    app.use(settings.httpNodeRoot,
+        express.basicAuth(function(user, pass) {
+            return user === settings.httpNodeAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpNodeAuth.pass;
+        })
+    );
+}
+if (settings.httpAdminRoot !== false) {
+    app.use(settings.httpAdminRoot,RED.httpAdmin);
+}
+if (settings.httpNodeRoot !== false) {
+    app.use(settings.httpNodeRoot,RED.httpNode);
+}
+
+if (settings.httpStatic) {
+    settings.httpStaticAuth = settings.httpStaticAuth || settings.httpAuth;
+    if (settings.httpStaticAuth) {
+        app.use("/",
+            express.basicAuth(function(user, pass) {
+                return user === settings.httpStaticAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpStaticAuth.pass;
+            })
+        );
+    }
+    app.use("/",express.static(settings.httpStatic));
+}
+
+function getListenPath() {
+    var listenPath = 'http'+(settings.https?'s':'')+'://'+
+                    (settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+
+                    ':'+settings.uiPort;
+    if (settings.httpAdminRoot !== false) {
+        listenPath += settings.httpAdminRoot;
+    } else if (settings.httpStatic) {
+        listenPath += "/";
+    }
+    return listenPath;
+}
+
+RED.start().then(function() {
+    if (settings.httpAdminRoot !== false || settings.httpNodeRoot !== false || settings.httpStatic) {
+        server.on('error', function(err) {
+            if (err.errno === "EADDRINUSE") {
+                util.log('[red] Unable to listen on '+getListenPath());
+                util.log('[red] Error: port in use');
+            } else {
+                util.log('[red] Uncaught Exception:');
+                if (err.stack) {
+                    util.log(err.stack);
+                } else {
+                    util.log(err);
+                }
+            }
+            process.exit(1);
+        });
+        server.listen(settings.uiPort,settings.uiHost,function() {
+            if (settings.httpAdminRoot === false) {
+                util.log('[red] Admin UI disabled');
+            }
+            process.title = 'node-red';
+            util.log('[red] Server now running at '+getListenPath());
+        });
+    } else {
+        util.log('[red] Running in headless mode');
+    }
+}).otherwise(function(err) {
+    util.log("[red] Failed to start server:");
+    if (err.stack) {
+        util.log(err.stack);
+    } else {
+        util.log(err);
+    }
+});
+
+
+process.on('uncaughtException',function(err) {
+    util.log('[red] Uncaught Exception:');
+    if (err.stack) {
+        util.log(err.stack);
+    } else {
+        util.log(err);
+    }
+    process.exit(1);
+});
+
+process.on('SIGINT', function () {
+    RED.stop();
+    // TODO: need to allow nodes to close asynchronously before terminating the
+    // process - ie, promises 
+    process.exit();
+});
diff --git a/dgbuilder/red/cli/lib/config.js b/dgbuilder/red/cli/lib/config.js
new file mode 100644 (file)
index 0000000..3cd5244
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var path = require("path");
+var fs = require("fs");
+
+var userHome = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
+
+var configDir = path.join(userHome,".nodered");
+var configFile = path.join(configDir,"config.json");
+
+var config;
+
+function load() {
+    if (config == null) {
+        try {
+            config = JSON.parse(fs.readFileSync(configFile));
+        } catch(err) {
+            config = {};
+        }
+    }
+}
+
+function save() {
+    try {
+        fs.mkdirSync(configDir);
+    } catch(err) {
+        if (err.code != "EEXIST") {
+            throw err;
+        }
+    }
+    fs.writeFileSync(configFile,JSON.stringify(config,null,4));
+}
+module.exports = {
+    unload: function() {
+        config = null;
+    }
+};
+module.exports.__defineGetter__('target',function() { load(); return config.target|| "http://localhost:1880" });
+module.exports.__defineSetter__('target',function(v) { load(); config.target = v; save();});
diff --git a/dgbuilder/red/cli/lib/request.js b/dgbuilder/red/cli/lib/request.js
new file mode 100644 (file)
index 0000000..fbbe3dc
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var when = require("when");
+var request = require("request");
+var config = require("./config");
+
+module.exports = function(path, options) {
+    var basePath = config.target;
+    return when.promise(function(resolve,reject) {
+        options.headers = options.headers||{};
+        options.headers['Accept'] = 'application/json';
+        if (options.method == 'PUT' || options.method == "POST") {
+            options.headers['content-type'] = 'application/json';
+        }
+        options.url = basePath+path;
+        
+        // Pull out the request function so we can stub it in the tests
+        var requestFunc = request.get;
+        
+        if (options.method == 'PUT') {
+            requestFunc = request.put;
+        } else if (options.method == 'POST') {
+            requestFunc = request.post;
+        } else if (options.method == 'DELETE') {
+            requestFunc = request.del;
+        }
+        requestFunc(options, function(error,response,body) {
+            if (!error && response.statusCode == 200) {
+                resolve(JSON.parse(body));
+            } else if (error) {
+                reject(error.toString());
+            } else {
+                reject(response.statusCode+": "+body)
+            }
+        });
+    });
+}
diff --git a/dgbuilder/red/cli/nr-cli.js b/dgbuilder/red/cli/nr-cli.js
new file mode 100755 (executable)
index 0000000..6d62f05
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/env node
+;(function() {
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var util = require("util");
+var request = require("request");
+var colors = require('colors');
+var apiRequest = require("./lib/request");
+var config = require("./lib/config");
+
+var commands = {
+    "target": function() {
+        var target = process.argv[3];
+        if (target) {
+            if (!/^https?:\/\/.+/.test(target)) {
+                console.warn("Invalid target url");
+                return;
+            }
+            if (target.slice(-1) == "/") {
+                target = target.slice(0,target.length-1);
+            }
+            var oldTarget = config.target;
+            config.target = target;
+        } else {
+            console.log("Target: ".yellow+config.target);
+        }
+        
+    },
+    "nodes": function() {
+        apiRequest('/nodes',{}).then(logNodeList).otherwise(logFailure);
+    },
+    "node": function() {
+        apiRequest('/nodes/'+process.argv[3],{}).then(logNodeList).otherwise(logFailure);
+    },
+    "enable-node": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "PUT",
+            body: JSON.stringify({enabled:true})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "disable-node": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "PUT",
+            body: JSON.stringify({enabled:false})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "install": function() {
+        apiRequest('/nodes',{
+            method: "POST",
+            body: JSON.stringify({module:process.argv[3]})
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "remove": function() {
+        apiRequest('/nodes/'+process.argv[3],{
+            method: "DELETE"
+        }).then(logNodeList).otherwise(logFailure);
+    },
+    "search": function() {
+        var options = {
+            method: "GET",
+            url: 'https://registry.npmjs.org/-/_view/byKeyword?startkey=["node-red"]&amp;endkey=["node-red",{}]&amp;group_level=3' ,
+            headers: {
+                'Accept': 'application/json',
+            }
+        };
+        request(options, function (error, response, body) {
+            if (!error && response.statusCode == 200) {
+                var info = (JSON.parse(body)).rows;
+                var filter = null;
+                if (process.argv[3]) {
+                    filter = new RegExp(process.argv[3]);
+                }
+                for (var i=0;i<info.length;i++) {
+                    var n = info[i];
+                    if (!filter || filter.test(n.key[1]) || filter.test(n.key[2])) {
+                        console.log(n.key[1] + (" - "+ n.key[2]).grey);
+                    }
+                }
+            } else if (error) {
+                console.log(error.toString().red);
+            } else {
+                console.log((response.statusCode+": "+body).red);
+            }
+        });   
+    }
+}
+
+function logNodeList(nodes) {
+    if (!util.isArray(nodes)) {
+        nodes = [nodes];
+    }
+    for (var i=0;i<nodes.length;i++) {
+        var n = nodes[i];
+        console.log(formatNodeInfo(n))
+    }
+}
+
+function logFailure(msg) {
+    console.log(msg.red);
+}
+
+function formatBoolean(v,c) {
+    if (v) {
+        return ("["+c+"]");
+    } else {
+        return ("[ ]");
+    }
+}
+
+function formatNodeInfo(n) {
+    var inError = n.hasOwnProperty("err");
+    
+    var str = formatBoolean(n.enabled,"X")+formatBoolean(n.loaded,"L")+" ";
+    str += n.id;
+    if (n.enabled && n.loaded) {
+        str = str.green;
+    } else if (n.enabled && n.err) {
+        str = str.red;
+    } else {
+        str = str.yellow;
+    }
+    if (n.module) {
+        str += " ["+n.module+"]";
+    }
+    str += " "+n.types.join(", ");
+    if (n.err) {
+        str+=" "+n.err.red;
+    }
+    return str;
+}
+
+if (commands[process.argv[2]]) {
+    commands[process.argv[2]].call();
+}
+
+
+})();
diff --git a/dgbuilder/red/comms.js b/dgbuilder/red/comms.js
new file mode 100644 (file)
index 0000000..5828c99
--- /dev/null
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var ws = require("ws");
+var util = require("util");
+
+var server;
+var settings;
+
+var wsServer;
+var activeConnections = [];
+
+var retained = {};
+
+var heartbeatTimer;
+var lastSentTime;
+
+
+function init(_server,_settings) {
+    server = _server;
+    settings = _settings;
+}
+
+function start() {
+
+    if (!settings.disableEditor) {
+        var webSocketKeepAliveTime = settings.webSocketKeepAliveTime || 15000;
+        var path = settings.httpAdminRoot || "/";
+        path = path + (path.slice(-1) == "/" ? "":"/") + "comms";
+        wsServer = new ws.Server({server:server,path:path});
+        
+        wsServer.on('connection',function(ws) {
+            activeConnections.push(ws);
+            ws.on('close',function() {
+                for (var i=0;i<activeConnections.length;i++) {
+                    if (activeConnections[i] === ws) {
+                        activeConnections.splice(i,1);
+                        break;
+                    }
+                }
+            });
+            ws.on('message', function(data,flags) {
+                var msg = null;
+                try {
+                    msg = JSON.parse(data);
+                } catch(err) {
+                    util.log("[red:comms] received malformed message : "+err.toString());
+                    return;
+                }
+                if (msg.subscribe) {
+                    handleRemoteSubscription(ws,msg.subscribe);
+                }
+            });
+            ws.on('error', function(err) {
+                util.log("[red:comms] error : "+err.toString());
+            });
+        });
+        
+        wsServer.on('error', function(err) {
+            util.log("[red:comms] server error : "+err.toString());
+        });
+         
+        lastSentTime = Date.now();
+        
+        heartbeatTimer = setInterval(function() {
+            var now = Date.now();
+            if (now-lastSentTime > webSocketKeepAliveTime) {
+                publish("hb",lastSentTime);
+            }
+        }, webSocketKeepAliveTime);
+    }
+}
+
+function stop() {
+    if (heartbeatTimer) {
+        clearInterval(heartbeatTimer);
+    }
+    if (wsServer) {
+        wsServer.close();
+    }
+}
+
+function publish(topic,data,retain) {
+    if (retain) {
+        retained[topic] = data;
+    } else {
+        delete retained[topic];
+    }
+    lastSentTime = Date.now();
+    activeConnections.forEach(function(conn) {
+        publishTo(conn,topic,data);
+    });
+}
+
+function publishTo(ws,topic,data) {
+    var msg = JSON.stringify({topic:topic,data:data});
+    try {
+        ws.send(msg);
+    } catch(err) {
+        util.log("[red:comms] send error : "+err.toString());
+    }
+}
+
+function handleRemoteSubscription(ws,topic) {
+    var re = new RegExp("^"+topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
+    for (var t in retained) {
+        if (re.test(t)) {
+            publishTo(ws,t,retained[t]);
+        }
+    }
+}
+
+
+module.exports = {
+    init:init,
+    start:start,
+    stop:stop,
+    publish:publish,
+}
diff --git a/dgbuilder/red/events.js b/dgbuilder/red/events.js
new file mode 100644 (file)
index 0000000..8959049
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var events = require("events"); 
+
+module.exports = new events.EventEmitter(); 
diff --git a/dgbuilder/red/library.js b/dgbuilder/red/library.js
new file mode 100644 (file)
index 0000000..cc4199f
--- /dev/null
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+
+var redApp = null;
+var storage = null;
+
+function init() {
+    redApp = require("./server").app;
+    storage = require("./storage");
+    
+    // -------- Flow Library --------
+    redApp.post(new RegExp("/library/flows\/(.*)"), function(req,res) {
+            var fullBody = '';
+            req.on('data', function(chunk) {
+                fullBody += chunk.toString();
+            });
+            req.on('end', function() {
+                storage.saveFlow(req.params[0],fullBody).then(function() {
+                    res.send(204);
+                }).otherwise(function(err) {
+                    util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                    res.send(500);
+                });
+            });
+    });
+    
+    redApp.get("/library/flows",function(req,res) {
+            storage.getAllFlows().then(function(flows) {
+                res.json(flows);
+            });
+    });
+    
+    redApp.get(new RegExp("/library/flows\/(.*)"), function(req,res) {
+            storage.getFlow(req.params[0]).then(function(data) {
+                res.set('Content-Type', 'application/json');
+                res.send(data);
+            }).otherwise(function(err) {
+                if (err) {
+                    util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                }
+                res.send(404);
+            });
+    });
+    
+    // ------------------------------
+}    
+
+function createLibrary(type) {
+    
+    redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) {
+            var path = req.params[1]||"";
+            storage.getLibraryEntry(type,path).then(function(result) {
+                if (typeof result === "string") {
+                    res.writeHead(200, {'Content-Type': 'text/plain'});
+                    res.write(result);
+                    res.end(); 
+                } else {
+                    res.json(result);
+                }
+            }).otherwise(function(err) {
+                if (err) {
+                    util.log("[red] Error loading library entry '"+path+"' : "+err);
+                    if (err.message.indexOf('forbidden') === 0) {
+                        res.send(403);
+                        return;
+                    }
+                }
+                res.send(404);
+            });
+    });
+    
+    redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) {
+            var path = req.params[0];
+            var fullBody = '';
+            req.on('data', function(chunk) {
+                    fullBody += chunk.toString();
+            });
+            req.on('end', function() {
+                    storage.saveLibraryEntry(type,path,req.query,fullBody).then(function() {
+                        res.send(204);
+                    }).otherwise(function(err) {
+                        util.log("[red] Error saving library entry '"+path+"' : "+err);
+                        if (err.message.indexOf('forbidden') === 0) {
+                            res.send(403);
+                            return;
+                        }
+                        res.send(500);
+                    });
+            });
+    });
+}
+
+module.exports.init = init;
+module.exports.register = createLibrary;
diff --git a/dgbuilder/red/log.js b/dgbuilder/red/log.js
new file mode 100644 (file)
index 0000000..236e6df
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var EventEmitter = require("events").EventEmitter;
+
+var logHandlers = [];
+
+var ConsoleLogHandler = new EventEmitter();
+ConsoleLogHandler.on("log",function(msg) {
+        util.log("["+msg.level+"] ["+msg.type+":"+(msg.name||msg.id)+"] "+msg.msg);
+});
+
+var log = module.exports = {
+    addHandler: function(func) {
+        logHandlers.push(func);
+    },
+    
+    log: function(msg) {
+        logHandlers.forEach(function(handler) {
+            handler.emit("log",msg);
+        });
+    }
+}
+
+log.addHandler(ConsoleLogHandler);
diff --git a/dgbuilder/red/nodes/Node.js b/dgbuilder/red/nodes/Node.js
new file mode 100644 (file)
index 0000000..0e6fc52
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var EventEmitter = require("events").EventEmitter;
+var clone = require("clone");
+var when = require("when");
+
+var flows = require("./flows");
+var comms = require("../comms");
+
+function Node(n) {
+    this.id = n.id;
+    flows.add(this);
+    this.type = n.type;
+    if (n.name) {
+        this.name = n.name;
+    }
+    this.wires = n.wires||[];
+}
+
+util.inherits(Node,EventEmitter);
+
+Node.prototype._on = Node.prototype.on;
+
+Node.prototype.on = function(event,callback) {
+    var node = this;
+    if (event == "close") {
+        if (callback.length == 1) {
+            this.close = function() {
+                return when.promise(function(resolve) {
+                    callback.call(node,function() {
+                        resolve();
+                    });
+                });
+            }
+        } else {
+            this.close = callback;
+        }
+    } else {
+        this._on(event,callback);
+    }
+}
+
+Node.prototype.close = function() {
+}
+
+Node.prototype.send = function(msg) {
+    // instanceof doesn't work for some reason here
+    if (msg == null) {
+        return;
+    } else if (!util.isArray(msg)) {
+        msg = [msg];
+    }
+    for (var i=0;i<this.wires.length;i++) {
+        var wires = this.wires[i];
+        if (i < msg.length) {
+            if (msg[i] != null) {
+                var msgs = msg[i];
+                if (!util.isArray(msg[i])) {
+                    msgs = [msg[i]];
+                }
+                //if (wires.length == 1) {
+                //    // Single recipient, don't need to clone the message
+                //    var node = flows.get(wires[0]);
+                //    if (node) {
+                //        for (var k in msgs) {
+                //            var mm = msgs[k];
+                //            node.receive(mm);
+                //        }
+                //    }
+                //} else {
+                    // Multiple recipients, must send message copies
+                    for (var j=0;j<wires.length;j++) {
+                        var node = flows.get(wires[j]);
+                        if (node) {
+                            for (var k=0;k<msgs.length;k++) {
+                                var mm = msgs[k];
+                                // Temporary fix for #97
+                                // TODO: remove this http-node-specific fix somehow
+                                var req = mm.req;
+                                var res = mm.res;
+                                delete mm.req;
+                                delete mm.res;
+                                var m = clone(mm);
+                                if (req) {
+                                    m.req = req;
+                                    mm.req = req;
+                                }
+                                if (res) {
+                                    m.res = res;
+                                    mm.res = res;
+                                }
+                                node.receive(m);
+                            }
+                        }
+                    }
+                //}
+            }
+        }
+    }
+}
+
+Node.prototype.receive = function(msg) {
+    this.emit("input",msg);
+}
+
+function log_helper(self, level, msg) {
+    var o = {level:level, id:self.id, type:self.type, msg:msg};
+    if (self.name) {
+        o.name = self.name;
+    }
+    self.emit("log",o);
+}
+
+Node.prototype.log = function(msg) {
+    log_helper(this, 'log', msg);
+}
+
+Node.prototype.warn = function(msg) {
+    log_helper(this, 'warn', msg);
+}
+
+Node.prototype.error = function(msg) {
+    log_helper(this, 'error', msg);
+}
+
+/**
+ * status: { fill:"red|green", shape:"dot|ring", text:"blah" }
+ */
+Node.prototype.status = function(status) {
+    comms.publish("status/"+this.id,status,true);
+}
+module.exports = Node;
diff --git a/dgbuilder/red/nodes/credentials.js b/dgbuilder/red/nodes/credentials.js
new file mode 100644 (file)
index 0000000..22e78d8
--- /dev/null
@@ -0,0 +1,208 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var when = require("when");
+
+var credentialCache = {};
+var storage = null;
+var credentialsDef = {};
+var redApp = null;
+
+/**
+ * Adds an HTTP endpoint to allow look up of credentials for a given node id.
+ */
+function registerEndpoint(type) {
+    redApp.get('/credentials/' + type + '/:id', function (req, res) {
+        // TODO: This could be a generic endpoint with the type value
+        //       parameterised.
+        //
+        // TODO: It should verify the given node id is of the type specified -
+        //       but that would add a dependency from this module to the
+        //       registry module that knows about node types.
+        var nodeType = type;
+        var nodeID = req.params.id;
+
+        var credentials = credentialCache[nodeID];
+        if (credentials === undefined) {
+            res.json({});
+            return;
+        }
+        var definition = credentialsDef[nodeType];
+
+        var sendCredentials = {};
+        for (var cred in definition) {
+            if (definition.hasOwnProperty(cred)) {
+                if (definition[cred].type == "password") {
+                    var key = 'has_' + cred;
+                    sendCredentials[key] = credentials[cred] != null && credentials[cred] !== '';
+                    continue;
+                }
+                sendCredentials[cred] = credentials[cred] || '';
+            }
+        }
+        res.json(sendCredentials);
+
+    });
+}
+
+
+module.exports = {
+    init: function (_storage) {
+        storage = _storage;
+        // TODO: this should get passed in init function call rather than
+        //       required directly.
+        redApp = require("../server").app;
+    },
+    
+    /**
+     * Loads the credentials from storage.
+     */
+    load: function () {
+        return storage.getCredentials().then(function (creds) {
+            credentialCache = creds;
+        }).otherwise(function (err) {
+            util.log("[red] Error loading credentials : " + err);
+        });
+    },
+    
+    /**
+     * Adds a set of credentials for the given node id.
+     * @param id the node id for the credentials
+     * @param creds an object of credential key/value pairs
+     * @return a promise for the saving of credentials to storage
+     */
+    add: function (id, creds) {
+        credentialCache[id] = creds;
+        return storage.saveCredentials(credentialCache);
+    },
+
+    /**
+     * Gets the credentials for the given node id.
+     * @param id the node id for the credentials
+     * @return the credentials
+     */
+    get: function (id) {
+        return credentialCache[id];
+    },
+
+    /**
+     * Deletes the credentials for the given node id.
+     * @param id the node id for the credentials
+     * @return a promise for the saving of credentials to storage
+     */
+    delete: function (id) {
+        delete credentialCache[id];
+        storage.saveCredentials(credentialCache);
+    },
+
+    /**
+     * Deletes any credentials for nodes that no longer exist
+     * @param getNode a function that can return a node for a given id
+     * @return a promise for the saving of credentials to storage
+     */
+    clean: function (getNode) {
+        var deletedCredentials = false;
+        for (var c in credentialCache) {
+            if (credentialCache.hasOwnProperty(c)) {
+                var n = getNode(c);
+                if (!n) {
+                    deletedCredentials = true;
+                    delete credentialCache[c];
+                }
+            }
+        }
+        if (deletedCredentials) {
+            return storage.saveCredentials(credentialCache);
+        } else {
+            return when.resolve();
+        }
+    },
+    
+    /**
+     * Registers a node credential definition.
+     * @param type the node type
+     * @param definition the credential definition
+     */
+    register: function (type, definition) {
+        var dashedType = type.replace(/\s+/g, '-');
+        credentialsDef[dashedType] = definition;
+        registerEndpoint(dashedType);
+    },
+    
+    /**
+     * Extracts and stores any credential updates in the provided node.
+     * The provided node may have a .credentials property that contains
+     * new credentials for the node.
+     * This function loops through the credentials in the definition for
+     * the node-type and applies any of the updates provided in the node.
+     * 
+     * This function does not save the credentials to disk as it is expected
+     * to be called multiple times when a new flow is deployed.
+     *
+     * @param node the node to extract credentials from
+     */
+    extract: function(node) {
+        var nodeID = node.id;
+        var nodeType = node.type;
+        var newCreds = node.credentials;
+        if (newCreds) {
+            var savedCredentials = credentialCache[nodeID] || {};
+            
+            var dashedType = nodeType.replace(/\s+/g, '-');
+            var definition = credentialsDef[dashedType];
+            
+            if (!definition) {
+                util.log('Credential Type ' + nodeType + ' is not registered.');
+                return;
+            }
+            
+            for (var cred in definition) {
+                if (definition.hasOwnProperty(cred)) {
+                    if (newCreds[cred] === undefined) {
+                        continue;
+                    }
+                    if (definition[cred].type == "password" && newCreds[cred] == '__PWRD__') {
+                        continue;
+                    }
+                    if (0 === newCreds[cred].length || /^\s*$/.test(newCreds[cred])) {
+                        delete savedCredentials[cred];
+                        continue;
+                    }
+                    savedCredentials[cred] = newCreds[cred];
+                }
+            }
+            credentialCache[nodeID] = savedCredentials;
+        }
+    },
+    
+    /**
+     * Saves the credentials to storage
+     * @return a promise for the saving of credentials to storage
+     */
+    save: function () {
+        return storage.saveCredentials(credentialCache);
+    },
+    
+    /**
+     * Gets the credential definition for the given node type
+     * @param type the node type
+     * @return the credential definition
+     */
+    getDefinition: function (type) {
+        return credentialsDef[type];
+    }
+}
diff --git a/dgbuilder/red/nodes/flows.js b/dgbuilder/red/nodes/flows.js
new file mode 100644 (file)
index 0000000..b0b5d51
--- /dev/null
@@ -0,0 +1,220 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var util = require("util");
+var when = require("when");
+
+var typeRegistry = require("./registry");
+var credentials = require("./credentials");
+var log = require("../log");
+var events = require("../events");
+
+var storage = null;
+
+var nodes = {};
+var activeConfig = [];
+var missingTypes = [];
+
+events.on('type-registered',function(type) {
+        if (missingTypes.length > 0) {
+            var i = missingTypes.indexOf(type);
+            if (i != -1) {
+                missingTypes.splice(i,1);
+                util.log("[red] Missing type registered: "+type);
+                if (missingTypes.length === 0) {
+                    parseConfig();
+                }
+            }
+        }
+});
+
+/**
+ * Parses the current activeConfig and creates the required node instances
+ */ 
+function parseConfig() {
+    var i;
+    var nt;
+    missingTypes = [];
+    
+    // Scan the configuration for any unknown node types
+    for (i=0;i<activeConfig.length;i++) {
+        var type = activeConfig[i].type;
+        // TODO: remove workspace in next release+1
+        if (type != "workspace" && type != "tab") {
+            nt = typeRegistry.get(type);
+            if (!nt && missingTypes.indexOf(type) == -1) {
+                missingTypes.push(type);
+            }
+        }
+    }
+    // Abort if there are any missing types
+    if (missingTypes.length > 0) {
+        util.log("[red] Waiting for missing types to be registered:");
+        for (i=0;i<missingTypes.length;i++) {
+            util.log("[red]  - "+missingTypes[i]);
+        }
+        return;
+    }
+
+    util.log("[red] Starting flows");
+    events.emit("nodes-starting");
+    
+    // Instantiate each node in the flow
+    for (i=0;i<activeConfig.length;i++) {
+        var nn = null;
+        // TODO: remove workspace in next release+1
+        if (activeConfig[i].type != "workspace" && activeConfig[i].type != "tab") {
+            nt = typeRegistry.get(activeConfig[i].type);
+            if (nt) {
+                try {
+                    nn = new nt(activeConfig[i]);
+                }
+                catch (err) {
+                    util.log("[red] "+activeConfig[i].type+" : "+err);
+                }
+            }
+            // console.log(nn);
+            if (nn === null) {
+                util.log("[red] unknown type: "+activeConfig[i].type);
+            }
+        }
+    }
+    // Clean up any orphaned credentials
+    credentials.clean(flowNodes.get);
+    events.emit("nodes-started");
+}
+
+/**
+ * Stops the current activeConfig
+ */
+function stopFlows() {
+    if (activeConfig&&activeConfig.length > 0) {
+        util.log("[red] Stopping flows");
+    }
+    return flowNodes.clear();
+}
+
+var flowNodes = module.exports = {
+    init: function(_storage) {
+        storage = _storage;
+    },
+    
+    /**
+     * Load the current activeConfig from storage and start it running
+     * @return a promise for the loading of the config
+     */
+    load: function() {
+        return storage.getFlows().then(function(flows) {
+            return credentials.load().then(function() {
+                activeConfig = flows;
+                if (activeConfig && activeConfig.length > 0) {
+                    parseConfig();
+                }
+            });
+        }).otherwise(function(err) {
+            util.log("[red] Error loading flows : "+err);
+        });
+    },
+    
+    /**
+     * Add a node to the current active set
+     * @param n the node to add
+     */
+    add: function(n) {
+        nodes[n.id] = n;
+        n.on("log",log.log);
+    },
+    
+    /**
+     * Get a node
+     * @param i the node id
+     * @return the node
+     */
+    get: function(i) {
+        return nodes[i];
+    },
+    
+    /**
+     * Stops all active nodes and clears the active set
+     * @return a promise for the stopping of all active nodes
+     */
+    clear: function() {
+        return when.promise(function(resolve) {
+            events.emit("nodes-stopping");
+            var promises = [];
+            for (var n in nodes) {
+                if (nodes.hasOwnProperty(n)) {
+                    try {
+                        var p = nodes[n].close();
+                        if (p) {
+                            promises.push(p);
+                        }
+                    } catch(err) {
+                        nodes[n].error(err);
+                    }
+                }
+            }
+            when.settle(promises).then(function() {
+                events.emit("nodes-stopped");
+                nodes = {};
+                resolve();
+            });
+        });
+    },
+    
+    /**
+     * Provides an iterator over the active set of nodes
+     * @param cb a function to be called for each node in the active set
+     */
+    each: function(cb) {
+        for (var n in nodes) {
+            if (nodes.hasOwnProperty(n)) {
+                cb(nodes[n]);
+            }
+        }
+    },
+
+    /**
+     * @return the active configuration
+     */
+    getFlows: function() {
+        return activeConfig;
+    },
+    
+    /**
+     * Sets the current active config.
+     * @param config the configuration to enable
+     * @return a promise for the starting of the new flow
+     */
+    setFlows: function (config) {
+        // Extract any credential updates
+        for (var i=0; i<config.length; i++) {
+            var node = config[i];
+            if (node.credentials) {
+                credentials.extract(node);
+                delete node.credentials;
+            }
+        }
+        return credentials.save()
+            .then(function() { return storage.saveFlows(config);})
+            .then(function() { return stopFlows();})
+            .then(function () {
+                activeConfig = config;
+                parseConfig();
+            });
+    },
+    stopFlows: stopFlows
+};
diff --git a/dgbuilder/red/nodes/index.js b/dgbuilder/red/nodes/index.js
new file mode 100644 (file)
index 0000000..3d5ad71
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var registry = require("./registry");
+var credentials = require("./credentials");
+var flows = require("./flows");
+var Node = require("./Node");
+
+/**
+ * Registers a node constructor
+ * @param type - the string type name
+ * @param constructor - the constructor function for this node type
+ * @param opts - optional additional options for the node
+ */
+function registerType(type,constructor,opts) {
+    if (opts && opts.credentials) {
+        credentials.register(type,opts.credentials);
+    }
+    registry.registerType(type,constructor);    
+}
+
+/**
+ * Called from a Node's constructor function, invokes the super-class
+ * constructor and attaches any credentials to the node.
+ * @param node the node object being created
+ * @param def the instance definition for the node 
+ */
+function createNode(node,def) {
+    Node.call(node,def);
+    var creds = credentials.get(node.id);
+    if (creds) {
+        node.credentials = creds;
+    }
+}
+
+function init(_settings,storage) {
+    credentials.init(storage);
+    flows.init(storage);
+    registry.init(_settings);
+}
+
+function checkTypeInUse(id) {
+    var nodeInfo = registry.getNodeInfo(id);
+    if (!nodeInfo) {
+        throw new Error("Unrecognised id: "+info);
+    }
+    var inUse = {};
+    flows.each(function(n) {
+        inUse[n.type] = (inUse[n.type]||0)+1;
+    });
+    var nodesInUse = [];
+    nodeInfo.types.forEach(function(t) {
+        if (inUse[t]) {
+            nodesInUse.push(t);
+        }
+    });
+    if (nodesInUse.length > 0) {
+        var msg = nodesInUse.join(", ");
+        throw new Error("Type in use: "+msg);
+    }
+}
+
+function removeNode(id) {
+    checkTypeInUse(id);
+    return registry.removeNode(id);
+}
+
+function removeModule(module) {
+    var info = registry.getNodeModuleInfo(module);
+    for (var i=0;i<info.nodes.length;i++) {
+        checkTypeInUse(info.nodes[i]);
+    }
+    return registry.removeModule(module);
+}
+
+
+function disableNode(id) {
+    checkTypeInUse(id);
+    return registry.disableNode(id);
+}
+
+module.exports = {
+    // Lifecycle
+    init: init,
+    load: registry.load,
+    
+    // Node registry
+    createNode: createNode,
+    getNode: flows.get,
+    
+    addNode: registry.addNode,
+    removeNode: removeNode,
+    
+    addModule: registry.addModule,
+    removeModule: removeModule,
+    
+    enableNode: registry.enableNode,
+    disableNode: disableNode,
+    
+    // Node type registry
+    registerType: registerType,
+    getType: registry.get,
+    getNodeInfo: registry.getNodeInfo,
+    getNodeModuleInfo: registry.getNodeModuleInfo,
+    getNodeList: registry.getNodeList,
+    getNodeConfigs: registry.getNodeConfigs,
+    getNodeConfig: registry.getNodeConfig,
+    clearRegistry: registry.clear,
+    cleanNodeList: registry.cleanNodeList,
+    
+    // Flow handling
+    loadFlows: flows.load,
+    stopFlows: flows.stopFlows,
+    setFlows: flows.setFlows,
+    getFlows: flows.getFlows,
+    
+    // Credentials
+    addCredentials: credentials.add,
+    getCredentials: credentials.get,
+    deleteCredentials: credentials.delete
+}
+
diff --git a/dgbuilder/red/nodes/registry.js b/dgbuilder/red/nodes/registry.js
new file mode 100644 (file)
index 0000000..f2073af
--- /dev/null
@@ -0,0 +1,693 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var util = require("util");
+var when = require("when");
+var whenNode = require('when/node');
+var fs = require("fs");
+var path = require("path");
+var crypto = require("crypto"); 
+var UglifyJS = require("uglify-js");
+
+var events = require("../events");
+
+var Node;
+var settings;
+
+function filterNodeInfo(n) {
+    var r = {
+        id: n.id,
+        name: n.name,
+        types: n.types,
+        enabled: n.enabled
+    }
+    if (n.hasOwnProperty("loaded")) {
+        r.loaded = n.loaded;
+    }
+    if (n.hasOwnProperty("module")) {
+        r.module = n.module;
+    }
+    if (n.hasOwnProperty("err")) {
+        r.err = n.err.toString();
+    }
+    return r;
+}
+
+var registry = (function() {
+    var nodeConfigCache = null;
+    var nodeConfigs = {};
+    var nodeList = [];
+    var nodeConstructors = {};
+    var nodeTypeToId = {};
+    var nodeModules = {};
+    
+    function saveNodeList() {
+        var nodeList = {};
+        
+        for (var i in nodeConfigs) {
+            if (nodeConfigs.hasOwnProperty(i)) {
+                var nodeConfig = nodeConfigs[i];
+                var n = filterNodeInfo(nodeConfig);
+                n.file = nodeConfig.file;
+                delete n.loaded;
+                delete n.err;
+                delete n.file;
+                delete n.id;
+                nodeList[i] = n;
+            }
+        }
+        if (settings.available()) {
+            return settings.set("nodes",nodeList);
+        } else {
+            return when.reject("Settings unavailable");
+        }
+    }
+    
+    return {
+        init: function() {
+            if (settings.available()) {
+                nodeConfigs = settings.get("nodes")||{};
+                // Restore the node id property to individual entries
+                for (var id in nodeConfigs) {
+                    if (nodeConfigs.hasOwnProperty(id)) {
+                        nodeConfigs[id].id = id;
+                    }
+                }
+            } else {
+                nodeConfigs = {};
+            }
+            nodeModules = {};
+            nodeTypeToId = {};
+            nodeConstructors = {};
+            nodeList = [];
+            nodeConfigCache = null;
+        },
+        
+        addNodeSet: function(id,set) {
+            if (!set.err) {
+                set.types.forEach(function(t) {
+                    nodeTypeToId[t] = id;
+                });
+            }
+            
+            if (set.module) {
+                nodeModules[set.module] = nodeModules[set.module]||{nodes:[]};
+                nodeModules[set.module].nodes.push(id);
+            }
+            
+            nodeConfigs[id] = set;
+            nodeList.push(id);
+            nodeConfigCache = null;
+        },
+        removeNode: function(id) {
+            var config = nodeConfigs[id];
+            if (!config) {
+                throw new Error("Unrecognised id: "+id);
+            }
+            delete nodeConfigs[id];
+            var i = nodeList.indexOf(id);
+            if (i > -1) {
+                nodeList.splice(i,1);
+            }
+            config.types.forEach(function(t) {
+                delete nodeConstructors[t];
+                delete nodeTypeToId[t];
+            });
+            config.enabled = false;
+            config.loaded = false;
+            nodeConfigCache = null;
+            return filterNodeInfo(config);
+        },
+        removeModule: function(module) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var nodes = nodeModules[module];
+            if (!nodes) {
+                throw new Error("Unrecognised module: "+module);
+            }
+            var infoList = [];
+            for (var i=0;i<nodes.nodes.length;i++) {
+                infoList.push(registry.removeNode(nodes.nodes[i]));
+            }
+            delete nodeModules[module];
+            saveNodeList();
+            return infoList;
+        },
+        getNodeInfo: function(typeOrId) {
+            if (nodeTypeToId[typeOrId]) {
+                return filterNodeInfo(nodeConfigs[nodeTypeToId[typeOrId]]);
+            } else if (nodeConfigs[typeOrId]) {
+                return filterNodeInfo(nodeConfigs[typeOrId]);
+            }
+            return null;
+        },
+        getNodeList: function() {
+            var list = [];
+            for (var id in nodeConfigs) {
+                if (nodeConfigs.hasOwnProperty(id)) {
+                    list.push(filterNodeInfo(nodeConfigs[id]))
+                }
+            }
+            return list;
+        },
+        registerNodeConstructor: function(type,constructor) {
+            if (nodeConstructors[type]) {
+                throw new Error(type+" already registered");
+            }
+            //TODO: Ensure type is known - but doing so will break some tests
+            //      that don't have a way to register a node template ahead
+            //      of registering the constructor
+            util.inherits(constructor,Node);
+            nodeConstructors[type] = constructor;
+            events.emit("type-registered",type);
+        },
+        
+        
+        /**
+         * Gets all of the node template configs
+         * @return all of the node templates in a single string
+         */
+        getAllNodeConfigs: function() {
+            if (!nodeConfigCache) {
+                var result = "";
+                var script = "";
+                for (var i=0;i<nodeList.length;i++) {
+                    var config = nodeConfigs[nodeList[i]];
+                    if (config.enabled && !config.err) {
+                        result += config.config;
+                        script += config.script;
+                    }
+                }
+                if (script.length > 0) {
+                    result += '<script type="text/javascript">';
+                    result += UglifyJS.minify(script, {fromString: true}).code;
+                    result += '</script>';
+                }
+                nodeConfigCache = result;
+            }
+            return nodeConfigCache;
+        },
+        
+        getNodeConfig: function(id) {
+            var config = nodeConfigs[id];
+            if (config) {
+                var result = config.config;
+                if (config.script) {
+                    result += '<script type="text/javascript">'+config.script+'</script>';
+                }
+                return result;
+            } else {
+                return null;
+            }
+        },
+        
+        getNodeConstructor: function(type) {
+            var config = nodeConfigs[nodeTypeToId[type]];
+            if (!config || (config.enabled && !config.err)) {
+                return nodeConstructors[type];
+            }
+            return null;
+        },
+        
+        clear: function() {
+            nodeConfigCache = null;
+            nodeConfigs = {};
+            nodeList = [];
+            nodeConstructors = {};
+            nodeTypeToId = {};
+        },
+        
+        getTypeId: function(type) {
+            return nodeTypeToId[type];
+        },
+        
+        getModuleInfo: function(type) {
+            return nodeModules[type];
+        },
+        
+        enableNodeSet: function(id) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var config = nodeConfigs[id];
+            if (config) {
+                delete config.err;
+                config.enabled = true;
+                if (!config.loaded) {
+                    // TODO: honour the promise this returns
+                    loadNodeModule(config);
+                }
+                nodeConfigCache = null;
+                saveNodeList();
+            } else {
+                throw new Error("Unrecognised id: "+id);
+            }
+            return filterNodeInfo(config);
+        },
+        
+        disableNodeSet: function(id) {
+            if (!settings.available()) {
+                throw new Error("Settings unavailable");
+            }
+            var config = nodeConfigs[id];
+            if (config) {
+                // TODO: persist setting
+                config.enabled = false;
+                nodeConfigCache = null;
+                saveNodeList();
+            } else {
+                throw new Error("Unrecognised id: "+id);
+            }
+            return filterNodeInfo(config);
+        },
+        
+        saveNodeList: saveNodeList,
+        
+        cleanNodeList: function() {
+            var removed = false;
+            for (var id in nodeConfigs) {
+                if (nodeConfigs.hasOwnProperty(id)) {
+                    if (nodeConfigs[id].module && !nodeModules[nodeConfigs[id].module]) {
+                        registry.removeNode(id);
+                        removed = true;
+                    }
+                }
+            }
+            if (removed) {
+                saveNodeList();
+            }
+        }
+    }
+})();
+
+
+
+function init(_settings) {
+    Node = require("./Node");
+    settings = _settings;
+    registry.init();
+}
+
+/**
+ * Synchronously walks the directory looking for node files.
+ * Emits 'node-icon-dir' events for an icon dirs found
+ * @param dir the directory to search
+ * @return an array of fully-qualified paths to .js files
+ */
+function getNodeFiles(dir) {
+    var result = [];
+    var files = [];
+    try {
+        files = fs.readdirSync(dir);
+    } catch(err) {
+        return result;
+    }
+    files.sort();
+    files.forEach(function(fn) {
+        var stats = fs.statSync(path.join(dir,fn));
+        if (stats.isFile()) {
+            if (/\.js$/.test(fn)) {
+                var valid = true;
+                if (settings.nodesExcludes) {
+                    for (var i=0;i<settings.nodesExcludes.length;i++) {
+                        if (settings.nodesExcludes[i] == fn) {
+                            valid = false;
+                            break;
+                        }
+                    }
+                }
+                valid = valid && fs.existsSync(path.join(dir,fn.replace(/\.js$/,".html")))
+                
+                if (valid) {
+                    result.push(path.join(dir,fn));
+                }
+            }
+        } else if (stats.isDirectory()) {
+            // Ignore /.dirs/, /lib/ /node_modules/ 
+            if (!/^(\..*|lib|icons|node_modules|test)$/.test(fn)) {
+                result = result.concat(getNodeFiles(path.join(dir,fn)));
+            } else if (fn === "icons") {
+                events.emit("node-icon-dir",path.join(dir,fn));
+            }
+        }
+    });
+    return result;
+}
+
+/**
+ * Scans the node_modules path for nodes
+ * @param moduleName the name of the module to be found
+ * @return a list of node modules: {dir,package}
+ */
+function scanTreeForNodesModules(moduleName) {
+    var dir = __dirname+"/../../nodes";
+    var results = [];
+    var up = path.resolve(path.join(dir,".."));
+    while (up !== dir) {
+        var pm = path.join(dir,"node_modules");
+        try {
+            var files = fs.readdirSync(pm);
+            for (var i=0;i<files.length;i++) {
+                var fn = files[i];
+                if (!registry.getModuleInfo(fn)) {
+                    if (!moduleName || fn == moduleName) {
+                        var pkgfn = path.join(pm,fn,"package.json");
+                        try {
+                            var pkg = require(pkgfn);
+                            if (pkg['node-red']) {
+                                var moduleDir = path.join(pm,fn);
+                                results.push({dir:moduleDir,package:pkg});
+                            }
+                        } catch(err) {
+                            if (err.code != "MODULE_NOT_FOUND") {
+                                // TODO: handle unexpected error
+                            }
+                        }
+                        if (fn == moduleName) {
+                            break;
+                        }
+                    }
+                }
+            }
+        } catch(err) {
+        }
+        
+        dir = up;
+        up = path.resolve(path.join(dir,".."));
+    }
+    return results;
+}
+
+/**
+ * Loads the nodes provided in an npm package.
+ * @param moduleDir the root directory of the package
+ * @param pkg the module's package.json object
+ */
+function loadNodesFromModule(moduleDir,pkg) {
+    var nodes = pkg['node-red'].nodes||{};
+    var results = [];
+    var iconDirs = [];
+    for (var n in nodes) {
+        if (nodes.hasOwnProperty(n)) {
+            var file = path.join(moduleDir,nodes[n]);
+            try {
+                results.push(loadNodeConfig(file,pkg.name,n));
+            } catch(err) {
+            }
+            var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons");
+            if (iconDirs.indexOf(iconDir) == -1) {
+                if (fs.existsSync(iconDir)) {
+                    events.emit("node-icon-dir",iconDir);
+                    iconDirs.push(iconDir);
+                }
+            }
+        }
+    }
+    return results;
+}
+
+
+/**
+ * Loads a node's configuration
+ * @param file the fully qualified path of the node's .js file
+ * @param name the name of the node
+ * @return the node object
+ *         {
+ *            id: a unqiue id for the node file
+ *            name: the name of the node file, or label from the npm module
+ *            file: the fully qualified path to the node's .js file
+ *            template: the fully qualified path to the node's .html file
+ *            config: the non-script parts of the node's .html file
+ *            script: the script part of the node's .html file
+ *            types: an array of node type names in this file
+ *         }
+ */
+function loadNodeConfig(file,module,name) {
+    var id = crypto.createHash('sha1').update(file).digest("hex");
+    if (module && name) {
+        var newid = crypto.createHash('sha1').update(module+":"+name).digest("hex");
+        var existingInfo = registry.getNodeInfo(id);
+        if (existingInfo) {
+            // For a brief period, id for modules were calculated incorrectly.
+            // To prevent false-duplicates, this removes the old id entry
+            registry.removeNode(id);
+            registry.saveNodeList();
+        }
+        id = newid;
+
+    }
+    var info = registry.getNodeInfo(id);
+    
+    var isEnabled = true;
+
+    if (info) {
+        if (info.hasOwnProperty("loaded")) {
+            throw new Error(file+" already loaded");
+        }
+        isEnabled = info.enabled;
+    }
+    
+    var node = {
+        id: id,
+        file: file,
+        template: file.replace(/\.js$/,".html"),
+        enabled: isEnabled,
+        loaded:false
+    }
+    
+    if (module) {
+        node.name = module+":"+name;
+        node.module = module;
+    } else {
+        node.name = path.basename(file)
+    }
+    try {
+        var content = fs.readFileSync(node.template,'utf8');
+        
+        var types = [];
+        
+        var regExp = /<script ([^>]*)data-template-name=['"]([^'"]*)['"]/gi;
+        var match = null;
+        
+        while((match = regExp.exec(content)) !== null) {
+            types.push(match[2]);
+        }
+        node.types = types;
+        node.config = content;
+        
+        // TODO: parse out the javascript portion of the template
+        node.script = "";
+        
+        for (var i=0;i<node.types.length;i++) {
+            if (registry.getTypeId(node.types[i])) {
+                node.err = node.types[i]+" already registered";
+                break;
+            }
+        }
+    } catch(err) {
+        node.types = [];
+        if (err.code === 'ENOENT') {
+            node.err = "Error: "+file+" does not exist";
+        } else {
+            node.err = err.toString();
+        }
+    }
+    registry.addNodeSet(id,node);
+    return node;
+}
+
+/**
+ * Loads all palette nodes
+ * @param defaultNodesDir optional parameter, when set, it overrides the default
+ *                        location of nodeFiles - used by the tests
+ * @return a promise that resolves on completion of loading
+ */
+function load(defaultNodesDir,disableNodePathScan) {
+    return when.promise(function(resolve,reject) {
+        // Find all of the nodes to load
+        var nodeFiles;
+        if(defaultNodesDir) {
+            nodeFiles = getNodeFiles(path.resolve(defaultNodesDir));
+        } else {
+            nodeFiles = getNodeFiles(__dirname+"/../../nodes");
+        }
+        
+        if (settings.nodesDir) {
+            var dir = settings.nodesDir;
+            if (typeof settings.nodesDir == "string") {
+                dir = [dir];
+            }
+            for (var i=0;i<dir.length;i++) {
+                nodeFiles = nodeFiles.concat(getNodeFiles(dir[i]));
+            }
+        }
+        var nodes = [];
+        nodeFiles.forEach(function(file) {
+            try {
+                nodes.push(loadNodeConfig(file));
+            } catch(err) {
+                // 
+            }
+        });
+        
+        // TODO: disabling npm module loading if defaultNodesDir set
+        //       This indicates a test is being run - don't want to pick up
+        //       unexpected nodes.
+        //       Urgh.
+        if (!disableNodePathScan) {
+            // Find all of the modules containing nodes
+            var moduleFiles = scanTreeForNodesModules();
+            moduleFiles.forEach(function(moduleFile) {
+                nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
+            });
+        }
+        var promises = [];
+        nodes.forEach(function(node) {
+            if (!node.err) {
+                promises.push(loadNodeModule(node));
+            }
+        });
+        
+        //resolve([]);
+        when.settle(promises).then(function(results) {
+            // Trigger a load of the configs to get it precached
+            registry.getAllNodeConfigs();
+            
+            if (settings.available()) {
+                resolve(registry.saveNodeList());
+            } else {
+                resolve();
+            }
+        }); 
+    });
+}
+
+/**
+ * Loads the specified node into the runtime
+ * @param node a node info object - see loadNodeConfig
+ * @return a promise that resolves to an update node info object. The object
+ *         has the following properties added:
+ *            err: any error encountered whilst loading the node
+ *            
+ */
+function loadNodeModule(node) {
+    var nodeDir = path.dirname(node.file);
+    var nodeFn = path.basename(node.file);
+    if (!node.enabled) {
+        return when.resolve(node);
+    }
+    try {
+        var loadPromise = null;
+        var r = require(node.file);
+        if (typeof r === "function") {
+            var promise = r(require('../red'));
+            if (promise != null && typeof promise.then === "function") {
+                loadPromise = promise.then(function() {
+                    node.enabled = true;
+                    node.loaded = true;
+                    return node;
+                }).otherwise(function(err) {
+                    node.err = err;
+                    return node;
+                });
+            }
+        }
+        if (loadPromise == null) {
+            node.enabled = true;
+            node.loaded = true;
+            loadPromise = when.resolve(node);
+        }
+        return loadPromise;
+    } catch(err) {
+        node.err = err;
+        return when.resolve(node);
+    }
+}
+
+function loadNodeList(nodes) {
+    var promises = [];
+    nodes.forEach(function(node) {
+        if (!node.err) {
+            promises.push(loadNodeModule(node));
+        } else {
+            promises.push(node);
+        }
+    });
+    
+    return when.settle(promises).then(function(results) {
+        return registry.saveNodeList().then(function() {
+            var list = results.map(function(r) {
+                return filterNodeInfo(r.value);
+            });
+            return list;
+        });
+    });
+}
+
+function addNode(file) {
+    if (!settings.available()) {
+        throw new Error("Settings unavailable");
+    }
+    var nodes = [];
+    try { 
+        nodes.push(loadNodeConfig(file));
+    } catch(err) {
+        return when.reject(err);
+    }
+    return loadNodeList(nodes);
+}
+
+function addModule(module) {
+    if (!settings.available()) {
+        throw new Error("Settings unavailable");
+    }
+    var nodes = [];
+    if (registry.getModuleInfo(module)) {
+        return when.reject(new Error("Module already loaded"));
+    }
+    var moduleFiles = scanTreeForNodesModules(module);
+    if (moduleFiles.length === 0) {
+        var err = new Error("Cannot find module '" + module + "'");
+        err.code = 'MODULE_NOT_FOUND';
+        return when.reject(err);
+    }
+    moduleFiles.forEach(function(moduleFile) {
+        nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package));
+    });
+    return loadNodeList(nodes);
+}
+
+module.exports = {
+    init:init,
+    load:load,
+    clear: registry.clear,
+    registerType: registry.registerNodeConstructor,
+    get: registry.getNodeConstructor,
+    getNodeInfo: registry.getNodeInfo,
+    getNodeModuleInfo: registry.getModuleInfo,
+    getNodeList: registry.getNodeList,
+    getNodeConfigs: registry.getAllNodeConfigs,
+    getNodeConfig: registry.getNodeConfig,
+    addNode: addNode,
+    removeNode: registry.removeNode,
+    enableNode: registry.enableNodeSet,
+    disableNode: registry.disableNodeSet,
+    
+    addModule: addModule,
+    removeModule: registry.removeModule,
+    cleanNodeList: registry.cleanNodeList
+}
diff --git a/dgbuilder/red/red.js b/dgbuilder/red/red.js
new file mode 100644 (file)
index 0000000..2735e0d
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var server = require("./server");
+var nodes = require("./nodes");
+var library = require("./library");
+var comms = require("./comms");
+var log = require("./log");
+var util = require("./util");
+var fs = require("fs");
+var settings = require("./settings");
+var credentials = require("./nodes/credentials");
+
+var path = require('path');
+
+process.env.NODE_RED_HOME = process.env.NODE_RED_HOME || path.resolve(__dirname+"/..");
+
+var events = require("events");
+
+var RED = {
+
+    init: function(httpServer,userSettings) {
+        userSettings.version = this.version();
+        settings.init(userSettings);
+        server.init(httpServer,settings);
+        library.init();
+        return server.app;
+    },
+    
+    start: server.start,
+    stop: server.stop,
+    nodes: nodes,
+    library: library,
+    credentials: credentials,
+    events: events,
+    log: log,
+    comms: comms,
+    settings:settings,
+    util: util,
+    version: function () {
+        var p = require(path.join(process.env.NODE_RED_HOME,"package.json"));
+        if (fs.existsSync(path.join(process.env.NODE_RED_HOME,".git"))) {
+            return p.version+".git";
+        } else {
+            return p.version;
+        }
+    }
+};
+
+RED.__defineGetter__("app", function() { console.log("Deprecated use of RED.app - use RED.httpAdmin instead"); return server.app });
+RED.__defineGetter__("httpAdmin", function() { return server.app });
+RED.__defineGetter__("httpNode", function() { return server.nodeApp });
+RED.__defineGetter__("server", function() { return server.server });
+
+module.exports = RED;
diff --git a/dgbuilder/red/server.js b/dgbuilder/red/server.js
new file mode 100644 (file)
index 0000000..91bee45
--- /dev/null
@@ -0,0 +1,1318 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var express = require('express');
+var util = require('util');
+var multer = require('multer');
+var when = require('when');
+var exec = require('child_process').exec;
+
+var createUI = require("./ui");
+var redNodes = require("./nodes");
+var comms = require("./comms");
+var storage = require("./storage");
+var fs=require('fs');
+var path = require("path");
+var app = null;
+var nodeApp = null;
+var server = null;
+var settings = null;
+
+var flowShareUsers = require("../flowShareUsers");
+       
+//console.dir(flowShareUsers);
+
+function createServer(_server,_settings) {
+    server = _server;
+    settings = _settings;
+
+    comms.init(_server,_settings);
+    
+    nodeApp = express();
+    app = express();
+        
+    if (settings.httpAdminRoot !== false) {
+        
+        
+        if (!settings.disableEditor) {
+            createUI(settings,app);
+        }
+        
+       var slaActions = require("./sla");
+
+        app.get("/flows",function(req,res) {
+            res.json(redNodes.getFlows());
+        });
+
+        app.get("/loadJSFiles",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var generatedJSDir=appDir + "/generatedJS";
+               var glob = require("glob")
+               glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+                         // files is an array of filenames.
+                        // If the `nonull` option is set, and nothing
+                       // was found, then files is ["**/*.js"]
+                       // er is an error object or null.
+                       //console.dir(files);
+                       var sliValuesObj =[];
+                       for(var i=0;files!= null && i<files.length;i++){
+                               var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+                               console.log("loading file " + f);
+                               try{
+                                       sliValuesObj.push(require(files[i]));
+                                       //console.dir(sliValuesObj);
+                               }catch(err){
+                                       console.log("Error:Could not load file " + files[i]);
+                               }
+                       }
+                       res.json({"sliValuesObj" : sliValuesObj});
+               });
+        });
+
+        app.get("/loadSelectedModules",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var generatedJSDir=appDir + "/generatedJS";
+               //console.dir(req);
+               var selectedModulesStr = req.query.selectedModules;
+               var selectedModules = [];
+               if(selectedModulesStr != undefined && selectedModulesStr != null){ 
+                       selectedModules = selectedModulesStr.split(",");                
+               }
+               console.log(selectedModules);
+               var loaded_modules = {"selected_modules" :selectedModules};
+               var file = userDir + "/selected_modules";
+               var content = "module.exports=\n" + JSON.stringify(loaded_modules);
+               try{
+                       fs.writeFileSync(file, content, 'utf8');
+               }catch(err){
+                       console.log("could not write to file " + file);
+               }
+               var sliValuesObj =[];
+               for(var i=0;selectedModules!= null && i<selectedModules.length;i++){
+                       var f = generatedJSDir + "/" + selectedModules[i] + "_inputs.js";
+                       try{
+                               delete require.cache[require.resolve(f)]
+                               require.resolve();
+                       }catch(err){
+                               console.log("error deleting loaded module " + f + " from cache");
+                       }
+                       //console.log("loading file " + f);
+                       try{
+                               sliValuesObj.push(require(f));
+                       }catch(err){
+                               console.log("Error:Could not load file " + f);
+                       }
+               }
+               //console.dir(sliValuesObj);
+               res.json({"sliValuesObj" : sliValuesObj});
+        });
+
+        app.get("/initialLoadSelectedModules",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var generatedJSDir=appDir + "/generatedJS";
+               var file = userDir + "/selected_modules";
+               var sliValuesObj =[];
+               var selected_modules = [];
+               var selectedModules;
+               try{
+                       selectedModules = require(file);        
+                       selected_modules=selectedModules["selected_modules"];
+                       //console.log("selected_modules are ");
+                       //console.dir(selected_modules);
+               }catch(err){
+                       console.log("Could not load the file " + file);
+               }
+               for(var i=0;selected_modules!= null && i<selected_modules.length;i++){
+                       var f = generatedJSDir + "/" + selected_modules[i] + "_inputs.js";
+                       console.log("loading file " + f);
+                       try{
+                               sliValuesObj.push(require(f));
+                       }catch(err){
+                               console.log("Error:Could not load file " + f);
+                       }
+               }
+               res.json({"sliValuesObj" : sliValuesObj});
+        });
+
+        app.get("/listAvailableModules",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var generatedJSDir=appDir + "/generatedJS";
+               var glob = require("glob")
+               var file = userDir + "/selected_modules";
+               var selected_modules = [];
+               var selectedModules;
+               try{
+                       delete require.cache[require.resolve(file)]
+                       require.resolve();
+               }catch(err){
+                       console.log("error deleting loaded module " + file + " from cache");
+               }
+               try{
+                       selectedModules = require(file);        
+                       selected_modules=selectedModules["selected_modules"];
+                       console.log("selected_modules are ");
+                       //console.dir(selected_modules);
+               }catch(err){
+                       console.log("Could not load the file " + file);
+               }
+               glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+                       var filesList =[];
+                       for(var i=0;files!= null && i<files.length;i++){
+                               var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+                               f = f.replace("_inputs.js","");
+                               if(selected_modules != undefined && selected_modules != null && selected_modules.indexOf(f) != -1){
+                                       filesList.push(f + ":checked");
+                               }else{
+                                       filesList.push(f + ":unchecked");
+                               }
+                       }
+                       res.json({"files" : filesList});
+               });
+        });
+
+        app.get("/listSLA",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+                slaActions.listSLA(jsonObj,req,res);
+        });
+
+        app.get("/listCurrentDGs",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+                slaActions.listCurrentDGs(jsonObj,req,res);
+        });
+
+        app.get("/activateDG",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+            slaActions.activateDG(jsonObj,req,res);
+        });
+
+        app.get("/deActivateDG",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+            slaActions.deActivateDG(jsonObj,req,res);
+        });
+
+        app.get("/deleteDG",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+            slaActions.deleteDG(jsonObj,req,res);
+        });
+
+        app.get("/getCurrentSettings",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               //console.log("userDir:" + userDir);
+               var settingsFile = userDir + "/customSettings.js"; 
+               var jsonObj = require(settingsFile);
+               res.json(jsonObj);
+        });
+
+        app.get("/getCommitsInfo", function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               //console.dir(req);
+                var filePath = req.query.filePath;
+                var fullFilePath = userDir + "/codecloud/" + filePath ;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitlog " + fullFilePath ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr});
+                       }else{
+                               res.send(500,{'error':error});
+                       }
+                       //console.log("stdout :" + stdout);
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                       }
+                       if(stdout){
+                               //console.log("output:" + stdout);
+                               res.send(200,{'stdout':stdout,'stderr':stderr});
+                       }
+               }
+               });
+       });
+
+        app.get("/importCodeCloudFlow",
+                function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir = appDir + "/" + settings.userDir;
+               //console.dir(req);
+                var commitId = req.query.commitId;
+                var filePath = req.query.filePath;
+                var fullFilePath = userDir + "/codecloud/" + filePath ;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitckout " + commitId + " " + fullFilePath ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,{maxBuffer: 1024 * 1024 * 16}, function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr});
+                       }else{
+                               res.send(500,{'error':error});
+                       }
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                       }
+                       if(stdout){
+                               //console.log("output:" + stdout);
+                               res.send(200,{'stdout':stdout,'stderr':stderr});
+                       }
+               }
+               });
+       });
+
+        app.get("/importGitLocalFlow",
+               function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var gitLocalRepository =  settings.gitLocalRepository;
+               //console.dir(req);
+                var filePath = req.query.filePath;
+                var fullFilePath = gitLocalRepository +"/" + filePath ;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec =  "cat " + fullFilePath ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,{maxBuffer: 1024 * 1024 * 16}, function (error,stdout,stderr){
+                if(error){
+                       console.log("Error occured:" + error);
+                       if(stderr){
+                               //console.log("stderr:" + stderr);
+                               res.send(500,{'error':error,'stderr':stderr});
+                       }else{
+                               res.send(500,{'error':error});
+                       }
+                }else{
+                       if(stderr){
+                               console.log("stderr:" + stderr);
+                       }
+                       if(stdout){
+                               //console.log("output:" + stdout);
+                               res.send(200,{'stdout':stdout,'stderr':stderr});
+                       }
+               }
+               });
+       });
+
+
+        app.get("/gitcheckout", function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var gitLocalRepository =  settings.gitLocalRepository;
+               //console.dir(req);
+                var branch = req.query.branch;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitcheckout " + gitLocalRepository + " " + branch ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"output":stderr});
+                                       }else{
+                                               res.json({"output":error});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               res.json({"output": stderr + " " + stdout});
+                                       }
+                               }
+                       });
+       });
+
+        app.get("/gitpull", function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var gitLocalRepository =  settings.gitLocalRepository;
+               //console.dir(req);
+                var branch = req.query.branch;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitpull " + gitLocalRepository ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"output":stderr});
+                                       }else{
+                                               res.json({"output":error});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               res.json({"output": stderr + " " + stdout});
+                                       }
+                               }
+                       });
+       });
+
+        app.get("/gitstatus", function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var gitLocalRepository =  settings.gitLocalRepository;
+               //console.dir(req);
+                var branch = req.query.branch;
+               //console.log("fullFilePath:" + fullFilePath);  
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitstatus " + gitLocalRepository ;
+               console.log("commandToExec:" + commandToExec);
+               var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"output":stderr});
+                                       }else{
+                                               res.json({"output":error});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               res.json({"output": stderr + " " + stdout});
+                                       }
+                               }
+                       });
+       });
+       
+        app.post("/getSharedFlow",
+            express.json(),
+            function(req,res) {
+               var qs = require('querystring');
+               var body = '';
+               req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end', function () {
+                       var post = qs.parse(body);
+                       //console.log("body:" + body);
+                       fs.readFile(post.filePath, 'utf8', function (err,data) {
+                               if (err) {
+                                       return console.log(err);
+                               }
+                               res.json(data);
+                               //console.log(data);
+                       });
+               //res.sendFile(body.filePath);
+               });
+        });
+        
+        app.post("/downloadYang",
+            express.json(),
+            function(req,res) {
+               var qs = require('querystring');
+               var body = '';
+               req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end', function () {
+                       var post = qs.parse(body);
+                       var fileName = post.fileName;
+                       var appDir = path.dirname(require.main.filename);
+                       var yangDir = appDir + "/yangFiles" ;
+                       var fullPathToFile = yangDir + "/" + fileName;
+                       res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+                       res.setHeader('Content-type', 'application/yang');
+                       res.download(fullPathToFile);
+               });
+        });
+
+       function writeToFile(fullPathToFileName,str){
+               try{
+                       fs.writeFileSync(fullPathToFileName,str);
+               }catch(e){
+                       console.log("Error:" + e);
+               }
+       }
+       function getCurrentDate(){
+               var d = new Date();
+               var mm = d.getMonth() + 1;
+               var dd =   d.getDate();
+               var yyyy = d.getYear() + 1900;
+               var hr = d.getHours();
+               var min = d.getMinutes();
+               var sec = d.getSeconds();
+               if(mm<10) mm = "0" + mm;
+               if(dd<10) dd = "0" + dd;
+               if(hr<10) hr = "0" + hr;
+               if(min<10) min = "0" + min;
+               if(sec<10) sec = "0" + sec;
+               var formatedValue = mm + "-" + dd + "-" + yyyy + "_" + hr + "" + min + "" + sec;
+               return formatedValue;
+       }
+
+
+        app.post("/downloadXml",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+               //console.log("Received request and processing:" + new Date());
+               var qs = require('querystring');
+               var body = '';
+               //var msecs1= Date.now();
+               req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end', function () {
+                       var appDir = path.dirname(require.main.filename);
+                       var xmlDir = appDir + "/" + settings.xmlPath;
+                       //var msecs2= Date.now();
+                       //console.log("Time taken to get request body:" + (msecs2 - msecs1));
+                       var msecs3= Date.now();
+                       var post = qs.parse(body);
+                       var msecs4= Date.now();
+                       //console.log("Time taken to parse body:" + (msecs4 - msecs3));
+                       var xml = post['flowXml'];
+                       //var pd = require('pretty-data').pd;
+                       //var formatted_xml = pd.xml(xml);
+                       var moduleName = post['moduleName'];
+                       var methodName = post['methodName'];
+                       if(moduleName == "" || methodName == ""){
+                               res.send({"ERROR":"ServiceLogic Module Name and method name are required."});
+                       }else{
+                               //var formatted_date = getCurrentDate();
+                               //var fileNameForServer=moduleName + "_" +methodName+ "_" +  formatted_date + ".xml";
+                               //var fileName=moduleName + "_method_" +methodName+ ".xml";
+                               var fileName=moduleName + "_" +methodName+ ".xml";
+                               var file = xmlDir + "/" + fileName;
+
+                               //var msecs2= Date.now();
+                               writeToFile(file,xml);
+                               //var msecs3= Date.now();
+                               //console.log("Time taken to write File:" + (msecs3 - msecs2));
+                               res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+                               res.setHeader('Content-type', 'text/xml');
+                               res.end(xml);
+                               //console.log("Response sent:" + new Date());
+                       }
+               });
+       });
+
+        app.post("/downloadJson",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+                       var appDir = path.dirname(require.main.filename);
+                       var sharedDir = appDir + "/" + settings.sharedDir;
+                       var qs = require('querystring');
+                       var body = '';
+                       req.on('data', function (data) {
+                               body += data;
+                       });
+                       req.on('end', function () {
+                               var post = qs.parse(body);
+                               var jsonStr = post['flowJson'];
+                               var moduleName = post['moduleName'];
+                               var methodName = post['methodName'];
+                               //console.log("jsonStr:" + jsonStr);
+                               if(moduleName == "" || methodName == ""){
+                                       res.send({"ERROR":"ServiceLogic Module Name and method name are required."});
+                               }else{
+                                       var formatted_date = getCurrentDate();
+                                       //console.log("moduleName:" + moduleName);
+                                       //console.log("methodName:" + methodName);
+
+                                       //var fileName=moduleName + "_method_" +methodName + ".json";
+                                       //var renameOldfileTo=moduleName + "_method_" +methodName+ "_" +  formatted_date + ".json";
+                                       var fileName=moduleName + "_" +methodName + ".json";
+                                       var renameOldfileTo=moduleName + "_" +methodName+ "_" +  formatted_date + ".json";
+                                       var file = sharedDir + "/" + fileName;
+                                       //console.log("fileName:" + fileName);
+                                       var renameFilePath = sharedDir + "/backups/" + renameOldfileTo;
+                                       //console.log("localfile:" + localfile);
+                                       fs.rename(file,renameFilePath, function (err) {
+                                               if(err){
+                                                       console.log('Error :' + err);
+                                               }
+                                               //write the newer version
+                                               writeToFile(file,jsonStr);
+                                               res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+                                               res.setHeader('Content-type', 'application/json');
+                                               //res.download(file);
+                                               res.end(jsonStr);
+                                       });
+                               }
+                       });
+       });
+
+        app.post("/flows",
+            express.json({'limit':'16mb'}),
+            function(req,res) {
+               //console.log("Processing Request");
+                var flows = req.body;
+                redNodes.setFlows(flows).then(function() {
+                    res.send(204);
+                }).otherwise(function(err) {
+                    util.log("[red] Error saving flows : "+err);
+                    res.send(500,err.message);
+                });
+            },
+            function(error,req,res,next) {
+                res.send(400,"Invalid Flow.  Error " + error);
+            }
+        );
+            
+        app.get("/nodes",function(req,res) {
+            if (req.get("accept") == "application/json") {
+                res.json(redNodes.getNodeList());
+            } else {
+                res.send(redNodes.getNodeConfigs());
+            }
+        });
+        
+        app.post("/nodes",
+            express.json(),
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var node = req.body;
+                var promise;
+                if (node.file) {
+                    promise = redNodes.addNode(node.file).then(reportAddedModules);
+                } else if (node.module) {
+                    var module = redNodes.getNodeModuleInfo(node.module);
+                    if (module) {
+                        res.send(400,"Module already loaded");
+                        return;
+                    }
+                    promise = installModule(node.module);
+                } else {
+                    res.send(400,"Invalid request");
+                    return;
+                }
+                promise.then(function(info) {
+                    res.json(info);
+                }).otherwise(function(err) {
+                    if (err.code === 404) {
+                        res.send(404);
+                    } else {
+                        res.send(400,err.toString());
+                    }
+                });
+            },
+            function(err,req,res,next) {
+                console.log(err.toString());
+                res.send(400,err);
+            }
+        );
+        
+        app.delete("/nodes/:id",
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var id = req.params.id;
+                var removedNodes = [];
+                try {
+                    var node = redNodes.getNodeInfo(id);
+                    var promise = null;
+                    if (!node) {
+                        var module = redNodes.getNodeModuleInfo(id);
+                        if (!module) {
+                            res.send(404);
+                            return;
+                        } else {
+                            promise = uninstallModule(id);
+                        }
+                    } else {
+                        promise = when.resolve([redNodes.removeNode(id)]).then(reportRemovedModules);
+                    }
+                    
+                    promise.then(function(removedNodes) {
+                        res.json(removedNodes);
+                    }).otherwise(function(err) {
+                        console.log(err.stack);
+                        res.send(400,err.toString());
+                    });
+                } catch(err) {
+                    res.send(400,err.toString());
+                }
+            },
+            function(err,req,res,next) {
+                res.send(400,err);
+            }
+        );
+        
+        app.get("/nodes/:id", function(req,res) {
+            var id = req.params.id;
+            var result = null;
+            if (req.get("accept") == "application/json") {
+                result = redNodes.getNodeInfo(id);
+            } else {
+                result = redNodes.getNodeConfig(id);
+            }
+            if (result) {
+                res.send(result);
+            } else {
+                res.send(404);
+            }
+        });
+        
+        app.put("/nodes/:id", 
+            express.json(),
+            function(req,res) {
+                if (!settings.available()) {
+                    res.send(400,new Error("Settings unavailable").toString());
+                    return;
+                }
+                var body = req.body;
+                if (!body.hasOwnProperty("enabled")) {
+                    res.send(400,"Invalid request");
+                    return;
+                }
+                try {
+                    var info;
+                    var id = req.params.id;
+                    var node = redNodes.getNodeInfo(id);
+                    if (!node) {
+                        res.send(404);
+                    } else if (!node.err && node.enabled === body.enabled) {
+                        res.json(node);
+                    } else {
+                        if (body.enabled) {
+                            info = redNodes.enableNode(id);
+                        } else {
+                            info = redNodes.disableNode(id);
+                        }
+                        if (info.enabled == body.enabled && !info.err) {
+                            comms.publish("node/"+(body.enabled?"enabled":"disabled"),info,false);
+                            util.log("[red] "+(body.enabled?"Enabled":"Disabled")+" node types:");
+                            for (var i=0;i<info.types.length;i++) {
+                                util.log("[red] - "+info.types[i]);
+                            }
+                        } else if (body.enabled && info.err) {
+                            util.log("[red] Failed to enable node:");
+                            util.log("[red] - "+info.name+" : "+info.err);
+                        }
+                        res.json(info);
+                    }
+                } catch(err) {
+                    res.send(400,err.toString());
+                }            
+            }
+        );
+        app.get("/getCodeCloudFlows",function(req,res) {
+               var userDir=settings.userDir;
+               var codeCloudDir=userDir + "/codecloud";
+               var glob = require("glob")
+               glob(codeCloudDir + "/**/*.json", null, function (er, files) {
+                         // files is an array of filenames.
+                        // If the `nonull` option is set, and nothing
+                       // was found, then files is ["**/*.js"]
+                       // er is an error object or null.
+                       //console.dir(files);
+                       var filesList =[];
+                       for(var i=0;files!= null && i<files.length;i++){
+                               var f = files[i].replace( new RegExp(codeCloudDir + "/", "g" ), "" );
+                               filesList.push(f);
+
+                       }
+                       res.json({"files" : filesList});
+               });
+        });
+
+        app.get("/getCurrentGitBranch",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir=settings.userDir;
+               var settingsFile = appDir + "/" +  userDir + "/customSettings.js"; 
+               //console.log("settingsFile:" + settingsFile);
+               var jsonObj = require(settingsFile);
+               var gitLocalRepository=jsonObj.gitLocalRepository;
+               if(gitLocalRepository == undefined || gitLocalRepository == null || gitLocalRepository == ''){
+                       res.json({"output" : "GIT_LOCAL_REPOSITORY_NOT_SET"});
+                       return;
+               }
+               var exec = require('child_process').exec;
+               var commandToExec = appDir + "/git_scripts/gitcurbranch " + gitLocalRepository ;
+                       console.log("commandToExec:" + commandToExec);
+                       var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"output":stderr});
+                                       }else{
+                                               res.json({"output":error});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               res.json({"output":stdout});
+                                       }
+                               }
+                       });
+                               
+       });
+
+        app.get("/getGitLocalFlows",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var userDir=settings.userDir;
+               var settingsFile = appDir + "/" +  userDir + "/customSettings.js"; 
+               //console.log("settingsFile:" + settingsFile);
+               var jsonObj = require(settingsFile);
+               var performGitPull = jsonObj.performGitPull;
+               if(performGitPull == undefined || performGitPull == null) {
+                       performGitPull="N";
+               }
+               var gitLocalRepository=jsonObj.gitLocalRepository;
+               if(gitLocalRepository == undefined || gitLocalRepository == null || gitLocalRepository == ''){
+                       res.json({"files" : ["GIT_LOCAL_REPOSITORY_NOT_SET"]});
+                       return;
+                               
+                  }
+
+               if(performGitPull == "Y"){      
+                       var exec = require('child_process').exec;
+                       var commandToExec = appDir + "/git_scripts/gitpull " + gitLocalRepository ;
+                       console.log("commandToExec:" + commandToExec);
+                       var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"files":[]});
+                                       }else{
+                                               res.json({"files":[]});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               var glob = require("glob")
+                                               glob(gitLocalRepository + "/**/*.json", null, function (er, files) {
+                                               // files is an array of filenames.
+                                               // If the `nonull` option is set, and nothing
+                                               // was found, then files is ["**/*.js"]
+                                               // er is an error object or null.
+                                               //console.dir(files);
+                                               var filesList =[];
+                                               for(var i=0;files!= null && i<files.length;i++){
+                                                       var f = files[i].replace( new RegExp(gitLocalRepository + "/", "g" ), "" );
+                                                       filesList.push(f);
+
+                                               }
+                                               res.json({"files" : filesList});
+                                               });
+                                       }
+                               }
+                       });
+               }else{//git pull not requested
+                       var glob = require("glob")
+                       glob(gitLocalRepository + "/**/*.json", null, function (er, files) {
+                       // files is an array of filenames.
+                       // If the `nonull` option is set, and nothing
+                       // was found, then files is ["**/*.js"]
+                       // er is an error object or null.
+                       //console.dir(files);
+                       var filesList =[];
+                       for(var i=0;files!= null && i<files.length;i++){
+                               var f = files[i].replace( new RegExp(gitLocalRepository + "/", "g" ), "" );
+                               filesList.push(f);
+
+                       }
+                       res.json({"files" : filesList});
+                       });
+               }
+       
+        });
+
+        app.get("/flowShareUsers",function(req,res) {
+            res.json(flowShareUsers);
+        });
+        app.get("/getRelease",function(req,res) {
+               var userDir = settings.userDir;
+               //var release = userDir.replace(/releases/g,"release");
+               res.json({"release" : userDir});
+        });
+        app.post("/getFiles/:id",function(req,res) {
+            var id = req.params.id;
+               //console.log("id:" + id);
+               var userDir=settings.userDir;
+               var flowDir= userDir + "/../" + id + "/flows/shared"; 
+               //console.log("flowDir:" + flowDir);
+               fs.readdir(flowDir,function(err, files){
+                       if(err){
+                               res.json({"files": []});
+                       }else{
+                               var onlyFilesArr =[];
+                               if(files != null && files.length>0){
+                                       files.sort(function(a,b){
+                                               //console.log("file1:" + a);    
+                                               //console.log("file2:" + b);    
+                                               var fileStat1=fs.statSync(flowDir+ "/" + a);    
+                                               var fileStat2=fs.statSync(flowDir+ "/" + b);    
+                                               if(fileStat1.mtime > fileStat2.mtime){
+                                                       return 1;
+                                               }else if(fileStat1.mtime < fileStat2.mtime){
+                                                       return -1;
+                                               }else{
+                                                       return 0;
+                                               }
+                                       });
+                                       for(var i=0;i<files.length;i++){
+                                               var fileStat=fs.statSync(flowDir+ "/" + files[i]);
+                                               if(fileStat.isFile()){
+                                                   onlyFilesArr.push({"filePath":flowDir+ "/" + files[i],"name":files[i]});
+                                               }
+                                       }
+                                       res.json(onlyFilesArr);
+                               }else{
+                                       res.json({"files": []});
+                               }
+                       }
+               });
+        });
+
+        app.post("/updateConfiguration",
+            express.json(),
+            function(req,res) {
+               var qs = require('querystring');
+               //console.log("Received the request:");
+               var body ="";
+                req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end',function(){
+                       var post = qs.parse(body);
+                       var dbHost = post["dbHost"];
+                       var dbPort = post["dbPort"];
+                       var dbName = post["dbName"];
+                       var dbUser = post["dbUser"];
+                       var dbPassword = post["dbPassword"];
+                       var gitLocalRepository = post["gitLocalRepository"];
+                       var performGitPull = post["performGitPull"];
+                       var appDir = path.dirname(require.main.filename);
+                       var userDir = appDir + "/" + settings.userDir;
+                       console.log("userDir:" + userDir);
+                       try{
+                               var settingsFile = userDir + "/customSettings.js"; 
+                               var jsonObj = require(settingsFile);
+                               jsonObj.flowFile = jsonObj.flowFile.replace(appDir + "/",'');
+                               jsonObj.dbHost = dbHost;
+                               jsonObj.dbPort = dbPort;
+                               jsonObj.dbName = dbName;
+                               jsonObj.dbUser = dbUser;
+                               jsonObj.dbPassword = dbPassword;
+                               jsonObj.gitLocalRepository = gitLocalRepository;
+                               jsonObj.performGitPull = performGitPull;
+                               var updatedSettings = jsonObj;
+
+                               var settingsStr= "module.exports=" + JSON.stringify(updatedSettings,null,4);
+                               //console.log("settingsStr:" + settingsStr);
+                               fs.writeFileSync(settingsFile,settingsStr);
+                               var svcLogicPropStr = "" ;
+                                       svcLogicPropStr += "org.onap.ccsdk.sli.dbtype=jdbc" + "\n";
+                                       svcLogicPropStr += "org.onap.ccsdk.sli.jdbc.url=jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName + "\n";
+                                       svcLogicPropStr += "org.onap.ccsdk.sli.jdbc.database=" + dbName + "\n";
+                                       svcLogicPropStr += "org.onap.ccsdk.sli.jdbc.user=" + dbUser  + "\n";
+                                       svcLogicPropStr += "org.onap.ccsdk.sli.jdbc.password=" + dbPassword;
+                               
+                               //create svclogic.properties file in the conf dir
+                               var svcPropFile = userDir + "/conf/svclogic.properties";
+                               fs.writeFileSync(svcPropFile,svcLogicPropStr);
+
+                               res.send({"status": "success"});
+                       }catch(e){
+                               console.log("Error:" + e);
+                               res.send({"status": "error"});
+                       }
+               });
+            }
+       );
+
+        app.post("/deleteYangFile",
+            express.json(),
+            function(req,res) {
+               var qs = require('querystring');
+               //console.log("Received the request:");
+               var body ="";
+                req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end',function(){
+                       var post = qs.parse(body);
+                       //console.dir(body);
+                       var fileName = post["fileName"];
+                       var appDir = path.dirname(require.main.filename);
+                       var yangFilePath = appDir + "/yangFiles/" + fileName;
+                       try{
+                               fs.unlinkSync(yangFilePath);
+                               res.send({"status" :"SUCCESS"});
+                       }catch(err){
+                               console.log("error" + err);
+                               res.send({"status" :"ERROR"});
+                       }
+                       //console.log("prevPassword:" + settings.httpAuth.pass );
+               });
+            }
+       );
+
+        app.post("/updatePassword",
+            express.json(),
+            function(req,res) {
+               var qs = require('querystring');
+               //console.log("Received the request:");
+               var body ="";
+                req.on('data', function (data) {
+                       body += data;
+               });
+               req.on('end',function(){
+                       var post = qs.parse(body);
+                       //console.dir(body);
+                       var password = post["password"];
+                       //console.log("prevPassword:" + settings.httpAuth.pass );
+                       //console.log("New password:" + password);
+                       var crypto = require("crypto");
+                       var cryptPasswd = crypto.createHash('md5').update(password,'utf8').digest('hex')
+                       var appDir = path.dirname(require.main.filename);
+                       var userDir = appDir + "/" + settings.userDir;
+                       //console.log("userDir:" + userDir);
+                       /*var newSettings = settings;
+                       newSettings.httpAuth.pass = cryptPasswd;
+                       var updatedSettings = JSON.stringify(settings,null,4);
+                       var settingsStr = "module.exports=" + updatedSettings;
+                       console.log(updatedSettings);
+                       */
+                       try{
+                               var settingsFile = userDir + "/customSettings.js"; 
+                               //console.log("settingsFile:" + settingsFile);
+                               //var buf = fs.readFileSync(settingsFile, "utf8");
+                               var jsonObj = require(settingsFile);
+                               //console.log("jsonObj:" + JSON.stringify(jsonObj));
+                               jsonObj.httpAuth.pass = cryptPasswd;
+                               jsonObj.httpAdminAuth.pass = cryptPasswd;
+                               jsonObj.httpNodeAuth.pass = cryptPasswd;
+                               jsonObj.flowFile = jsonObj.flowFile.replace(appDir + "/",'');
+                               var updatedSettings = jsonObj;
+                               /*
+                               delete updatedSettings.httpRoot;
+                               delete updatedSettings.disableEditor;
+                               delete updatedSettings.httpAdminRoot;
+                               delete updatedSettings.httpAdminAuth;
+                               delete updatedSettings.httpNodeRoot;
+                               delete updatedSettings.httpNodeAuth;
+                               delete updatedSettings.uiHost;
+                               delete updatedSettings.version;
+                               */
+                               var settingsStr= "module.exports=" + JSON.stringify(updatedSettings,null,4);
+                               //console.log("settingsStr:" + settingsStr);
+                               fs.writeFileSync(settingsFile,settingsStr);
+                               settings.httpAuth.pass = cryptPasswd;
+                               res.send({"status": "success"});
+                       }catch(e){
+                               console.log("Error:" + e);
+                               res.send({"status": "error"});
+                       }
+               });
+            }
+       );
+
+       var appDir = path.dirname(require.main.filename);
+       var yangDir = appDir + "/yangFiles" ;
+       var diskStorage =   multer.diskStorage({
+                       destination: function (req, file, callback) {
+                                               callback(null, yangDir);
+                       },
+                       filename: function (req, file, callback) {
+                               //callback(null, file.fieldname + '-' + Date.now());
+                               callback(null, file.originalname);
+                       }
+       });
+       var upload = multer({ storage : diskStorage}).single('yangFile');
+
+       app.post('/api/uploadyang',function(req,res){
+               upload(req,res,function(err) {
+                       if(err) {
+                               console.log(err);
+                               return res.end("Error uploading file." + err);
+                       }
+                       //console.dir(req);     
+                       var fileName = req.file.originalname;
+                       var yangFileFullPath =  appDir + "/yangFiles/" + fileName;
+                       console.log("yangFileFullPath:" + yangFileFullPath);
+                       var commandToExec =""; 
+                       if(fileName != null){
+                               var matchedArr = fileName.match(/.zip$/);
+                               if(matchedArr != null && matchedArr.length >0){
+                                       console.log("uploaded zip file" + fileName);
+                                       //commandToExec = appDir + "/tools/generate_props_from_yangs_zip.sh " + yangFileFullPath ;
+                                       commandToExec = appDir + "/tools/generate_props_from_yang.sh " + yangFileFullPath ;
+                               }else{
+                                       commandToExec = appDir + "/tools/generate_props_from_yang.sh " + yangFileFullPath ;
+                                       console.log("uploaded file" + fileName);
+                               }
+                       }
+                       var exec = require('child_process').exec;
+                       console.log("commandToExec:" + commandToExec);
+                       var child = exec(commandToExec ,function (error,stdout,stderr){
+                               if(error){
+                                       console.log("Error occured:" + error);
+                                       var msg = "File " + fileName + " could not be processed successfully.";
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                               res.json({"sliValuesObj" : [],"message":msg});
+                                       }else{
+                                               res.json({"sliValuesObj" : [],"message":msg});
+                                       }
+                               }else{
+                                       if(stderr){
+                                               console.log("stderr:" + stderr);
+                                       }
+                                       if(stdout){
+                                               console.log("stdout:" + stdout);
+                                       }
+                                       var msg = "File " + fileName + " processed successfully.";
+                                       var generatedJSDir=appDir + "/generatedJS";
+                                       var sliValuesObj =[];
+                                       //var glob = require("glob");
+                                       //glob(generatedJSDir + "/**/*.js", null, function (er, files) {
+                                       /*
+                                               var sliValuesObj =[];
+                                               for(var i=0;files!= null && i<files.length;i++){
+                                                       var f = files[i].replace( new RegExp(generatedJSDir + "/", "g" ), "" );
+                                                       console.log("loading file " + f);
+                                                       try{
+                                                               sliValuesObj.push(require(files[i]));
+                                                               //console.dir(sliValuesObj);
+                                                       }catch(err){
+                                                               console.log("Error:Could not load file " + files[i]);
+                                                       }
+                                               } 
+                                               res.json({"sliValuesObj" : sliValuesObj,"message":msg});
+                                       });
+                                       */
+                                       res.json({"sliValuesObj" : sliValuesObj,"message":msg});
+                               }
+                       });
+               });
+        });
+        app.get("/getYangFiles",function(req,res) {
+               var appDir = path.dirname(require.main.filename);
+               var yangFilesDir=appDir + "/yangFiles";
+               var glob = require("glob")
+               glob(yangFilesDir + "/**/*.yang", null, function (er, files) {
+                       var filesList =[];
+                       for(var i=0;files!= null && i<files.length;i++){
+                               var f = files[i].replace( new RegExp(yangFilesDir + "/", "g" ), "" );
+                               filesList.push(f);
+
+                       }
+                       res.json({"files" : filesList});
+               });
+        });
+       }
+}
+
+function reportAddedModules(info) {
+    comms.publish("node/added",info,false);
+    if (info.length > 0) {
+        util.log("[red] Added node types:");
+        for (var i=0;i<info.length;i++) {
+            for (var j=0;j<info[i].types.length;j++) {
+                util.log("[red] - "+
+                    (info[i].module?info[i].module+":":"")+
+                    info[i].types[j]+
+                    (info[i].err?" : "+info[i].err:"")
+                    );
+            }
+        }
+    }
+    return info;
+}
+
+function reportRemovedModules(removedNodes) {
+    comms.publish("node/removed",removedNodes,false);
+    util.log("[red] Removed node types:");
+    for (var j=0;j<removedNodes.length;j++) {
+        for (var i=0;i<removedNodes[j].types.length;i++) {
+            util.log("[red] - "+(removedNodes[i].module?removedNodes[i].module+":":"")+removedNodes[j].types[i]);
+        }
+    }
+    return removedNodes;
+}
+
+function installModule(module) { 
+    //TODO: ensure module is 'safe'
+    return when.promise(function(resolve,reject) {
+        if (/[\s;]/.test(module)) {
+            reject(new Error("Invalid module name"));
+            return;
+        }
+        util.log("[red] Installing module: "+module);
+        var child = exec('npm install --production '+module, function(err, stdin, stdout) {
+            if (err) {
+                var lookFor404 = new RegExp(" 404 .*"+module+"$","m");
+                if (lookFor404.test(stdout)) {
+                    util.log("[red] Installation of module "+module+" failed: module not found");
+                    var e = new Error();
+                    e.code = 404;
+                    reject(e);
+                } else {
+                    util.log("[red] Installation of module "+module+" failed:");
+                    util.log("------------------------------------------");
+                    console.log(err.toString());
+                    util.log("------------------------------------------");
+                    reject(new Error("Install failed"));
+                }
+            } else {
+                util.log("[red] Installed module: "+module);
+                resolve(redNodes.addModule(module).then(reportAddedModules));
+            }
+        });
+    });
+}
+
+function uninstallModule(module) {
+    var list = redNodes.removeModule(module);
+    return when.promise(function(resolve,reject) {
+        if (/[\s;]/.test(module)) {
+            reject(new Error("Invalid module name"));
+            return;
+        }
+        util.log("[red] Removing module: "+module);
+        var child = exec('npm remove '+module, function(err, stdin, stdout) {
+            if (err) {
+                util.log("[red] Removal of module "+module+" failed:");
+                util.log("------------------------------------------");
+                console.log(err.toString());
+                util.log("------------------------------------------");
+                reject(new Error("Removal failed"));
+            } else {
+                util.log("[red] Removed module: "+module);
+                reportRemovedModules(list);
+                resolve(list);
+            }
+        });
+    });
+}
+
+function start() {
+    var defer = when.defer();
+    
+    storage.init(settings).then(function() {
+        settings.load(storage).then(function() {
+            console.log("\nWelcome to Node-RED\n===================\n");
+            if (settings.version) {
+                util.log("[red] Version: "+settings.version);
+            }
+            util.log("[red] Loading palette nodes");
+            redNodes.init(settings,storage);
+            redNodes.load().then(function() {
+                var i;
+                var nodes = redNodes.getNodeList();
+                var nodeErrors = nodes.filter(function(n) { return n.err!=null;});
+                var nodeMissing = nodes.filter(function(n) { return n.module && n.enabled && !n.loaded && !n.err;});
+                if (nodeErrors.length > 0) {
+                    util.log("------------------------------------------");
+                    if (settings.verbose) {
+                        for (i=0;i<nodeErrors.length;i+=1) {
+                            util.log("["+nodeErrors[i].name+"] "+nodeErrors[i].err);
+                        }
+                    } else {
+                        util.log("[red] Failed to register "+nodeErrors.length+" node type"+(nodeErrors.length==1?"":"s"));
+                        util.log("[red] Run with -v for details");
+                    }
+                    util.log("------------------------------------------");
+                }
+                if (nodeMissing.length > 0) {
+                    util.log("[red] Missing node modules:");
+                    var missingModules = {};
+                    for (i=0;i<nodeMissing.length;i++) {
+                        var missing = nodeMissing[i];
+                        missingModules[missing.module] = (missingModules[missing.module]||[]).concat(missing.types);
+                    }
+                    var promises = [];
+                    for (i in missingModules) {
+                        if (missingModules.hasOwnProperty(i)) {
+                            util.log("[red] - "+i+": "+missingModules[i].join(", "));
+                            if (settings.autoInstallModules) {
+                                installModule(i).otherwise(function(err) {
+                                    // Error already reported. Need the otherwise handler
+                                    // to stop the error propagating any further
+                                });
+                            }
+                        }
+                    }
+                    if (!settings.autoInstallModules) {
+                        util.log("[red] Removing modules from config");
+                        redNodes.cleanNodeList();
+                    }
+                }
+                defer.resolve();
+                
+                redNodes.loadFlows();
+            }).otherwise(function(err) {
+                console.log(err);
+            });
+            comms.start();
+        });
+    }).otherwise(function(err) {
+        defer.reject(err);
+    });
+    
+    return defer.promise;
+}
+
+function stop() {
+    redNodes.stopFlows();
+    comms.stop();
+}
+
+module.exports = { 
+    init: createServer,
+    start: start,
+    stop: stop
+}
+
+module.exports.__defineGetter__("app", function() { return app });
+module.exports.__defineGetter__("nodeApp", function() { return nodeApp });
+module.exports.__defineGetter__("server", function() { return server });
diff --git a/dgbuilder/red/settings.js b/dgbuilder/red/settings.js
new file mode 100644 (file)
index 0000000..4994953
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var when = require("when");
+
+var assert = require("assert");
+
+var userSettings = null;
+var globalSettings = null;
+var storage = null;
+
+var persistentSettings = {
+    init: function(settings) {
+        userSettings = settings;
+        
+        for (var i in settings) {
+            if (settings.hasOwnProperty(i)) {
+                (function() {
+                    var j = i;
+                    persistentSettings.__defineGetter__(j,function() { return userSettings[j]; });
+                    persistentSettings.__defineSetter__(j,function() { throw new Error("Property '"+i+"' is read-only"); });
+                })();
+            }
+        }
+        globalSettings = null;
+    },
+    load: function(_storage) {
+        storage = _storage;
+        return storage.getSettings().then(function(_settings) {
+            globalSettings = _settings;
+        });
+    },
+    get: function(prop) {
+        if (userSettings.hasOwnProperty(prop)) {
+            return userSettings[prop];
+        }
+        if (globalSettings === null) {
+            throw new Error("Settings not available");
+        }
+        return globalSettings[prop];
+    },
+    
+    set: function(prop,value) {
+        if (userSettings.hasOwnProperty(prop)) {
+            throw new Error("Property '"+prop+"' is read-only");
+        }
+        if (globalSettings === null) {
+            throw new Error("Settings not available");
+        }
+        var current = globalSettings[prop];
+        globalSettings[prop] = value;
+        try {
+            assert.deepEqual(current,value);
+            return when.resolve();
+        } catch(err) {
+            return storage.saveSettings(globalSettings);
+        }
+    },
+    
+    available: function() {
+        return (globalSettings !== null);
+    },
+    
+    reset: function() {
+        userSettings = null;
+        globalSettings = null;
+        storage = null;
+    }
+}
+
+module.exports = persistentSettings;
diff --git a/dgbuilder/red/sla.js b/dgbuilder/red/sla.js
new file mode 100644 (file)
index 0000000..1729ecb
--- /dev/null
@@ -0,0 +1,249 @@
+exports.listSLA =  function(settings,req,res) {
+try{
+       var mysql = require('mysql');
+
+       //console.dir(settings);
+       var connection = mysql.createConnection(
+       {
+       host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+       var sqlQuery = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+       //console.log("sqlQuery:" + sqlQuery);
+         connection.query(sqlQuery, function(err, rows) {
+            if(!err) {
+                if ( rows.length > 0 )
+                {
+                        res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                }else{
+                        res.send({'rows': [],'dbHost':settings.dbHost});
+                }
+            } else {
+                       console.log("error:" + err);
+                   res.send({error: "Connection to DB failed.",'dbHost':settings.dbHost});
+            }
+               //console.dir(rows);
+               connection.end();
+        }); //end query
+}catch(error){
+       console.log(error);
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.listCurrentDGs =  function(settings,req,res) {
+       var _module = req.query.module;
+       var rpc = req.query.rpc;
+       console.log("_module:" + _module);
+       console.log("rpc:" + rpc);
+try{
+       var mysql = require('mysql');
+
+       //console.dir(settings);
+       var connection = mysql.createConnection(
+       {
+       host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+       var sqlQuery = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC where module ='" + _module + "' and rpc ='" + rpc + "'";
+       console.log("sqlQuery:" + sqlQuery);
+         connection.query(sqlQuery, function(err, rows) {
+            if(!err) {
+                if ( rows.length > 0 )
+                {
+                        res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                }else{
+                        res.send({'rows': [],'dbHost':settings.dbHost});
+                }
+            } else {
+                       console.log("error:" + err);
+                   res.send({error: "Connection to DB failed.",'dbHost':settings.dbHost});
+            }
+               //console.dir(rows);
+               connection.end();
+        }); //end query
+}catch(error){
+       console.log(error);
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.activateDG = function(settings,req,res){
+       var _module = req.query.module;
+       var rpc = req.query.rpc;
+       var version = req.query.version;
+       var mode = req.query.mode;
+       var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+       var mysql = require('mysql');
+       var connection = mysql.createConnection(
+       {
+       host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+       var updateStmt = "UPDATE SVC_LOGIC SET active=\'Y\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+
+         connection.query(updateStmt, function(err, result) {
+               var nextUpdateStmt = "UPDATE SVC_LOGIC SET active=\'N\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version !=\'"
+                        +  version + "'";
+               connection.query(nextUpdateStmt, function(err, result) {
+                       var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+                       if(displayOnlyCurrent == 'true'){
+                               query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+                                       +  _module + "' and rpc=\'" + rpc + "'";
+                       }
+                       connection.query(query, function(err, rows) {
+                               if(!err) {
+                                       if ( rows.length > 0 )
+                                       {
+                                               res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                                       }else{
+                                               res.send({'rows': [],'dbHost':settings.dbHost});
+                                       }
+                               } else {
+                                       res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+                               }
+                               connection.end();
+                       }); //end query
+               }); //end query
+               }); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+
+exports.deActivateDG = function(settings,req,res){
+
+       var _module = req.query.module;
+       var rpc = req.query.rpc;
+       var version = req.query.version;
+       var mode = req.query.mode;
+       var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+       var mysql = require('mysql');
+       var connection = mysql.createConnection(
+       {
+       host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+       var updateStmt = "UPDATE SVC_LOGIC SET active=\'N\' WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+
+         connection.query(updateStmt, function(err, result) {
+               var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+               if(displayOnlyCurrent == 'true'){
+                       query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+                               +  _module + "' and rpc=\'" + rpc + "'";
+               }
+               connection.query(query, function(err, rows) {
+               if(!err) {
+                       if ( rows.length > 0 )
+                       {
+                               res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                       }else{
+                               res.send({'rows': [],'dbHost':settings.dbHost});
+                       }
+               } else {
+                       res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+               }
+               connection.end();
+               }); //end query
+               }); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
+
+exports.deleteDG = function(settings,req,res){
+
+       var _module = req.query.module;
+       var rpc = req.query.rpc;
+       var version = req.query.version;
+       var mode = req.query.mode;
+       var displayOnlyCurrent = req.query.displayOnlyCurrent;
+
+try{
+       var mysql = require('mysql');
+       var connection = mysql.createConnection(
+       {
+       host     : settings.dbHost,
+        port     : settings.dbPort,
+        user     : settings.dbUser,
+        password : settings.dbPassword,
+        database : settings.dbName
+       });
+
+        var rows=[];
+
+       var deleteStmt = "DELETE FROM SVC_LOGIC  WHERE module=\'"
+                        + _module + "' AND rpc=\'"
+                        + rpc + "' AND version=\'"
+                        +  version + "' AND mode=\'"
+                        +  mode + "'";
+        console.log(deleteStmt);
+
+         connection.query(deleteStmt, function(err, result) {
+               var query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC";
+               if(displayOnlyCurrent == 'true'){
+                       query = "SELECT module,rpc,version,mode,active FROM SVC_LOGIC WHERE module=\'"
+                               +  _module + "' and rpc=\'" + rpc + "'";
+               }
+               connection.query(query, function(err, rows) {
+               if(!err) {
+                       if ( rows.length > 0 )
+                       {
+                               res.send({ 'rows': rows,'dbHost':settings.dbHost } );
+                       }else{
+                               res.send({'rows': [],'dbHost':settings.dbHost});
+                       }
+               } else {
+                       res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+               }
+               connection.end();
+               }); //end query
+               }); //end query
+}catch(error){
+        res.send({'error': "Connection to DB failed.",'dbHost':settings.dbHost});
+}
+}
diff --git a/dgbuilder/red/storage/index.js b/dgbuilder/red/storage/index.js
new file mode 100644 (file)
index 0000000..ba93962
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var when = require('when');
+
+var storageModule;
+var settingsAvailable;
+
+function moduleSelector(aSettings) {
+    var toReturn;
+    if (aSettings.storageModule) {
+        if (typeof aSettings.storageModule === "string") {
+            // TODO: allow storage modules to be specified by absolute path
+            toReturn = require("./"+aSettings.storageModule);
+        } else {
+            toReturn = aSettings.storageModule;
+        }
+    } else {
+        toReturn = require("./localfilesystem");
+    }
+    return toReturn;
+}
+
+function is_malicious(path) {
+    return path.indexOf('../') != -1 || path.indexOf('..\\') != -1;
+}
+
+var storageModuleInterface = {
+        init: function(settings) {
+            try {
+                storageModule = moduleSelector(settings);
+                settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings");
+            } catch (e) {
+                return when.reject(e);
+            }
+            return storageModule.init(settings);
+        },
+        getFlows: function() {
+            return storageModule.getFlows();
+        },
+        saveFlows: function(flows) {
+            return storageModule.saveFlows(flows);
+        },
+        getCredentials: function() {
+            return storageModule.getCredentials();
+        },
+        saveCredentials: function(credentials) {
+            return storageModule.saveCredentials(credentials);
+        },
+        getSettings: function() {
+            if (settingsAvailable) {
+                return storageModule.getSettings();
+            } else {
+                return when.resolve(null);
+            }
+        },
+        saveSettings: function(settings) {
+            if (settingsAvailable) {
+                return storageModule.saveSettings(settings);
+            } else {
+                return when.resolve();
+            }
+        },
+        /* Library Functions */
+        getAllFlows: function() {
+            return storageModule.getAllFlows();
+        },
+        getFlow: function(fn) {
+            if (is_malicious(fn)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.getFlow(fn);
+        },
+        saveFlow: function(fn, data) {
+            if (is_malicious(fn)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.saveFlow(fn, data);
+        },
+        getLibraryEntry: function(type, path) {
+            if (is_malicious(path)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.getLibraryEntry(type, path);
+        },
+        saveLibraryEntry: function(type, path, meta, body) {
+            if (is_malicious(path)) {
+                return when.reject(new Error('forbidden flow name'));
+            }
+            return storageModule.saveLibraryEntry(type, path, meta, body);
+        }
+}
+
+module.exports = storageModuleInterface;
diff --git a/dgbuilder/red/storage/localfilesystem.js b/dgbuilder/red/storage/localfilesystem.js
new file mode 100644 (file)
index 0000000..4825533
--- /dev/null
@@ -0,0 +1,309 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var fs = require('fs');
+var when = require('when');
+var nodeFn = require('when/node/function');
+var keys = require('when/keys');
+var util = require('util');
+var fspath = require("path");
+var mkdirp = require("mkdirp");
+
+var promiseDir = nodeFn.lift(mkdirp);
+
+var settings;
+var flowsFile;
+var flowsFullPath;
+var flowsPrev;
+var credentialsFile;
+var oldCredentialsFile;
+var userDir;
+var libDir;
+var libFlowsDir;
+var globalSettingsFile;
+
+function listFiles(dir) {
+    var dirs = {};
+    var files = [];
+    var dirCount = 0;
+    return nodeFn.call(fs.readdir, dir).then(function (contents) {
+        contents.sort().forEach(function(fn) {
+            var stats = fs.lstatSync(dir+"/"+fn);
+            if (stats.isDirectory()) {
+                dirCount += 1;
+                dirs[fn] = listFiles(dir+"/"+fn)
+            } else {
+                files.push(fn.split(".")[0]);
+            }
+        })
+        var result = {};
+        if (dirCount > 0) { result.d = keys.all(dirs); }
+        if (files.length > 0) { result.f = when.resolve(files); }
+        return keys.all(result);
+    })
+}
+
+function getFileMeta(root,path) {
+    var fn = fspath.join(root,path);
+    var fd = fs.openSync(fn,"r");
+    var size = fs.fstatSync(fd).size;
+    var meta = {};
+    var read = 0;
+    var length = 10;
+    var remaining = "";
+    var buffer = Buffer(length);
+    while(read < size) {
+        read+=fs.readSync(fd,buffer,0,length);
+        var data = remaining+buffer.toString();
+        var parts = data.split("\n");
+        remaining = parts.splice(-1);
+        for (var i=0;i<parts.length;i+=1) {
+            var match = /^\/\/ (\w+): (.*)/.exec(parts[i]);
+            if (match) {
+                meta[match[1]] = match[2];
+            } else {
+                read = size;
+                break;
+            }
+        }
+    }
+    fs.closeSync(fd);
+    return meta;
+}
+
+function getFileBody(root,path) {
+    var body = "";
+    var fn = fspath.join(root,path);
+    var fd = fs.openSync(fn,"r");
+    var size = fs.fstatSync(fd).size;
+    var scanning = true;
+    var read = 0;
+    var length = 50;
+    var remaining = "";
+    var buffer = Buffer(length);
+    while(read < size) {
+        var thisRead = fs.readSync(fd,buffer,0,length);
+        read += thisRead;
+        if (scanning) {
+            var data = remaining+buffer.slice(0,thisRead).toString();
+            var parts = data.split("\n");
+            remaining = parts.splice(-1)[0];
+            for (var i=0;i<parts.length;i+=1) {
+                if (! /^\/\/ \w+: /.test(parts[i])) {
+                    scanning = false;
+                    body += parts[i]+"\n";
+                }
+            }
+            if (! /^\/\/ \w+: /.test(remaining)) {
+                scanning = false;
+            }
+            if (!scanning) {
+                body += remaining;
+            }
+        } else {
+            body += buffer.slice(0,thisRead).toString();
+        }
+    }
+    fs.closeSync(fd);
+    return body;
+}
+
+var localfilesystem = {
+    init: function(_settings) {
+        settings = _settings;
+        userDir = settings.userDir || process.env.NODE_RED_HOME;
+
+        if (settings.flowFile) {
+            flowsFile = settings.flowFile;
+            flowsFullPath = flowsFile;
+        } else {
+            flowsFile = 'flows_'+require('os').hostname()+'.json';
+            flowsFullPath = fspath.join(userDir,flowsFile);
+        }
+        var fsext = fspath.extname(flowsFile);
+        credentialsFile = fspath.join(userDir,fspath.basename(flowsFile,fsext)+"_cred"+fsext);
+        oldCredentialsFile = fspath.join(userDir,"credentials.json");
+        flowsPrev = fspath.join(userDir,"flows.backup");
+
+        libDir = fspath.join(userDir,"lib");
+        libFlowsDir = fspath.join(libDir,"flows");
+
+        
+        globalSettingsFile = fspath.join(userDir,".config.json");
+        
+        return promiseDir(libFlowsDir);
+    },
+
+    getFlows: function() {
+        var defer = when.defer();
+        fs.exists(flowsFullPath, function(exists) {
+            if (exists) {
+                util.log("[red] Loading flows : "+flowsFile);
+                defer.resolve(nodeFn.call(fs.readFile,flowsFullPath,'utf8').then(function(data) {
+                    return JSON.parse(data);
+                }));
+            } else {
+                util.log("[red] Flows file not found : "+flowsFile   );
+                defer.resolve([]);
+            }
+        });
+        return defer.promise;
+    },
+
+    saveFlows: function(flows) {
+        if (fs.existsSync(flowsFullPath)) {
+            fs.renameSync(flowsFullPath,flowsPrev);
+        }
+        
+        var flowData;
+        
+        if (settings.flowFilePretty) {
+            flowData = JSON.stringify(flows,null,4);
+        } else {
+            flowData = JSON.stringify(flows);
+        }
+               console.log("Writing to file:" + flowsFullPath); 
+        return nodeFn.call(fs.writeFile, flowsFullPath, flowData);
+    },
+
+    getCredentials: function() {
+        var defer = when.defer();
+        fs.exists(credentialsFile, function(exists) {
+            if (exists) {
+                defer.resolve(nodeFn.call(fs.readFile, credentialsFile, 'utf8').then(function(data) {
+                    return JSON.parse(data)
+                }));
+            } else {
+                fs.exists(oldCredentialsFile, function(exists) {
+                    if (exists) {
+                        defer.resolve(nodeFn.call(fs.readFile, oldCredentialsFile, 'utf8').then(function(data) {
+                            return JSON.parse(data)
+                        }));
+                    } else {
+                        defer.resolve({});
+                    }
+                });
+            }
+        });
+        return defer.promise;
+    },
+
+    saveCredentials: function(credentials) {
+        var credentialData;
+        if (settings.flowFilePretty) {
+            credentialData = JSON.stringify(credentials,null,4);
+        } else {
+            credentialData = JSON.stringify(credentials);
+        }
+        
+        return nodeFn.call(fs.writeFile, credentialsFile, credentialData)
+    },
+    
+    getSettings: function() {
+        if (fs.existsSync(globalSettingsFile)) {
+            return nodeFn.call(fs.readFile,globalSettingsFile,'utf8').then(function(data) {
+                if (data) {
+                    try {
+                        return JSON.parse(data);
+                    } catch(err) {
+                        util.log("[red] Corrupted config detected - resetting");
+                        return {};
+                    }
+                } else {
+                    return {};
+                }
+            });
+        }
+        return when.resolve({});
+    },
+    saveSettings: function(settings) {
+        return nodeFn.call(fs.writeFile,globalSettingsFile,JSON.stringify(settings,null,1),'utf8');
+    },
+    
+    
+    getAllFlows: function() {
+        return listFiles(libFlowsDir);
+    },
+
+    getFlow: function(fn) {
+        var defer = when.defer();
+        var file = fspath.join(libFlowsDir,fn+".json");
+        fs.exists(file, function(exists) {
+            if (exists) {
+                defer.resolve(nodeFn.call(fs.readFile,file,'utf8'));
+            } else {
+                defer.reject();
+            }
+        });
+        return defer.promise;
+    },
+
+    saveFlow: function(fn,data) {
+        var file = fspath.join(libFlowsDir,fn+".json");
+        return promiseDir(fspath.dirname(file)).then(function () {
+            return nodeFn.call(fs.writeFile, file, data);
+        });
+    },
+
+    getLibraryEntry: function(type,path) {
+        var root = fspath.join(libDir,type);
+        var rootPath = fspath.join(libDir,type,path);
+        return promiseDir(root).then(function () {
+            return nodeFn.call(fs.lstat, rootPath).then(function(stats) {
+                if (stats.isFile()) {
+                    return getFileBody(root,path);
+                }
+                if (path.substr(-1) == '/') {
+                    path = path.substr(0,path.length-1);
+                }
+                return nodeFn.call(fs.readdir, rootPath).then(function(fns) {
+                    var dirs = [];
+                    var files = [];
+                    fns.sort().filter(function(fn) {
+                        var fullPath = fspath.join(path,fn);
+                        var absoluteFullPath = fspath.join(root,fullPath);
+                        if (fn[0] != ".") {
+                            var stats = fs.lstatSync(absoluteFullPath);
+                            if (stats.isDirectory()) {
+                                dirs.push(fn);
+                            } else {
+                                var meta = getFileMeta(root,fullPath);
+                                meta.fn = fn;
+                                files.push(meta);
+                            }
+                        }
+                    });
+                    return dirs.concat(files);
+                });
+            });
+        });
+    },
+
+    saveLibraryEntry: function(type,path,meta,body) {
+        var fn = fspath.join(libDir, type, path);
+        var headers = "";
+        for (var i in meta) {
+            if (meta.hasOwnProperty(i)) {
+                headers += "// "+i+": "+meta[i]+"\n";
+            }
+        }
+        return promiseDir(fspath.dirname(fn)).then(function () {
+            nodeFn.call(fs.writeFile, fn, headers+body);
+        });
+    }
+};
+
+module.exports = localfilesystem;
diff --git a/dgbuilder/red/ui.js b/dgbuilder/red/ui.js
new file mode 100644 (file)
index 0000000..16580bf
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var express = require('express');
+var fs = require("fs");
+var events = require("./events");
+var path = require("path");
+
+var icon_paths = [path.resolve(__dirname + '/../public/icons')];
+
+var settings; // settings has to be global, otherwise variable not in scope for express
+
+events.on("node-icon-dir",function(dir) {
+    icon_paths.push(path.resolve(dir));
+});
+
+
+function setupUI(_settings,app) {
+    
+    settings = _settings;
+    
+    // Need to ensure the url ends with a '/' so the static serving works
+    // with relative paths
+    app.get("/",function(req,res) {
+        if (req.originalUrl.slice(-1) != "/") {
+            res.redirect(req.originalUrl+"/");
+        } else {
+            req.next();
+        }
+    });
+    
+    var iconCache = {};
+    //TODO: create a default icon
+    var defaultIcon = path.resolve(__dirname + '/../public/icons/arrow-in.png');
+    
+    app.get("/icons/:icon",function(req,res) {
+        if (iconCache[req.params.icon]) {
+            res.sendfile(iconCache[req.params.icon]); // if not found, express prints this to the console and serves 404
+        } else { 
+            for (var p=0;p<icon_paths.length;p++) {
+                var iconPath = path.join(icon_paths[p],req.params.icon);
+                if (fs.existsSync(iconPath)) {
+                    res.sendfile(iconPath);
+                    iconCache[req.params.icon] = iconPath;
+                    return;
+                }
+            }
+            res.sendfile(defaultIcon);
+        }
+    });
+    
+    app.get("/settings", function(req,res) {
+        var safeSettings = {
+            httpNodeRoot: settings.httpNodeRoot,
+            version: settings.version
+        };
+        res.json(safeSettings);
+    });
+    
+    app.use("/",express.static(__dirname + '/../public'));
+    
+    return app;
+}
+
+module.exports = setupUI;
diff --git a/dgbuilder/red/util.js b/dgbuilder/red/util.js
new file mode 100644 (file)
index 0000000..7ca72b0
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+function ensureString(o) {
+    if (Buffer.isBuffer(o)) {
+        return o.toString();
+    } else if (typeof o === "object") {
+        return JSON.stringify(o);
+    } else if (typeof o === "string") {
+        return o;
+    }
+    return ""+o;
+}
+
+function ensureBuffer(o) {
+    if (Buffer.isBuffer(o)) {
+        return o;
+    } else if (typeof o === "object") {
+        o = JSON.stringify(o);
+    } else if (typeof o !== "string") {
+        o = ""+o;
+    }
+    return new Buffer(o);
+}
+
+module.exports = {
+    ensureString: ensureString,
+    ensureBuffer: ensureBuffer,
+};
+
diff --git a/dgbuilder/releases/sdnc1.0/.config.json b/dgbuilder/releases/sdnc1.0/.config.json
new file mode 100644 (file)
index 0000000..d5f86c2
--- /dev/null
@@ -0,0 +1,228 @@
+{
+ "nodes": {
+  "f01e121fdcca44f4f1d1135f3e68095e1376b7eb": {
+   "name": "block.js",
+   "types": [
+    "block"
+   ],
+   "enabled": true
+  },
+  "717b8f34cf67474d1af03fdd6822bc9ef2e67bc2": {
+   "name": "call.js",
+   "types": [
+    "call"
+   ],
+   "enabled": true
+  },
+  "206bda0ae2599ad0cc8ce121fe7b70b84bf8a366": {
+   "name": "configure.js",
+   "types": [
+    "configure"
+   ],
+   "enabled": true
+  },
+  "4698a1beb7105851d2867245198c6b14f67f3e84": {
+   "name": "delete.js",
+   "types": [
+    "delete"
+   ],
+   "enabled": true
+  },
+  "dea017092a5d56efb769026110177045d8ea3430": {
+   "name": "execute.js",
+   "types": [
+    "execute"
+   ],
+   "enabled": true
+  },
+  "2e1ff0459a9f2572f6d441ee4ffc966835a36e04": {
+   "name": "exists.js",
+   "types": [
+    "exists"
+   ],
+   "enabled": true
+  },
+  "6ecaadc772558adea9aad9d440ee272a92b432f4": {
+   "name": "forNode.js",
+   "types": [
+    "for"
+   ],
+   "enabled": true
+  },
+  "a08ac375f31fb15f59a0df05c496ddd740aa6472": {
+   "name": "get-resource.js",
+   "types": [
+    "get-resource"
+   ],
+   "enabled": true
+  },
+  "39cc8c5b404aa076e5456d62de989bcdd2731f9a": {
+   "name": "is-available.js",
+   "types": [
+    "is-available"
+   ],
+   "enabled": true
+  },
+  "9bea307fd340b01a62086abf3a3940ac77730568": {
+   "name": "notify.js",
+   "types": [
+    "notify"
+   ],
+   "enabled": true
+  },
+  "276c320cd57c858be6dac2c636877648a35aa04c": {
+   "name": "record.js",
+   "types": [
+    "record"
+   ],
+   "enabled": true
+  },
+  "b36c73e0a1c43560d7b29a8959198fe431020ad9": {
+   "name": "release.js",
+   "types": [
+    "release"
+   ],
+   "enabled": true
+  },
+  "dfc45ebbf76658d3e8e73dbfb8bf962057ca2a57": {
+   "name": "reserve.js",
+   "types": [
+    "reserve"
+   ],
+   "enabled": true
+  },
+  "06a4ee60c18fddc68d290826daa18a9991b92919": {
+   "name": "save.js",
+   "types": [
+    "save"
+   ],
+   "enabled": true
+  },
+  "f99370311d57128b2bd1f408365e982c0dbafc46": {
+   "name": "set.js",
+   "types": [
+    "set"
+   ],
+   "enabled": true
+  },
+  "ab2b190a8e0c91eb36aed4f7fe25aef0c1019e9d": {
+   "name": "switchNode.js",
+   "types": [
+    "switchNode"
+   ],
+   "enabled": true
+  },
+  "d14d57596f9c543889e37fd44b83ae179224ec28": {
+   "name": "update.js",
+   "types": [
+    "update"
+   ],
+   "enabled": true
+  },
+  "28591694ec8869525734ef3e60ea13603d3a61f2": {
+   "name": "GenericXML.js",
+   "types": [
+    "GenericXML"
+   ],
+   "enabled": true
+  },
+  "055a038d5bf33e3aaeff6d83be1d0e0f9feaacb5": {
+   "name": "comment.js",
+   "types": [
+    "comment"
+   ],
+   "enabled": true
+  },
+  "2f1e87ae27d50973e857fa71e67eb717e65f2019": {
+   "name": "dgstart.js",
+   "types": [
+    "dgstart"
+   ],
+   "enabled": true
+  },
+  "c10b21de58bf98f978d17a2d0c16e8038d339fc3": {
+   "name": "method.js",
+   "types": [
+    "method"
+   ],
+   "enabled": true
+  },
+  "3b5f11ac0d6283221bc08ebf11d64fa17c15d4cb": {
+   "name": "serviceLogic.js",
+   "types": [
+    "service-logic"
+   ],
+   "enabled": true
+  },
+  "91e5dfbc8a58ff4f4c75c88f68209fe74172a79a": {
+   "name": "already-active.js",
+   "types": [
+    "already-active"
+   ],
+   "enabled": true
+  },
+  "2356e6f2b50eefaf1def0d8dd86f95227f5f3142": {
+   "name": "failure.js",
+   "types": [
+    "failure"
+   ],
+   "enabled": true
+  },
+  "d43be73f359a928c57a7cffcd5f37a7b9740d921": {
+   "name": "not-found.js",
+   "types": [
+    "not-found"
+   ],
+   "enabled": true
+  },
+  "bbc41e923705ff934c652daa85ea6599000e317b": {
+   "name": "other.js",
+   "types": [
+    "other"
+   ],
+   "enabled": true
+  },
+  "5490a91f90dcf4d1857910debbad5dfbfdc015f3": {
+   "name": "outcome.js",
+   "types": [
+    "outcome"
+   ],
+   "enabled": true
+  },
+  "608774ad827770597de4c27f9da3d202ad510409": {
+   "name": "outcomeFalse.js",
+   "types": [
+    "outcomeFalse"
+   ],
+   "enabled": true
+  },
+  "f8eb7854fe489265a7d484611791e750e96e0f4a": {
+   "name": "outcomeTrue.js",
+   "types": [
+    "outcomeTrue"
+   ],
+   "enabled": true
+  },
+  "cfb4ea42aa90d421129ff3275427599a438d3e61": {
+   "name": "success.js",
+   "types": [
+    "success"
+   ],
+   "enabled": true
+  },
+  "cdf3ac03ebc8419da64f2f3dc792c72660cdf41b": {
+   "name": "returnFailure.js",
+   "types": [
+    "returnFailure"
+   ],
+   "enabled": true
+  },
+  "8656992c3f5ffa48e7ea12a14fa33cfa87e0be4f": {
+   "name": "returnSuccess.js",
+   "types": [
+    "returnSuccess"
+   ],
+   "enabled": true
+  }
+ }
+}
\ No newline at end of file
diff --git a/dgbuilder/releases/sdnc1.0/codecloud/.gitignore b/dgbuilder/releases/sdnc1.0/codecloud/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/conf/svclogic.properties b/dgbuilder/releases/sdnc1.0/conf/svclogic.properties
new file mode 100644 (file)
index 0000000..92d997f
--- /dev/null
@@ -0,0 +1,5 @@
+org.onap.ccsdk.sli.dbtype=jdbc
+org.onap.ccsdk.sli.jdbc.url=jdbc:mysql://dbhost:3306/sdnctl
+org.onap.ccsdk.sli.jdbc.database=sdnctl
+org.onap.ccsdk.sli.jdbc.user=sdnctl
+org.onap.ccsdk.sli.jdbc.password=gamma
diff --git a/dgbuilder/releases/sdnc1.0/customSettings.js b/dgbuilder/releases/sdnc1.0/customSettings.js
new file mode 100644 (file)
index 0000000..dc85fa5
--- /dev/null
@@ -0,0 +1,38 @@
+module.exports={
+    "name": "Release sdnc1.0",
+    "emailAddress": "dguser@onap.org",
+    "uiPort": 3100,
+    "mqttReconnectTime": 15000,
+    "serialReconnectTime": 15000,
+    "debugMaxLength": 1000,
+    "htmlPath": "releases/sdnc1.0/html/",
+    "xmlPath": "releases/sdnc1.0/xml/",
+    "flowFile": "releases/sdnc1.0/flows/flows.json",
+    "sharedDir": "releases/sdnc1.0/flows/shared",
+    "userDir": "releases/sdnc1.0",
+    "httpAuth": {
+        "user": "dguser",
+        "pass": "cc03e747a6afbbcbf8be7668acfebee5"
+    },
+    "dbHost": "dbhost",
+    "dbPort": "3306",
+    "dbName": "sdnctl",
+    "dbUser": "sdnctl",
+    "dbPassword": "gamma",
+    "gitLocalRepository": "",
+    "httpRoot": "/",
+    "disableEditor": false,
+    "httpAdminRoot": "/",
+    "httpAdminAuth": {
+        "user": "dguser",
+        "pass": "cc03e747a6afbbcbf8be7668acfebee5"
+    },
+    "httpNodeRoot": "/",
+    "httpNodeAuth": {
+        "user": "dguser",
+        "pass": "cc03e747a6afbbcbf8be7668acfebee5"
+    },
+    "uiHost": "0.0.0.0",
+    "version": "0.9.1",
+    "performGitPull": "N"
+}
diff --git a/dgbuilder/releases/sdnc1.0/flows/shared/.gitignore b/dgbuilder/releases/sdnc1.0/flows/shared/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/flows/shared/backups/.gitignore b/dgbuilder/releases/sdnc1.0/flows/shared/backups/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/html/.gitignore b/dgbuilder/releases/sdnc1.0/html/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/lib/flows/.gitignore b/dgbuilder/releases/sdnc1.0/lib/flows/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/logs/.gitignore b/dgbuilder/releases/sdnc1.0/logs/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/releases/sdnc1.0/logs/process_pid b/dgbuilder/releases/sdnc1.0/logs/process_pid
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/dgbuilder/releases/sdnc1.0/xml/.gitignore b/dgbuilder/releases/sdnc1.0/xml/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/show_status.sh b/dgbuilder/show_status.sh
new file mode 100755 (executable)
index 0000000..2119751
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+tbold=$(tput setf 3)
+bold=$(tput setf 2)
+bold1=$(tput setf 2)
+offbold=$(tput rmso;tput sgr0)
+
+function pad {
+        #echo "1 is $1 2 is $2"
+        if [ "$1" == "" ]
+        then
+                $1 = "";
+        fi
+        let count=0
+        curr_len=`expr length "$1"`
+        let space_length=$2-$curr_len
+        spaces=""
+        while [ $count -lt $space_length ]
+        do
+                spaces="$spaces "
+                let count=$count+1
+        done
+        echo "$1$spaces"
+}
+       
+function isRunning {
+       echo $(curl -I "$1" 2>/dev/null|head -1|tail -1|awk '{print $2}')
+}
+dirName=$(pwd)
+options=($(ls -l $dirName/releases|grep ^d|awk '{print $NF}'|sort))
+       echo "$(pad RELEASE 15)$(pad URL 30)$(pad Status 10)"
+       echo "$(pad '----' 15)$(pad '---' 30)$(pad '------' 10)"
+       for opt in "${options[@]}" 
+       do 
+               
+               releaseDir="$opt"
+               if [ -e "./releases/${opt}/customSettings.js" ]
+               then
+                       pid=$(cat ./releases/$releaseDir/logs/process_pid 2>/dev/null)
+                       port=$(cat ./releases/$releaseDir/customSettings.js 2>/dev/null|grep uiPort|sed -e 's/[, ]//g'|cut -d: -f2)
+                       resp1=$(isRunning "http://localhost:$port")
+                       if [ "$resp1" == "401" ]
+                       then    
+                               echo "$(pad $releaseDir 15)$(pad http://localhost:$port 30)${bold}$(pad running 10)${offbold}"
+                       else
+                               processId=$(netstat -upltn 2>/dev/null|grep $port|awk '{print $NF}'|sed -e 's%/node-red%%g')
+                               if [ "$processId" == "" ]
+                               then
+                                       echo "$(pad $releaseDir 15)$(pad http://localhost:$port 30)${bold}$(pad stopped 10)${offbold}"
+                               else
+                                       echo "$(pad $releaseDir 15)$(pad http://localhost:$port 30)${bold}$(pad running 10)${offbold}"
+                               fi
+                       fi
+               fi
+       done
diff --git a/dgbuilder/src/assembly/assemble_zip.xml b/dgbuilder/src/assembly/assemble_zip.xml
new file mode 100644 (file)
index 0000000..f13efa0
--- /dev/null
@@ -0,0 +1,101 @@
+<!--
+  ============LICENSE_START=======================================================
+  openECOMP : SDN-C
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights
+                                                       reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<!-- Defines how we build the .zip file which is our distribution. -->
+
+<assembly
+       xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+       <id>bin</id>
+       <formats>
+               <format>zip</format>
+       </formats>
+
+        <includeBaseDirectory>false</includeBaseDirectory>
+
+        <fileSets>
+        <fileSet>
+            <directory>core_nodes</directory>
+            <outputDirectory>dgbuilder/core_nodes</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>generatedJS</directory>
+            <outputDirectory>dgbuilder/generatedJS</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>git_scripts</directory>
+            <outputDirectory>dgbuilder/git_scripts</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>nodes</directory>
+            <outputDirectory>dgbuilder/nodes</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>public</directory>
+            <outputDirectory>dgbuilder/public</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>red</directory>
+            <outputDirectory>dgbuilder/red</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>releases</directory>
+            <outputDirectory>dgbuilder/releases</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>svclogic</directory>
+            <outputDirectory>dgbuilder/svclogic</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>test</directory>
+            <outputDirectory>dgbuilder/test</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>tools</directory>
+            <outputDirectory>dgbuilder/tools</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>yangFiles</directory>
+            <outputDirectory>dgbuilder/yangFiles</outputDirectory>
+        </fileSet>
+               <fileSet>
+            <directory>.</directory>
+            <outputDirectory>dgbuilder/</outputDirectory>
+                <includes>
+                       <include>*.json</include>
+                       <include>*.js</include>
+                       <include>*.md</include>
+                       <include>*.sh</include>
+                       <include>LICENSE</include>
+               </includes>
+        </fileSet>
+               <fileSet>
+                       <directory>target/svclogic/lib</directory>
+                       <outputDirectory>dgbuilder/svclogic/lib</outputDirectory>
+                       <includes>
+                               <include>*.jar</include>
+                       </includes>
+               </fileSet>
+    </fileSets>
+
+
+</assembly>
diff --git a/dgbuilder/start.sh b/dgbuilder/start.sh
new file mode 100755 (executable)
index 0000000..38f1158
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/bash
+releaseDir="$1"
+if [ "$#" != "1" ]
+then
+       echo "Usage: $0 releaseDirName"
+       exit
+fi
+echo "ReleaseDir:$releaseDir"
+export PROJECT_HOME=`pwd`
+tbold=$(tput setf 3)
+bold=$(tput setf 2)
+bold1=$(tput setf 2)
+offbold=$(tput rmso;tput sgr0)
+
+function pad {
+        #echo "1 is $1 2 is $2"
+        if [ "$1" == "" ]
+        then
+                $1 = "";
+        fi
+        let count=0
+        curr_len=`expr length "$1"`
+        let space_length=$2-$curr_len
+        spaces=""
+        while [ $count -lt $space_length ]
+        do
+                spaces="$spaces "
+                let count=$count+1
+        done
+        echo "$1$spaces"
+}
+       
+function isRunning {
+       echo $(curl -I "$1" 2>/dev/null|head -1|tail -1|awk '{print $2}')
+}
+
+npm install
+
+if [ -e "releases/${releaseDir}/customSettings.js" ]
+then
+       pid=$(cat releases/$releaseDir/logs/process_pid 2>/dev/null)
+       port=$(cat releases/$releaseDir/customSettings.js|grep uiPort|sed -e 's/[, ]//g'|cut -d: -f2 )
+       count=$(ps -p$pid 2>/dev/null|grep -v PID|wc -l)
+       if [ "$count" != "0" ]
+       then 
+               echo "For Release \"$releaseDir\" - http://localhost:$port"
+               echo "********ALREADY RUNNING PID:$pid *******"
+       else
+               pid_listening_on_port=$(netstat -upltn 2>/dev/null|grep -w $port|awk '{print $NF}'|cut -d'/' -f1)
+               if [ "$pid_listening_on_port" != "" ]
+               then
+                       if [ "$pid_listening_on_port" != "$pid" ]
+                       then
+                               echo "port $port is already in use by other process"
+                               ps -p $pid_listening_on_port
+                       else
+                               echo "Process is already running.";
+                       fi
+                       exit;
+               fi
+               node red.js --settings releases/${releaseDir}/customSettings.js 
+               process_pid="$!"
+               echo $process_pid  >releases/$releaseDir/logs/process_pid
+               port=$(cat releases/${releaseDir}/customSettings.js|grep uiPort|sed -e 's/[, ]//g'|cut -d: -f2)
+               echo "For Release \"$releaseDir\"  ${urlIp}:$port --- STARTED PID:$process_pid"
+               if [ "${releaseDir}" != "" ]
+               then
+                       sleep 3
+                       ./show_status.sh|grep -w ${releaseDir}
+               fi
+       fi
+else
+       echo "Directory ${releaseDir}  is not setup. Use the createReleaseDir.sh script to setup the directory."
+fi
diff --git a/dgbuilder/stop.sh b/dgbuilder/stop.sh
new file mode 100755 (executable)
index 0000000..b67babc
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+tbold=$(tput setf 3)
+bold=$(tput setf 2)
+bold1=$(tput setf 2)
+offbold=$(tput rmso;tput sgr0)
+
+function pad {
+        #echo "1 is $1 2 is $2"
+        if [ "$1" == "" ]
+        then
+                $1 = "";
+        fi
+        let count=0
+        curr_len=`expr length "$1"`
+        let space_length=$2-$curr_len
+        spaces=""
+        while [ $count -lt $space_length ]
+        do
+                spaces="$spaces "
+                let count=$count+1
+        done
+        echo "$1$spaces"
+}
+releaseDir=""
+if [ "$#" == "1" ]
+then
+       releaseDir="$1"
+fi
+
+if [ -e "releases/${releaseDir}/customSettings.js" ]
+then
+               port=$(cat releases/${releaseDir}/customSettings.js|grep uiPort|sed -e 's/[, ]//g'|cut -d: -f2)
+       kill $(cat releases/${releaseDir}/logs/process_pid  2>/dev/null) >/dev/null 2>&1
+       if [ "$?" != "0" ]
+       then
+               #kill only if its a node-red process
+               processPid=$(netstat -upltn 2>/dev/null|grep -w $port|awk '{print $NF}'|sed -e 's%/node-red%%g')
+               kill $processPid 2>/dev/null
+               echo "http://localhost:$port ---- STOPPED"
+               ./show_status.sh|grep -w "${releaseDir}"
+       else
+               echo "http://localhost:$port ---- STOPPED"
+               ./show_status.sh|grep -w "${releaseDir}"
+       fi
+else
+       if [ "$releaseDir" != "" ]
+       then
+               echo "Release Directory ${releaseDir} not setup.";
+       else
+               echo "Usage:$0 releaseDirName"
+       fi      
+fi
diff --git a/dgbuilder/svclogic/copy_xml.sh b/dgbuilder/svclogic/copy_xml.sh
new file mode 100755 (executable)
index 0000000..8b2cc4e
--- /dev/null
@@ -0,0 +1,4 @@
+dt=$(date +'%m%d%Y_%H%M%S')
+mv ~/dg_xml/dg.xml ~/dg_xml/dg_${dt}.xml
+cp $(ls -ltr /home/users/schinthakayala/nodered/production/flowDesigner/users/sheshi/xml/*.xml|tail -1|awk '{print $NF}') ~/dg_xml/dg.xml
+echo "copied the latest DG"
diff --git a/dgbuilder/svclogic/dg.xml b/dgbuilder/svclogic/dg.xml
new file mode 100644 (file)
index 0000000..069a026
--- /dev/null
@@ -0,0 +1,2 @@
+<service-logic xmlns='http://www.onap.org/sdnc/svclogic' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://www.onap.org/sdnc/svclogic ./svclogic.xsd' module='ModuleName' version='1.0.0'><method rpc='rpcName' mode='sync'>
+</method></service-logic>
diff --git a/dgbuilder/svclogic/lib/.gitignore b/dgbuilder/svclogic/lib/.gitignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/dgbuilder/svclogic/load_dg b/dgbuilder/svclogic/load_dg
new file mode 100755 (executable)
index 0000000..e13745b
--- /dev/null
@@ -0,0 +1 @@
+/home/users/schinthakayala/dg_xml/svclogic.sh load /home/users/schinthakayala/dg_xml/dg.xml /home/users/schinthakayala/dg_xml/svclogic.properties
diff --git a/dgbuilder/svclogic/svclogic.properties b/dgbuilder/svclogic/svclogic.properties
new file mode 100644 (file)
index 0000000..b34ee25
--- /dev/null
@@ -0,0 +1,5 @@
+org.onap.ccsdk.sli.dbtype = jdbc\r
+org.onap.ccsdk.sli.jdbc.url = jdbc:mysql://dbhost:3306/sdnctl\r
+org.onap.ccsdk.sli.jdbc.database = sdnctl\r
+org.onap.ccsdk.sli.jdbc.user = sdnctl\r
+org.onap.ccsdk.sli.jdbc.password = gamma\r
diff --git a/dgbuilder/svclogic/svclogic.sh b/dgbuilder/svclogic/svclogic.sh
new file mode 100755 (executable)
index 0000000..4c0d2da
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+#echo "PROJECT_HOME:$PROJECT_HOME"
+
+MYSQL_JDBC_DRIVER=${MYSQL_JDBC_DRIVER:-$PROJECT_HOME/svclogic/lib/mysql-connector-java-5.1.31.jar}
+JARDIR="$PROJECT_HOME/svclogic/lib"
+#JARDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+CLASSPATH=$CLASSPATH:$MYSQL_JDBC_DRIVER
+for jar in $JARDIR/*.jar
+do
+    CLASSPATH=$CLASSPATH:${jar}
+done
+#echo "CLASSPATH is ${CLASSPATH}"
+java  -cp ${CLASSPATH}:${MYSQL_JDBC_DRIVER}:${SLI_COMMON_JAR} org.onap.ccsdk.sli.core.sli.SvcLogicParser $*
diff --git a/dgbuilder/test/_spec.js b/dgbuilder/test/_spec.js
new file mode 100644 (file)
index 0000000..9eb7e07
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+/**
+ * This test simply checks that for every .js file there exists
+ * a *_spec.js file under ./test correspondingly.
+ */
+
+/**
+ * Currently we're only checking the core components under ./red
+ * TODO: Increase the scope of this check
+ */
+
+var fs = require("fs");
+var should = require("should");
+var path = require('path');
+
+// Directories to check with .js files and _spec.js files respectively
+var jsdir = path.resolve(__dirname, "../red");
+var testdir = path.resolve(__dirname, "red");
+
+var fs = require('fs');
+var walkDirectory = function(dir, topdir, done) {
+    fs.readdir(dir, function(err, list) {
+        var error;
+        var errReturned = false;
+        if (err) {
+            return done(err);
+        }
+
+        var i = 0;
+        (function next() {
+            var file = list[i++];
+
+            // return error if there are no more files to check and error has not been previously returned to avoid multiple calls to done()
+            if (!file) {
+                if (!errReturned) {
+                    errReturned = true;
+                    return done(error);
+                }
+            } else {
+                file = path.resolve(dir, file);
+                fs.stat(file, function(err, stat) {
+                    if (stat && stat.isDirectory()) {
+                        walkDirectory(file, false, function(err) {
+                            if (!error) {
+                                error = err;
+                            }
+                            next();
+                        });
+                    } else {
+                        if (path.extname(file) === ".js") {
+                            var testFile = file.replace(jsdir, testdir).replace(".js", "_spec.js");
+                            fs.exists(testFile, function (exists) {
+                                try {
+                                    exists.should.equal(true, testFile + " does not exist");
+                                } catch (err) {
+                                    if (!topdir) {
+                                        return done(err);
+                                    } else {
+                                        error = err;
+                                        return;
+                                    }
+                                }
+                            });
+                        }
+                        next();
+                    }
+                });
+            }
+        })();
+    });
+};
+
+describe('_spec.js', function() {
+    this.timeout(50000); // we might not finish within the Mocha default timeout limit, project will also grow
+    it('is checking if all .js files have a corresponding _spec.js test file.', function(done) {
+        walkDirectory(jsdir, true, done);
+    });
+});
diff --git a/dgbuilder/test/nodes/core/core/20-inject_spec.js b/dgbuilder/test/nodes/core/core/20-inject_spec.js
new file mode 100644 (file)
index 0000000..aeeac9d
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var injectNode = require("../../../../nodes/core/core/20-inject.js");
+var helper = require("../../helper.js");
+
+describe('inject node', function() {
+
+    before(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+
+    it('should inject once', function(done) {
+
+        helper.load(injectNode, [{id:"n1", type:"inject",
+                    payload:"payload", topic: "t1",
+                    once: true, wires:[["n2"]] },
+                   {id:"n2", type:"helper"}],
+                  function() {
+                      var n2 = helper.getNode("n2");
+                      n2.on("input", function(msg) {
+                          msg.should.have.property('topic', 't1');
+                          msg.should.have.property('payload', 'payload');
+                          done();
+                      });
+                  });
+    });
+
+    it('should inject repeatedly', function(done) {
+
+        helper.load(injectNode, [{id:"n1", type:"inject",
+                    payload:"payload", topic: "t2",
+                    repeat: 0.2, wires:[["n2"]] },
+                   {id:"n2", type:"helper"}],
+                  function() {
+                      var n2 = helper.getNode("n2");
+                      var count = 0;
+                      n2.on("input", function(msg) {
+                          msg.should.have.property('topic', 't2');
+                          msg.should.have.property('payload', 'payload');
+                          count += 1;
+                          if (count > 2) {
+                              helper.clearFlows().then(function() {
+                                  done();
+                              });
+                          }
+                      });
+                  });
+    });
+
+    it('should inject with cron', function(done) {
+        helper.load(injectNode, [{id:"n1", type:"inject",
+                    payloadType:"date", topic: "t3",
+                    crontab: "* * * * * *", wires:[["n3"]] },
+                   {id:"n3", type:"helper"}],
+                  function() {
+                      var n3 = helper.getNode("n3");
+                      n3.on("input", function(msg) {
+                          msg.should.have.property('topic', 't3');
+                          msg.should.have.property('payload').be.a.Number;
+                          helper.clearFlows().then(function() {
+                              done();
+                          });
+                      });
+                  });
+    });
+
+    describe('post', function() {
+        it('should inject message', function(done) {
+            helper.load(injectNode,
+                        [{id:"n1", type:"inject",
+                          payloadType:"some type", topic: "t4",
+                          wires:[["n4"]] },
+                         { id:"n4", type:"helper"}], function() {
+                             var n4 = helper.getNode("n4");
+                             n4.on("input", function(msg) {
+                                 msg.should.have.property('topic', 't4');
+                                 msg.should.have.property('payload', '');
+                                 helper.clearFlows().then(function() {
+                                     done();
+                                 });
+                             });
+                             helper.request()
+                                 .post('/inject/n1')
+                                 .expect(200).end(function(err) {
+                                     if (err) {
+                                         return helper.clearFlows()
+                                             .then(function () {
+                                                 done(err);
+                                             });
+                                     }
+                                 });
+                         });
+        });
+
+        it('should fail for invalid node', function(done) {
+            helper.request().post('/inject/invalid').expect(404).end(done);
+        });
+    });
+});
diff --git a/dgbuilder/test/nodes/core/core/58-debug_spec.js b/dgbuilder/test/nodes/core/core/58-debug_spec.js
new file mode 100644 (file)
index 0000000..f83fc2c
--- /dev/null
@@ -0,0 +1,298 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var debugNode = require("../../../../nodes/core/core/58-debug.js");
+var helper = require("../../helper.js");
+var WebSocket = require('ws');
+
+describe('debug node', function() {
+
+    before(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+
+
+    it('should be loaded', function(done) {
+        var flow = [{id:"n1", type:"debug", name: "Debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            n1.should.have.property('name', 'Debug');
+            done();
+        });
+    });
+
+    it('should publish on input', function(done) {
+        var flow = [{id:"n1", type:"debug", name: "Debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload:"test"});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",name:"Debug",msg:"test"}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish to console', function(done) {
+        var flow = [{id:"n1", type:"debug", console: "true" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var count = 0;
+            n1.on('log', function(msg) {
+                msg.should.eql({level:'log',id:'n1',type:'debug',msg:'test'});
+                count++;
+                if (count == 2) {
+                    done();
+                }
+            });
+            websocket_test(function() {
+                n1.emit("input", {payload:"test"});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",msg:"test"}
+                });
+                count++;
+            }, function() {
+                if (count == 2) {
+                    done();
+                }
+            });
+        });
+    });
+
+    it('should publish complete message', function(done) {
+        var flow = [{id:"n1", type:"debug", complete: "true" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload:"test"});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{id:"n1",msg:'(Object) {\n "payload": "test"\n}'}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish an Error', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: new Error("oops")});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",msg:"Error: oops"}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish a boolean', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: true});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",msg: '(boolean) true'}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish with no payload', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",msg: '(undefined)'}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish an object', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: {type:'foo'}});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{id:"n1",msg:'(Object) {\n "type": "foo"\n}'}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish an array', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: [0,1,2,3]});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{id:"n1",msg: '(Array) [\n 0,\n 1,\n 2,\n 3\n]'}
+                });
+            }, done);
+        });
+    });
+
+    it('should publish an object with circular references', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                var o = { name: 'bar' };
+                o.o = o;
+                n1.emit("input", {payload: o});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{
+                        id:"n1",
+                        msg:'(Object) {\n "name": "bar",\n "o": "[circular]"\n}'
+                    }
+                });
+            }, done);
+        });
+    });
+
+    it('should truncated a long message', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: Array(1002).join("X")});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{
+                        id:"n1",
+                        msg: Array(1001).join("X")+' ....'
+                    }
+                });
+            }, done);
+        });
+    });
+
+    it('should convert Buffer to hex', function(done) {
+        var flow = [{id:"n1", type:"debug" }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload: new Buffer('HELLO', 'utf8')});
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",
+                    data:{
+                        id:"n1",
+                        msg: '(Buffer) 48454c4c4f',
+                    }
+                });
+            }, done);
+        });
+    });
+
+    it('should publish when active', function(done) {
+        var flow = [{id:"n1", type:"debug", active: false }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function() {
+                n1.emit("input", {payload:"message 1"});
+                helper.request()
+                    .post('/debug/n1/enable')
+                    .expect(200).end(function(err) {
+                        if (err) { return done(err); }
+                        n1.emit("input", {payload:"message 2"});
+                    });
+            }, function(msg) {
+                JSON.parse(msg).should.eql({
+                    topic:"debug",data:{id:"n1",msg:"message 2"}
+                });
+            }, done);
+        });
+    });
+
+    it('should not publish when inactive', function(done) {
+        var flow = [{id:"n1", type:"debug", active: true }];
+        helper.load(debugNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            websocket_test(function(close) {
+                helper.request()
+                    .post('/debug/n1/disable')
+                    .expect(201).end(function(err) {
+                        if (err) {
+                            close();
+                            return done(err);
+                        }
+                        n1.emit("input", {payload:"message"});
+                        setTimeout(function() {
+                            close();
+                            done();
+                        }, 200);
+                    });
+            }, function(msg) {
+                should.fail(null,null,"unexpected message");
+            }, function() {});
+        });
+    });
+
+    describe('post', function() {
+        it('should return 404 on invalid state', function(done) {
+            var flow = [{id:"n1", type:"debug", active: true }];
+            helper.load(debugNode, flow, function() {
+                helper.request()
+                    .post('/debug/n1/foobar')
+                    .expect(404).end(done);
+            });
+        });
+
+        it('should return 404 on invalid node', function(done) {
+            helper.request()
+                .post('/debug/n99/enable')
+                .expect(404).end(done);
+        });
+    });
+
+});
+
+function websocket_test(open_callback, message_callback, done_callback) {
+    var ws = new WebSocket(helper.url() + "/comms");
+    var close_callback = function() { ws.close(); };
+    ws.on('open', function() { open_callback(close_callback); });
+    ws.on('message', function(msg) {
+        message_callback(msg, close_callback);
+        ws.close();
+        done_callback();
+    });
+}
diff --git a/dgbuilder/test/nodes/core/core/80-function_spec.js b/dgbuilder/test/nodes/core/core/80-function_spec.js
new file mode 100644 (file)
index 0000000..9efd93a
--- /dev/null
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var functionNode = require("../../../../nodes/core/core/80-function.js");
+var helper = require("../../helper.js");
+
+describe('function node', function() {
+
+    before(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{id:"n1", type:"function", name: "function" }];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            n1.should.have.property('name', 'function');
+            done();
+        });
+    });
+
+    it('should send returned message', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                msg.should.have.property('payload', 'foo');
+                done();
+            });
+            n1.receive({payload:"foo",topic: "bar"});
+        });
+    });
+
+    it('should pass through _topic', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                msg.should.have.property('payload', 'foo');
+                msg.should.have.property('_topic', 'baz');
+                done();
+            });
+            n1.receive({payload:"foo",topic: "bar", _topic: "baz"});
+        });
+    });
+
+    it('should send to multiple outputs', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"],["n3"]],
+                     func:"return [{payload: '1'},{payload: '2'}];"},
+                    {id:"n2", type:"helper"}, {id:"n3", type:"helper"} ];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            var n3 = helper.getNode("n3");
+            var count = 0;
+            n2.on("input", function(msg) {
+                should(msg).have.property('payload', '1');
+                count++;
+                if (count == 2) {
+                    done();
+                }
+            });
+            n3.on("input", function(msg) {
+                should(msg).have.property('payload', '2');
+                count++;
+                if (count == 2) {
+                    done();
+                }
+            });
+            n1.receive({payload:"foo",topic: "bar"});
+        });
+    });
+
+    it('should send to multiple messages', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"]],
+                     func:"return [[{payload: 1},{payload: 2}]];"},
+                    {id:"n2", type:"helper"} ];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            var count = 0;
+            n2.on("input", function(msg) {
+                count++;
+                should(msg).have.property('payload', count);
+                should(msg).have.property('_topic', 'baz');
+                if (count == 2) {
+                    done();
+                }
+            });
+            n1.receive({payload:"foo", topic: "bar", _topic:"baz"});
+        });
+    });
+
+    it('should allow input to be discarded by returning null', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return null"},
+                    {id:"n2", type:"helper"}];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            setTimeout(function() {
+                done();
+            }, 200);
+            n2.on("input", function(msg) {
+                should.fail(null,null,"unexpected message");
+            });
+            n1.receive({payload:"foo",topic: "bar"});
+        });
+    });
+
+    it('should handle and log script error', function(done) {
+        var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"retunr"}];
+        helper.load(functionNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            n1.on("log", function(msg) {
+                msg.should.have.property('level', 'error');
+                msg.should.have.property('id', 'n1');
+                msg.should.have.property('type', 'function');
+                msg.should.have.property('msg', 'ReferenceError: retunr is not defined');
+                done();
+            });
+            n1.receive({payload:"foo",topic: "bar"});
+        });
+    });
+
+});
diff --git a/dgbuilder/test/nodes/core/core/80-template_spec.js b/dgbuilder/test/nodes/core/core/80-template_spec.js
new file mode 100644 (file)
index 0000000..a89afa3
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var templateNode = require("../../../../nodes/core/core/80-template.js");
+var helper = require("../../helper.js");
+
+describe('template node', function() {
+
+    before(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+
+
+    it('should modify payload', function(done) {
+        var flow = [{id:"n1", type:"template", field: "payload", template: "payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
+        helper.load(templateNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                msg.should.have.property('payload', 'payload=foo');
+                done();
+            });
+            n1.receive({payload:"foo",topic: "bar"});
+        });
+    });
+
+});
diff --git a/dgbuilder/test/nodes/core/core/89-delay_spec.js b/dgbuilder/test/nodes/core/core/89-delay_spec.js
new file mode 100644 (file)
index 0000000..22c3173
--- /dev/null
@@ -0,0 +1,420 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+
+var delayNode = require("../../../../nodes/core/core/89-delay.js");
+var helper = require("../../helper.js");
+
+var GRACE_PERCENTAGE=10;
+
+var nanosToSeconds = 1000000000;
+var millisToSeconds = 1000;
+
+var secondsToMinutes = 60;
+var secondsToHours = 3600;
+var secondsToDays = 86400;
+
+
+describe('delayNode', function() {
+    
+    beforeEach(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function(done) {
+        helper.unload();
+        helper.stopServer(done);
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[[]]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            delayNode1.should.have.property('name', 'delayNode');
+            done();
+        });
+    });
+    
+    var TimeUnitEnum = {
+            MILLIS : "milliseconds",
+            SECONDS : "seconds",
+            MINUTES : "minutes",
+            HOURS : "hours",
+            DAYS : "days"
+    }
+    
+    /**
+     * Tells whether two numeric values are close enough to each other
+     * @param actualValue - the value we're testing
+     * @param expectedValue - the value we're matching the test value against
+     * @param tolerancePercent - the percentage of tolerated deviation (0 means equals)
+     */
+    function closeEnough(actualValue, expectedValue, tolerancePercent) {
+        var toReturn;
+        var toleranceFraction = expectedValue * (tolerancePercent/100);
+        var minExpected = expectedValue - toleranceFraction;
+        var maxExpected = expectedValue + toleranceFraction;
+        
+        if(actualValue >= minExpected && actualValue <= maxExpected) {
+            toReturn = true;
+        } else {
+            toReturn = false;
+        }
+        return toReturn;
+    }
+    
+    /**
+     * Runs a delay test
+     * @param aTimeout - the timeout quantity
+     * @param aTimeoutUnit - the unit of the timeout: milliseconds, seconds, minutes, hours, days
+     */
+    function genericDelayTest(aTimeout, aTimeoutUnit, done) {
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delay","timeout":aTimeout,"timeoutUnits":aTimeoutUnit,"rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    var endTime = process.hrtime(startTime);
+                    var runtimeNanos = ( (endTime[0] * nanosToSeconds) + endTime[1] );
+                    var runtimeSeconds = runtimeNanos / nanosToSeconds;
+                    var aTimeoutUnifiedToSeconds;
+                    
+                    // calculating the timeout in seconds
+                    if(aTimeoutUnit == TimeUnitEnum.MILLIS) {
+                        aTimeoutUnifiedToSeconds = aTimeout / millisToSeconds;
+                    } else if(aTimeoutUnit == TimeUnitEnum.SECONDS) {
+                        aTimeoutUnifiedToSeconds = aTimeout;
+                    } else if(aTimeoutUnit == TimeUnitEnum.MINUTES) {
+                        aTimeoutUnifiedToSeconds = aTimeout * secondsToMinutes;
+                    } else if(aTimeoutUnit == TimeUnitEnum.HOURS) {
+                        aTimeoutUnifiedToSeconds = aTimeout * secondsToHours;
+                    } else if(aTimeoutUnit == TimeUnitEnum.DAYS) {
+                        aTimeoutUnifiedToSeconds = aTimeout * secondsToDays;
+                    }
+                    
+                    if(closeEnough(runtimeSeconds, aTimeoutUnifiedToSeconds, GRACE_PERCENTAGE)) {
+                        done();
+                    } else {
+                        try {
+                            should.fail(null, null, "Delayed runtime seconds " +  runtimeSeconds + " was not close enough to exlected timeout seconds: " + aTimeoutUnifiedToSeconds);
+                        } catch (err) {
+                            done(err);
+                        }
+                    }
+                } catch(err) {
+                    done(err);
+                }
+            });
+            var startTime = process.hrtime();
+            delayNode1.receive({payload:"delayMe"});
+        });
+    }
+    
+    /**
+     * We send a message, take a timestamp then when the message is received by the helper node, we take another timestamp.
+     * Then check if the message has been delayed by the expected amount.
+     */
+    it('delays the message in seconds', function(done) {
+        genericDelayTest(0.5, "seconds", done);
+    });
+    
+    it('delays the message in milliseconds', function(done) {
+        genericDelayTest(500, "milliseconds", done);
+    });
+    
+    it('delays the message in minutes', function(done) { // this is also 0.5 seconds
+        genericDelayTest(0.00833, "minutes", done);
+    });
+    
+    it('delays the message in hours', function(done) { // this is also 0.5 seconds
+        genericDelayTest(0.0001388, "hours", done);
+    });
+    
+    it('delays the message in days', function(done) { // this is also 0.5 seconds
+        genericDelayTest(0.000005787, "days", done);
+    });
+    
+    /**
+     * Runs a rate limit test - only testing seconds!
+     * @param aLimit - the message limit count
+     * @param runtimeInMillis - when to terminate run and count messages received
+     */
+    function genericRateLimitSECONDSTest(aLimit, runtimeInMillis, done) {
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":5,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var receivedMessagesStack = [];
+            var rate = 1000/aLimit;
+            
+            var receiveTimestamp;
+            
+            helperNode1.on("input", function(msg) {
+                if(receiveTimestamp) {
+                    var elapse = process.hrtime(receiveTimestamp);
+                    var receiveInterval = (elapse[0] * 1000) + ((elapse[1] / nanosToSeconds) * 1000);
+                    receiveInterval.should.be.above(rate * 0.9);
+                }
+                receiveTimestamp = process.hrtime();
+                receivedMessagesStack.push(msg);
+            });
+            
+            var possibleMaxMessageCount = Math.ceil(aLimit * (runtimeInMillis / 1000) + aLimit); // +aLimit as at the start of the 2nd period, we're allowing the 3rd burst
+            
+            var i = 0;
+            for(; i < possibleMaxMessageCount + 1; i++) {
+                delayNode1.receive({payload:i});
+            }
+            
+            setTimeout(function() {
+                try {
+                    receivedMessagesStack.length.should.be.lessThan(possibleMaxMessageCount);
+                    for(var j = 0; j < receivedMessagesStack.length; j++) {
+                        if(receivedMessagesStack[j].payload === j) {
+                            if(j === (receivedMessagesStack.length -1)) { // last message, all matched so far
+                                done();
+                            }
+                        } else {
+                            should.fail(null, null, "Received messages were not received in order. Message was " + receivedMessagesStack[i].payload + " on count " + i);
+                        }
+                    }   
+                } catch (err) {
+                    done(err);
+                }
+            }, runtimeInMillis);
+        });
+    }
+    
+    it('limits the message rate to 1 per second', function(done) {
+        genericRateLimitSECONDSTest(1, 1500, done);
+    });
+    
+    it('limits the message rate to 2 per second, 2 seconds', function(done) {
+        this.timeout(6000);
+        genericRateLimitSECONDSTest(2, 2100, done);
+    });
+    
+    /**
+     * Runs a rate limit test with drop support - only testing seconds!
+     * @param aLimit - the message limit count
+     * @param runtimeInMillis - when to terminate run and count messages received
+     */
+    function dropRateLimitSECONDSTest(aLimit, runtimeInMillis, done) {
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":5,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var receivedMessagesStack = [];
+            
+            var rate = 1000/aLimit;
+            
+            var receiveTimestamp;
+            
+            helperNode1.on("input", function(msg) {
+                if(receiveTimestamp) {
+                    var elapse = process.hrtime(receiveTimestamp);
+                    var receiveInterval = (elapse[0] * 1000) + ((elapse[1] / nanosToSeconds) * 1000);
+                    receiveInterval.should.be.above(rate * 0.9);
+                }
+                receiveTimestamp = process.hrtime();
+                receivedMessagesStack.push(msg);
+            });
+            
+            var possibleMaxMessageCount = Math.ceil(aLimit * (runtimeInMillis / 1000) + aLimit); // +aLimit as at the start of the 2nd period, we're allowing the 3rd burst
+            
+            var i = 0;
+            delayNode1.receive({payload:i});
+            i++;
+            for(; i < possibleMaxMessageCount + 1; i++) {
+                setTimeout(function() {
+                   delayNode1.receive({payload:i});
+                }, 2 * ((rate * i) / possibleMaxMessageCount) );
+            }
+            
+            //we need to send a message delayed so that it doesn't get dropped
+            setTimeout(function() {
+                delayNode1.receive({payload:++i});
+            }, runtimeInMillis - 300); // should give enough time to squeeze another message in
+            
+            setTimeout(function() {
+                try {
+                    receivedMessagesStack.length.should.be.lessThan(possibleMaxMessageCount + 1);
+                    receivedMessagesStack.length.should.be.greaterThan(2); // ensure that we receive more than 1st and last message
+                    receivedMessagesStack[0].payload.should.be.exactly(0); // means we received the last message injected just before test termination
+                    var foundAtLeastOneDrop = false;
+                    for(var i = 0; i < receivedMessagesStack.length; i++) {
+                        if(i > 0) {
+                            if(receivedMessagesStack[i].payload - receivedMessagesStack[i - 1].payload > 1) {
+                                foundAtLeastOneDrop = true;
+                            }
+                        }
+                    }
+                    foundAtLeastOneDrop.should.be.true;
+                    done();
+                } catch (err) {
+                    done(err);
+                }
+            }, runtimeInMillis);
+        });
+    }
+    
+    it('limits the message rate to 1 per second, 4 seconds, with drop', function(done) {
+        this.timeout(6000);
+        dropRateLimitSECONDSTest(1, 4000, done);
+    });
+    
+    it('limits the message rate to 2 per second, 5 seconds, with drop', function(done) {
+        this.timeout(6000);
+        dropRateLimitSECONDSTest(2, 5000, done);
+    });
+    
+    /**
+     * Returns true if the actualTimeout is gracefully in between the timeoutFrom and timeoutTo
+     * values. Gracefully means that inBetween could actually mean smaller/greater values
+     * than the timeout range so long as it's within an actual grace percentage.
+     * @param timeoutFrom - The expected timeout range (low number)
+     * @param timeoutTo - The expected timeout range (high number)
+     * @param actualTimeout - The actual measured timeout value of test
+     * @param allowedGracePercent - The percentage of grace allowed
+     */
+    function inBetweenDelays(timeoutFrom, timeoutTo, actualTimeout, allowedGracePercent) {
+        if(closeEnough(actualTimeout, timeoutFrom, allowedGracePercent)) {
+            return true;
+        } else if(closeEnough(actualTimeout, timeoutTo, allowedGracePercent)) {
+            return true;
+        } else if(timeoutFrom < actualTimeout && timeoutTo > actualTimeout) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    /**
+     * Runs a RANDOM DELAY test, checks if the delay is in between the given timeout values
+     * @param aTimeoutFrom - the timeout quantity which is the minimal acceptable wait period
+     * @param aTimeoutTo - the timeout quantity which is the maximum acceptable wait period
+     * @param aTimeoutUnit - the unit of the timeout: milliseconds, seconds, minutes, hours, days
+     */
+    function randomDelayTest(aTimeoutFrom, aTimeoutTo, aTimeoutUnit, done) {
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"random","timeout":5,"timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":aTimeoutFrom,"randomLast":aTimeoutTo,"randomUnits":aTimeoutUnit,"drop":false,"wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    var endTime = process.hrtime(startTime);
+                    var runtimeNanos = ( (endTime[0] * nanosToSeconds) + endTime[1] );
+                    var runtimeSeconds = runtimeNanos / nanosToSeconds;
+                    var aTimeoutFromUnifiedToSeconds;
+                    var aTimeoutToUnifiedToSeconds;
+                    
+                    // calculating the timeout in seconds
+                    if(aTimeoutUnit == TimeUnitEnum.MILLIS) {
+                        aTimeoutFromUnifiedToSeconds = aTimeoutFrom / millisToSeconds;
+                        aTimeoutToUnifiedToSeconds = aTimeoutTo / millisToSeconds;
+                    } else if(aTimeoutUnit == TimeUnitEnum.SECONDS) {
+                        aTimeoutFromUnifiedToSeconds = aTimeoutFrom;
+                        aTimeoutToUnifiedToSeconds = aTimeoutTo;
+                    } else if(aTimeoutUnit == TimeUnitEnum.MINUTES) {
+                        aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToMinutes;
+                        aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToMinutes;
+                    } else if(aTimeoutUnit == TimeUnitEnum.HOURS) {
+                        aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToHours;
+                        aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToHours;
+                    } else if(aTimeoutUnit == TimeUnitEnum.DAYS) {
+                        aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToDays;
+                        aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToDays;
+                    }
+                    
+                    if(inBetweenDelays(aTimeoutFromUnifiedToSeconds, aTimeoutToUnifiedToSeconds, runtimeSeconds, GRACE_PERCENTAGE)) {
+                        done();
+                    } else {
+                        try {
+                            should.fail(null, null, "Delayed runtime seconds " +  runtimeSeconds + " was not \"in between enough\" enough to expected values of: " + aTimeoutFromUnifiedToSeconds + " and " + aTimeoutToUnifiedToSeconds);
+                        } catch (err) {
+                            done(err);
+                        }
+                    }
+                } catch(err) {
+                    done(err);
+                }
+            });
+            var startTime = process.hrtime();
+            delayNode1.receive({payload:"delayMe"});
+        });
+    }
+    
+    it('randomly delays the message in seconds', function(done) {
+        randomDelayTest(0.4, 0.8, "seconds", done);
+    });
+    
+    it(' randomly delays the message in milliseconds', function(done) {
+        randomDelayTest(400, 800, "milliseconds", done);
+    });
+    
+    it('randomly delays the message in minutes', function(done) {
+        randomDelayTest(0.0066, 0.0133, "minutes", done);
+    });
+    
+    it('delays the message in hours', function(done) {
+        randomDelayTest(0.000111111, 0.000222222, "hours", done);
+    });
+    
+    it('delays the message in days', function(done) {
+        randomDelayTest(0.0000046296, 0.0000092593, "days", done);
+    });
+    
+    it('handles bursts using a buffer', function(done) {
+        this.timeout(6000);
+
+        var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":5,"timeoutUnits":"seconds","rate":1000,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(delayNode, flow, function() {
+            var delayNode1 = helper.getNode("delayNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            
+            var sinon = require('sinon');
+            
+            var receivedWarning = false;
+            var messageBurstSize = 1500;
+            
+            // we ensure that we note that a warning is received for buffer growth
+            sinon.stub(delayNode1, 'warn', function(warning){
+                if(warning.indexOf("buffer exceeded 1000 messages" > -1)) {
+                    receivedWarning = true;
+                }
+            });
+            
+            // we ensure that the warning is received for buffer size and that we get the last message
+            helperNode1.on("input", function(msg) {
+                if(msg.payload === (messageBurstSize - 1) && receivedWarning === true) {
+                    done(); // it will timeout if we don't receive the last message
+                }
+            });
+            // send 1500 messages as quickly as possible
+            for(var i = 0; i < messageBurstSize; i++) {
+                delayNode1.receive({payload:i});   
+            }
+        });
+    });
+    
+});
diff --git a/dgbuilder/test/nodes/core/core/90-comment_spec.js b/dgbuilder/test/nodes/core/core/90-comment_spec.js
new file mode 100644 (file)
index 0000000..54563e9
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var commentNode = require("../../../../nodes/core/core/90-comment.js");
+var helper = require("../../helper.js");
+
+describe('comment node', function() {
+
+    afterEach(function() {
+        helper.unload();
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{id:"n1", type:"comment", name: "comment" }];
+        helper.load(commentNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            n1.should.have.property('name', 'comment');
+            done();
+        });
+    });
+
+});
diff --git a/dgbuilder/test/nodes/core/logic/10-switch_spec.js b/dgbuilder/test/nodes/core/logic/10-switch_spec.js
new file mode 100644 (file)
index 0000000..d5a4280
--- /dev/null
@@ -0,0 +1,367 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+
+var switchNode = require("../../../../nodes/core/logic/10-switch.js");
+var helper = require("../../helper.js");
+
+describe('SwitchNode', function() {
+    
+    beforeEach(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function(done) {
+        helper.unload();
+        helper.stopServer(done);
+    });
+    
+    it('should be loaded', function(done) {
+        var flow = [{"id":"switchNode1","type":"switch","name":"switchNode","property":"payload","rules":[{"t":"eq","v":""}],"checkall":"true","outputs":1,"wires":[[]]}];
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            switchNode1.should.have.property('name', 'switchNode');
+            done();
+        });
+    });
+    
+    /**
+     * Test a switch node where one argument is consumed by the rule (such as greater than).
+     * @param rule - the switch rule (see 10-switc.js) string we're using
+     * @param ruleWith - whatever the rule should be executed with (say greater than 5)
+     * @param aCheckall - whether the switch flow should have the checkall flag set to true/false
+     * @param shouldReceive - whether the helper node should receive a payload
+     * @param sendPayload - the payload message we're sending
+     * @param done - callback when done
+     */
+    function genericSwitchTest(rule, ruleWith, aCheckall, shouldReceive, sendPayload, done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":rule,"v":ruleWith}],checkall:aCheckall,outputs:1,wires:[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        customFlowSwitchTest(flow, shouldReceive, sendPayload, done);
+    }
+    
+    /**
+     * Test a switch node where NO arguments are consumed by the rule (such as TRUE/FALSE)
+     * @param rule - the switch rule (see 10-switc.js) string we're using
+     * @param aCheckall - whether the switch flow should have the checkall flag set to true/false
+     * @param shouldReceive - whether the helper node should receive a payload
+     * @param sendPayload - the payload message we're sending
+     * @param done - callback when done
+     */
+    function singularSwitchTest(rule, aCheckall, shouldReceive, sendPayload, done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":rule}],checkall:aCheckall,outputs:1,wires:[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        customFlowSwitchTest(flow, shouldReceive, sendPayload, done);
+    }
+    
+    /**
+     * Test a switch node where two arguments are consumed by the rule (such as between).
+     * @param rule - the switch rule (see 10-switc.js) string we're using
+     * @param ruleWith - whatever the rule should be executed with (say between 5...)
+     * @param ruleWith2 - whatever the rule should be executed with (say ...and 5)
+     * @param aCheckall - whether the switch flow should have the checkall flag set to true/false
+     * @param shouldReceive - whether the helper node should receive a payload
+     * @param sendPayload - the payload message we're sending
+     * @param done - callback when done
+     */
+    function twoFieldSwitchTest(rule, ruleWith, ruleWith2, aCheckall, shouldReceive, sendPayload, done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":rule,"v":ruleWith,"v2":ruleWith2}],checkall:aCheckall,outputs:1,wires:[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        customFlowSwitchTest(flow, shouldReceive, sendPayload, done);
+    }
+    
+    /**
+     * Execute a switch test. Can specify whether the should node is expected to send a payload onwards to the helper node.
+     * The flow and the payload can be customised
+     * @param flow - the custom flow to be tested => must contain a switch node (switchNode1) wiring a helper node (helperNode1)
+     * @param shouldReceive - whether the helper node should receive a payload
+     * @param sendPayload - the payload message we're sending
+     * @param done - callback when done
+     */
+    function customFlowSwitchTest(flow, shouldReceive, sendPayload, done) {
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    if(shouldReceive === true) {
+                        msg.payload.should.equal(sendPayload);
+                        done();   
+                    } else {
+                        should.fail(null, null, "We should never get an input!");
+                    }
+                } catch(err) {
+                    done(err);
+                }
+            });
+            switchNode1.receive({payload:sendPayload});
+            if(shouldReceive === false) {
+                setTimeout(function() {
+                    done();
+                }, 200);
+            }
+        });
+    }
+    
+    it('should check if payload equals given value', function(done) {
+        genericSwitchTest("eq", "Hello", true, true, "Hello", done);
+    });
+    
+    it('should return nothing when the payload doesn\'t equal to desired string', function(done) {
+        genericSwitchTest("eq", "Hello", true, false, "Hello!", done);
+    });
+    
+    it('should check if payload NOT equals given value', function(done) {
+        genericSwitchTest("neq", "Hello", true, true, "HEllO", done);
+    });
+    
+    it('should return nothing when the payload does equal to desired string', function(done) {
+        genericSwitchTest("neq", "Hello", true, false, "Hello", done);
+    });
+    
+    it('should check if payload equals given numeric value', function(done) {
+        genericSwitchTest("eq", 3, true, true, 3, done);
+    });
+    
+    it('should return nothing when the payload doesn\'t equal to desired numeric value', function(done) {
+        genericSwitchTest("eq", 2, true, false, 4, done);
+    });
+    
+    it('should check if payload NOT equals given numeric value', function(done) {
+        genericSwitchTest("neq", 55667744, true, true, -1234, done);
+    });
+    
+    it('should return nothing when the payload does equal to desired numeric value', function(done) {
+        genericSwitchTest("neq", 10, true, false, 10, done);
+    });
+    
+    it('should check if payload is less than given value', function(done) {
+        genericSwitchTest("lt", 3, true, true, 2, done);
+    });
+    
+    it('should return nothing when the payload is not less than desired string', function(done) {
+        genericSwitchTest("lt", 3, true, false, 4, done);
+    });
+    
+    it('should check if payload less than equals given value', function(done) {
+        genericSwitchTest("lte", 3, true, true, 3, done);
+    });
+    
+    it('should check if payload is greater than given value', function(done) {
+        genericSwitchTest("gt", 3, true, true, 6, done);
+    });
+    
+    it('should return nothing when the payload is not greater than desired string', function(done) {
+        genericSwitchTest("gt", 3, true, false, -1, done);
+    });
+    
+    it('should check if payload is greater than/equals given value', function(done) {
+        genericSwitchTest("gte", 3, true, true, 3, done);
+    });
+    
+    it('should return nothing when the payload is not greater than desired string', function(done) {
+        genericSwitchTest("gt", 3, true, false, -1, done);
+    });
+    
+    it('should check if payload is greater than/equals given value', function(done) {
+        genericSwitchTest("gte", 3, true, true, 3, done);
+    });
+    
+    it('should check if payload is between given values', function(done) {
+        twoFieldSwitchTest("btwn", 3, 5, true, true, 4, done);
+    });
+    
+    it('should check if payload is not between given values', function(done) {
+        twoFieldSwitchTest("btwn", 3, 5, true, false, 12, done);
+    });
+    
+    it('should check if payload contains given value', function(done) {
+        genericSwitchTest("cont", "Hello", true, true, "Hello World!", done);
+    });
+    
+    it('should return nothing when the payload doesn\'t contain desired string', function(done) {
+        genericSwitchTest("cont", "Hello", true, false, "This is not a greeting!", done);
+    });
+    
+    it('should match regex', function(done) {
+        genericSwitchTest("regex", "[abc]+", true, true, "abbabac", done);
+    });
+    
+    it('should return nothing when the payload doesn\'t match regex', function(done) {
+        genericSwitchTest("regex", "\\d+", true, false, "This is not a digit", done);
+    });
+    
+    it('should return nothing when the payload doesn\'t contain desired string', function(done) {
+        genericSwitchTest("cont", "Hello", true, false, "This is not a greeting!", done);
+    });
+    
+    it('should check if input is true', function(done) {
+        singularSwitchTest(true, true, true, true, done);
+    });
+    
+    it('sends nothing when input is false and checking for true', function(done) {
+        singularSwitchTest(true, true, false, false, done);
+    });
+    
+    it('should check if input is indeed false', function(done) {
+        singularSwitchTest(false, true, true, false, done);
+    });
+    
+    it('sends nothing when input is false and checking for true', function(done) {
+        singularSwitchTest(false, true, false, true, done);
+    });
+    
+    it('should check if input is indeed null', function(done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"null"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        
+        
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                if(msg.payload) {
+                    try {
+                        should.fail(null, null, "msg.payload should be undefined!");   
+                    } catch (err) {
+                        done(err);
+                    }
+                } else {
+                    done();
+                }
+            });
+            switchNode1.receive({payload:undefined});
+        });
+    });
+    
+    it('should check if input is indeed not null', function(done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"nnull"}],checkall:false,outputs:1,wires:[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        
+        
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                if(msg.payload) {
+                    done();
+                } else {
+                    try {
+                        msg.payload.should.equal("Anything here");
+                    } catch (err) {
+                        done(err);
+                    }
+                }
+            });
+            switchNode1.receive({payload:"Anything here"});
+        });
+    });
+    
+    it('sends a message when the "else/otherwise" statement is selected' , function(done) {
+        singularSwitchTest("else", true, true, 123456, done);
+    });
+    
+    it('handles more than one switch statement' , function(done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"eq","v":"Hello"},{"t":"cont","v":"ello"}, {"t":"else"}],checkall:true,outputs:3,wires:[["helperNode1"], ["helperNode2"], ["helperNode3"]]},
+                    {id:"helperNode1", type:"helper", wires:[]},
+                    {id:"helperNode2", type:"helper", wires:[]},
+                    {id:"helperNode3", type:"helper", wires:[]}];
+        
+        
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var helperNode2 = helper.getNode("helperNode2");
+            var helperNode3 = helper.getNode("helperNode3");
+            
+            var nodeHitCount = 0;
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Hello");
+                    nodeHitCount++;
+                } catch (err) {
+                    done(err);
+                }
+            });
+            helperNode2.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Hello");
+                    nodeHitCount++;
+                    if(nodeHitCount == 2) {
+                        done();
+                    } else {
+                        try {
+                            should.fail(null, null, "Both statements should be triggered!");   
+                        } catch (err) {
+                            done(err);
+                        }
+                    }
+                } catch (err) {
+                    done(err);
+                }
+            });
+            helperNode3.on("input", function(msg) {
+                try {
+                    should.fail(null, null, "The otherwise/else statement should not be triggered here!");   
+                } catch (err) {
+                    done(err);
+                }
+            });
+            switchNode1.receive({payload:"Hello"});
+        });
+    });
+    
+    it('stops after first statement' , function(done) {
+        var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"eq","v":"Hello"},{"t":"cont","v":"ello"}, {"t":"else"}],checkall:"false",outputs:3,wires:[["helperNode1"], ["helperNode2"], ["helperNode3"]]},
+                    {id:"helperNode1", type:"helper", wires:[]},
+                    {id:"helperNode2", type:"helper", wires:[]},
+                    {id:"helperNode3", type:"helper", wires:[]}];
+        
+        
+        helper.load(switchNode, flow, function() {
+            var switchNode1 = helper.getNode("switchNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var helperNode2 = helper.getNode("helperNode2");
+            var helperNode3 = helper.getNode("helperNode3");
+            
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Hello");
+                    done();
+                } catch (err) {
+                    done(err);
+                }
+            });
+            helperNode2.on("input", function(msg) {
+                try {
+                    should.fail(null, null, "The otherwise/else statement should not be triggered here!");   
+                } catch (err) {
+                    done(err);
+                }
+            });
+            helperNode3.on("input", function(msg) {
+                try {
+                    should.fail(null, null, "The otherwise/else statement should not be triggered here!");   
+                } catch (err) {
+                    done(err);
+                }
+            });
+            switchNode1.receive({payload:"Hello"});
+        });
+    });
+    
+});
diff --git a/dgbuilder/test/nodes/core/logic/15-change_spec.js b/dgbuilder/test/nodes/core/logic/15-change_spec.js
new file mode 100644 (file)
index 0000000..5072dfc
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+
+var changeNode = require("../../../../nodes/core/logic/15-change.js");
+var helper = require("../../helper.js");
+
+describe('ChangeNode', function() {
+    
+    beforeEach(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function(done) {
+        helper.unload();
+        helper.stopServer(done);
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"replace","property":"payload","from":"","to":"","reg":false,"name":"changeNode","wires":[[]]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            changeNode1.should.have.property('name', 'changeNode');
+            done();
+        });
+    });
+    
+    it('sets the value of the message property', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"replace","property":"payload","from":"","to":"changed","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("changed");
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({payload:"changeMe"});
+        });
+    });
+    
+    it('changes the value of the message property', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"change","property":"payload","from":"Hello","to":"Goodbye","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Goodbye World!");
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({payload:"Hello World!"});
+        });
+    });
+    
+    it('changes the value of the message property based on a regex', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"change","property":"payload","from":"\\d+","to":"NUMBER","reg":true,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Replace all numbers NUMBER and NUMBER");
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({payload:"Replace all numbers 12 and 14"});
+        });
+    });
+    
+    it('supports regex groups', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"change","property":"payload","from":"(Hello)","to":"$1-$1-$1","reg":true,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal("Hello-Hello-Hello World");
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({payload:"Hello World"});
+        });
+    });
+    
+    it('Reports invalid regex', function(done) {
+        
+        var sinon = require('sinon');
+        
+        var flow = [{"id":"changeNode1","type":"change","action":"change","property":"payload","from":"\\+**+","to":"NUMBER","reg":true,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            
+            sinon.stub(changeNode1, 'error', function(error) {
+                if(error.indexOf("regular expression" > -1)) {
+                    done();
+                } else {
+                    try {
+                        should.fail(null, null, "An error should be reported for an invalid regex");
+                    } catch (err) {
+                        done(err);
+                    }
+                }
+             });
+            changeNode1.receive({payload:"This is irrelevant"});
+        });
+    });
+    
+    it('deletes the value of the message property', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"delete","property":"payload","from":"","to":"","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.should.not.have.property('payload');
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({payload:"This won't get through!"});
+        });
+    });
+    
+// TODO confirm the behaviour of the change node later,apparently calling eval such that  makeNew( msg, node.property.split("."), eval(node.to) ); is incorrect
+//    it('changes the property name of the message object', function(done) {
+//        var flow = [{"id":"changeNode1","type":"change","action":"replace","property":"payload","from":"","to":"msg.otherProp=10","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
+//                    {id:"helperNode1", type:"helper", wires:[]}];
+//        helper.load(changeNode, flow, function() {
+//            var changeNode1 = helper.getNode("changeNode1");
+//            var helperNode1 = helper.getNode("helperNode1");
+//            helperNode1.on("input", function(msg) {
+//                try {
+//                    msg.otherProp.should.equal(10);
+//                    done();
+//                } catch(err) {
+//                    done(err);
+//                }
+//            });
+//            changeNode1.receive({payload:"changeMe"});
+//        });
+//    });
+    
+    it('splits dot delimited properties into objects', function(done) {
+        var flow = [{"id":"changeNode1","type":"change","action":"replace","property":"pay.load","from":"","to":"10","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(changeNode, flow, function() {
+            var changeNode1 = helper.getNode("changeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.pay.load.should.equal("10");
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            changeNode1.receive({"pay.load":"changeMe"});
+        });
+    });
+});
+
diff --git a/dgbuilder/test/nodes/core/logic/16-range_spec.js b/dgbuilder/test/nodes/core/logic/16-range_spec.js
new file mode 100644 (file)
index 0000000..abb6c64
--- /dev/null
@@ -0,0 +1,131 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+
+var rangeNode = require("../../../../nodes/core/logic/16-range.js");
+var helper = require("../../helper.js");
+
+describe('RangeNode', function() {
+    
+    beforeEach(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function(done) {
+        helper.unload();
+        helper.stopServer(done);
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{"id":"rangeNode1","type":"range","minin":"0","maxin":"99","minout":"100","maxout":"199","action":"range","round":true,"name":"rangeNode","wires":[[]]}];
+        helper.load(rangeNode, flow, function() {
+            var rangeNode1 = helper.getNode("rangeNode1");
+            rangeNode1.should.have.property('name', 'rangeNode');
+            done();
+        });
+    });
+    
+    /**
+     * Run a generic range test
+     * @param action - scale/clamp (range limit)/roll (modulo): what action to choose
+     * @param minin - map from minimum value
+     * @param maxin - map from maximum value
+     * @param minout - map to minimum value
+     * @param maxout - map to maximum value 
+     * @param round - whether to round the result to the nearest integer
+     * @param aPayload - what payload to send to the range node
+     * @param expectedResult - what result we're expecting
+     * @param done - the callback to call when test done
+     */
+    function genericRangeTest(action, minin, maxin, minout, maxout, round, aPayload, expectedResult, done) {
+        var flow = [{"id":"rangeNode1","type":"range","minin":minin,"maxin":maxin,"minout":minout,"maxout":maxout,"action":action,"round":round,"name":"rangeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(rangeNode, flow, function() {
+            var rangeNode1 = helper.getNode("rangeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                try {
+                    msg.payload.should.equal(expectedResult);
+                    done();
+                } catch(err) {
+                    done(err);
+                }
+            });
+            rangeNode1.receive({payload:aPayload});
+        });
+    }
+    
+    it('ranges numbers up tenfold', function(done) {
+        genericRangeTest("scale", 0, 100, 0, 1000, false, 50, 500, done);
+    });
+    
+    it('ranges numbers down such as centimetres to metres', function(done) {
+        genericRangeTest("scale", 0, 100, 0, 1, false, 55, 0.55, done);
+    });
+    
+    it('wraps numbers down say for degree/rotation reading 1/2', function(done) {
+        genericRangeTest("roll", 0, 10, 0, 360, true, 15, 180, done); // 1/2 around wrap => "one and a half turns"
+    });
+    
+    it('wraps numbers around say for degree/rotation reading 1/3', function(done) {
+        genericRangeTest("roll", 0, 10, 0, 360, true, 13.3333, 120, done); // 1/3 around wrap => "one and a third turns"
+    });
+    
+    it('wraps numbers around say for degree/rotation reading 1/4', function(done) {
+        genericRangeTest("roll", 0, 10, 0, 360, true, 12.5, 90, done); // 1/4 around wrap => "one and a quarter turns"
+    });
+    
+    it('wraps numbers around say for degree/rotation reading 1/4', function(done) {
+        genericRangeTest("roll", 0, 10, 0, 360, true, 12.5, 90, done); // 1/4 around wrap => "one and a quarter turns"
+    });
+    
+    it('wraps numbers down say for degree/rotation reading 1/4', function(done) {
+        genericRangeTest("roll", 0, 10, 0, 360, true, -12.5, 270, done); // 1/4 backwards wrap => "one and a quarter turns backwards"
+    });
+    
+    it('clamps numbers within a range - over max', function(done) {
+        genericRangeTest("clamp", 0, 10, 0, 1000, false, 111, 1000, done);
+    });
+    
+    it('clamps numbers within a range - below min', function(done) {
+        genericRangeTest("clamp", 0, 10, 0, 1000, false, -1, 0, done);
+    });
+    
+    it('reports if input is not a number', function(done) {
+        var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":0,"minout":0,"maxout":0,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(rangeNode, flow, function() {
+            var rangeNode1 = helper.getNode("rangeNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            
+            var sinon = require('sinon');
+            sinon.stub(rangeNode1, 'log', function(log) {
+                if(log.indexOf("Not a number") > -1) {
+                    done();
+                } else {
+                    try {
+                        should.fail(null, null, "Non-number inputs should be reported!");   
+                    } catch (err) {
+                        done(err);
+                    }
+                }
+            });
+            
+            rangeNode1.receive({payload:"NOT A NUMBER"});
+        });
+    });
+});
diff --git a/dgbuilder/test/nodes/core/parsers/70-HTML_spec.js b/dgbuilder/test/nodes/core/parsers/70-HTML_spec.js
new file mode 100644 (file)
index 0000000..e7e4cbb
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var sinon = require("sinon");
+var path = require("path");
+var fs = require('fs-extra');
+
+var htmlNode = require("../../../../nodes/core/parsers/70-HTML.js");
+var helper = require("../../helper.js");
+
+describe('html node', function() {
+
+    var resourcesDir = __dirname+ path.sep + ".." + path.sep + ".." + path.sep + ".." + path.sep + "resources" + path.sep;
+    var file = path.join(resourcesDir, "70-HTML-test-file.html");
+    
+    before(function(done) {
+        helper.startServer(done);   
+    });
+
+    beforeEach(function() {
+        fs.existsSync(file).should.be.true;
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+  
+    it('should be loaded', function(done) {
+        var flow = [{id:"htmlNode1", type:"html", name: "htmlNode" }];
+        helper.load(htmlNode, flow, function() {
+            var htmlNode1 = helper.getNode("htmlNode1");
+            htmlNode1.should.have.property('name', 'htmlNode');
+            done();
+        });
+    });
+
+    it('should retrieve header contents as default', function(done) {
+        fs.readFile(file, 'utf8', function(err, data) {
+            var flow = [{id:"n1",type:"html",wires:[["n2"]],func:"return msg;"},
+                        {id:"n2", type:"helper"}];
+            
+            helper.load(htmlNode, flow, function() {
+                var n1 = helper.getNode("n1");
+                var n2 = helper.getNode("n2");
+                n2.on("input", function(msg) {
+                    msg.should.have.property('topic', 'bar');
+                    should.equal(msg.payload, 'This is a test page for node 70-HTML');
+                    done();
+                });
+                n1.receive({payload:data,topic: "bar"});
+            });          
+        });
+    });
+    
+    it('should retrieve paragraph contents when specified', function(done) {
+        fs.readFile(file, 'utf8', function(err, data) {
+            var flow = [{id:"n1",type:"html",wires:[["n2"]],ret:"text",tag:"p"},
+                        {id:"n2", type:"helper"}];
+            
+            helper.load(htmlNode, flow, function() {
+                var n1 = helper.getNode("n1");
+                var n2 = helper.getNode("n2");
+                n2.on("input", function(msg) {
+                    msg.should.have.property('topic', 'bar');
+                    should.equal(msg.payload, 'There\'s nothing to read here.');
+                    done();
+                });
+                n1.receive({payload:data,topic: "bar"});
+            });          
+        });
+    });
+    
+    it('should retrieve list contents as an array of html as default', function(done) {
+        fs.readFile(file, 'utf8', function(err, data) {
+            var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ol"},
+                        {id:"n2", type:"helper"}];
+            
+            helper.load(htmlNode, flow, function() {
+                var n1 = helper.getNode("n1");
+                var n2 = helper.getNode("n2");
+                n2.on("input", function(msg) {
+                    msg.should.have.property('topic', 'bar');
+                    msg.payload[0].indexOf("<li>Blue</li>").should.be.above(-1);
+                    msg.payload[0].indexOf("<li>Red</li>").should.be.above(-1);
+                    done();
+                });
+                n1.receive({payload:data,topic: "bar"});
+            });          
+        });
+    });
+
+    it('should retrieve list contents as an array of text', function(done) {
+        fs.readFile(file, 'utf8', function(err, data) {
+            var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ol",ret:"text"},
+                        {id:"n2", type:"helper"}];
+            
+            helper.load(htmlNode, flow, function() {
+                var n1 = helper.getNode("n1");
+                var n2 = helper.getNode("n2");
+                n2.on("input", function(msg) {
+                    msg.should.have.property('topic', 'bar');
+                    msg.payload.should.be.instanceof(Array).and.have.lengthOf(1);
+                    msg.payload[0].indexOf("Blue").should.be.above(-1);
+                    msg.payload[0].indexOf("Red").should.be.above(-1);
+                    done();
+                });
+                n1.receive({payload:data,topic: "bar"});
+            });          
+        });
+    });
+
+    it('should log on error', function(done) {
+        fs.readFile(file,function(err, data) {
+            var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"p"},
+                        {id:"n2", type:"helper"}];
+            
+            helper.load(htmlNode, flow, function() {
+                var n1 = helper.getNode("n1");
+                var n2 = helper.getNode("n2");
+                n1.on("log", function(msg) {
+                    msg.should.have.property('msg');
+                    msg.msg.indexOf("Error:").should.be.above(-1);
+                    msg.msg.should.startWith("Error:");
+                    done();
+                });
+                n1.receive({payload:null,topic: "bar"});
+            });          
+        });
+    });
+    
+    describe('multiple messages', function(){
+        var cnt = 0;
+        
+        afterEach(function() {
+            cnt.should.be.exactly(2);
+            cnt = 0;
+        });
+        
+        it('should retrieve list contents as html as default with output as multiple msgs ', function(done) {
+            fs.readFile(file, 'utf8', function(err, data) {
+                var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ul",as:"multi"},
+                            {id:"n2", type:"helper"}];
+                
+                helper.load(htmlNode, flow, function() {
+                    var n1 = helper.getNode("n1");
+                    var n2 = helper.getNode("n2");
+                    n2.on("input", function(msg) {
+                        cnt++;
+                        msg.should.have.property('topic', 'bar');
+                        if (cnt !== 1 && cnt !== 2) {
+                            return false;
+                        }
+                        if (cnt === 1) {
+                            msg.payload.indexOf("<li>Apple</li>").should.be.above(-1);
+                            msg.payload.indexOf("<li>Pear</li>").should.be.above(-1);     
+                        } else if (cnt === 2) {
+                            msg.payload.indexOf("<li>Potato</li>").should.be.above(-1);
+                            msg.payload.indexOf("<li>Parsnip</li>").should.be.above(-1);
+                            done();
+                        } 
+                    });
+                    n1.receive({payload:data,topic: "bar"});
+                });   
+            });
+        });    
+        
+        it('should retrieve list contents as text with output as multiple msgs ', function(done) {
+            fs.readFile(file, 'utf8', function(err, data) {
+                var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ul",ret:"text",as:"multi"},
+                            {id:"n2", type:"helper"}];
+                
+                helper.load(htmlNode, flow, function() {
+                    var n1 = helper.getNode("n1");
+                    var n2 = helper.getNode("n2");
+                    n2.on("input", function(msg) {
+                        cnt++;
+                        msg.should.have.property('topic', 'bar');
+                        if (cnt !== 1 && cnt !== 2) {
+                            return false;
+                        }
+                        if (cnt === 1) {
+                            msg.payload.indexOf("Apple").should.be.above(-1);
+                            msg.payload.indexOf("Pear").should.be.above(-1);     
+                        } else if (cnt === 2) {
+                            msg.payload.indexOf("Potato").should.be.above(-1);
+                            msg.payload.indexOf("Parsnip").should.be.above(-1);
+                            done();
+                        } 
+                    });
+                    n1.receive({payload:data,topic: "bar"});
+                });          
+            });
+        });
+        
+    });
+});
diff --git a/dgbuilder/test/nodes/core/parsers/70-JSON_spec.js b/dgbuilder/test/nodes/core/parsers/70-JSON_spec.js
new file mode 100644 (file)
index 0000000..b2ebe71
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var jsonNode = require("../../../../nodes/core/parsers/70-JSON.js");
+var helper = require("../../helper.js");
+
+describe('JSON node', function() {
+
+    before(function(done) {
+        helper.startServer(done);
+    });
+    
+    afterEach(function() {
+        helper.unload();
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{id:"jsonNode1", type:"json", name: "jsonNode" }];
+        helper.load(jsonNode, flow, function() {
+            var jsonNode1 = helper.getNode("jsonNode1");
+            jsonNode1.should.have.property('name', 'jsonNode');
+            done();
+        });
+    });
+
+    it('should convert a valid json string to a javascript object', function(done) {
+        var flow = [{id:"jn1",type:"json",wires:[["jn2"]],func:"return msg;"},
+                    {id:"jn2", type:"helper"}];
+        helper.load(jsonNode, flow, function() {
+            var jn1 = helper.getNode("jn1");
+            var jn2 = helper.getNode("jn2");
+            jn2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                msg.payload.should.have.property('employees');
+                msg.payload.employees[0].should.have.property('firstName', 'John');
+                msg.payload.employees[0].should.have.property('lastName', 'Smith');
+                done();
+            });
+            var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
+            jn1.receive({payload:jsonString,topic: "bar"});
+        });
+    });
+    
+    it('should convert a javascript object to a json string', function(done) {
+        var flow = [{id:"jn1",type:"json",wires:[["jn2"]],func:"return msg;"},
+                    {id:"jn2", type:"helper"}];
+        helper.load(jsonNode, flow, function() {
+            var jn1 = helper.getNode("jn1");
+            var jn2 = helper.getNode("jn2");
+            jn2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                should.equal(msg.payload, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
+                done();
+            });
+            var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
+            jn1.receive({payload:obj,topic: "bar"});
+        });
+    });
+
+    it('should log an error if asked to parse an invalid json string', function(done) {
+        var flow = [{id:"jn1",type:"json",wires:[["jn2"]],func:"return msg;"},
+                    {id:"jn2", type:"helper"}];
+        helper.load(jsonNode, flow, function() {
+            var jn1 = helper.getNode("jn1");
+            var jn2 = helper.getNode("jn2");
+            jn1.on("log", function(msg) {
+                msg.should.have.property('msg');
+                should.deepEqual("SyntaxError: Unexpected token o"+ "\nfoo", msg.msg);
+                done();
+            });
+            jn1.receive({payload:'foo',topic: "bar"});
+        });
+    });
+    
+    it('should log an error if asked to parse something thats not json or js', function(done) {
+        var flow = [{id:"jn1",type:"json",wires:[["jn2"]],func:"return msg;"},
+                    {id:"jn2", type:"helper"}];
+        helper.load(jsonNode, flow, function() {
+            var jn1 = helper.getNode("jn1");
+            var jn2 = helper.getNode("jn2");
+            jn1.on("log", function(msg) {
+                msg.should.have.property('msg');
+                should.deepEqual("dropped: 1", msg.msg);
+                done();
+            });
+            jn1.receive({payload:1,topic: "bar"});
+        });
+    });
+    
+});
diff --git a/dgbuilder/test/nodes/core/parsers/70-XML_spec.js b/dgbuilder/test/nodes/core/parsers/70-XML_spec.js
new file mode 100644 (file)
index 0000000..8bf269d
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var xmlNode = require("../../../../nodes/core/parsers/70-XML.js");
+var helper = require("../../helper.js");
+
+describe('XML node', function() {
+
+    before(function(done) {
+        helper.startServer(done);   
+    });
+
+    afterEach(function() {
+        helper.unload();
+    });
+    
+    it('should be loaded', function(done) {
+        var flow = [{id:"xmlNode1", type:"xml", name: "xmlNode" }];
+        helper.load(xmlNode, flow, function() {
+            var xmlNode1 = helper.getNode("xmlNode1");
+            xmlNode1.should.have.property('name', 'xmlNode');
+            done();
+        });
+    });
+
+    it('should convert a valid xml string to a javascript object', function(done) {
+        var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(xmlNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                msg.payload.should.have.property('employees');
+                msg.payload.employees.should.have.property('firstName');
+                should.equal(msg.payload.employees.firstName[0], 'John');
+                msg.payload.employees.should.have.property('lastName');
+                should.equal(msg.payload.employees.lastName[0], 'Smith');
+                done();
+            });
+            var string = '<employees><firstName>John</firstName><lastName>Smith</lastName></employees>';
+            n1.receive({payload:string,topic: "bar"});
+        });
+    });
+   
+    it('should convert a javascript object to an xml string', function(done) {
+        var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(xmlNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n2.on("input", function(msg) {
+                msg.should.have.property('topic', 'bar');
+                console.log(msg.payload);
+                var index = msg.payload.indexOf('<employees><firstName>John</firstName><lastName>Smith</lastName></employees>');
+                index.should.be.above(-1);
+                done();
+            });
+            var obj = {"employees":{"firstName":["John"],"lastName":["Smith"] }};
+            n1.receive({payload:obj,topic: "bar"});
+        });
+    });
+    
+    it('should log an error if asked to parse an invalid xml string', function(done) {
+        var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(xmlNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n1.on("log", function(msg) {
+                should.deepEqual("error", msg.level);
+                done();
+            });
+            n1.receive({payload:'<not valid xml>',topic: "bar"});
+        });
+    });
+    
+    it('should log an error if asked to parse something thats not xml or js', function(done) {
+        var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
+                    {id:"n2", type:"helper"}];
+        helper.load(xmlNode, flow, function() {
+            var n1 = helper.getNode("n1");
+            var n2 = helper.getNode("n2");
+            n1.on("log", function(msg) {
+                msg.should.have.property('msg');
+                should.deepEqual("This node only handles xml strings or js objects.", msg.msg);
+                done();
+            });
+            n1.receive({payload:1,topic: "bar"});
+        });
+    });
+
+});
diff --git a/dgbuilder/test/nodes/core/storage/28-tail_spec.js b/dgbuilder/test/nodes/core/storage/28-tail_spec.js
new file mode 100644 (file)
index 0000000..0612457
--- /dev/null
@@ -0,0 +1,165 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var path = require('path');
+var fs = require('fs-extra');
+var mkdirp = require('mkdirp');
+
+var tailNode = require("../../../../nodes/core/storage/28-tail.js");
+var helper = require("../../helper.js");
+
+describe('TailNode', function() {
+
+    var resourcesDir = path.join(__dirname,"..","..","..","resources");
+    var fileToTail = path.join(resourcesDir,"28-tail-test-file.txt");
+
+    beforeEach(function(done) {
+        fs.writeFileSync(fileToTail, "Tail message line 1\nTail message line 2\n");
+        helper.startServer(done);
+    });
+
+    afterEach(function(done) {
+        helper.unload().then(function() {
+            fs.unlinkSync(fileToTail);
+            helper.stopServer(done);
+        });
+    });
+
+    it('should be loaded', function(done) {
+        var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail}];
+        helper.load(tailNode, flow, function() {
+            var tailNode1 = helper.getNode("tailNode1");
+            tailNode1.should.have.property('name', 'tailNode');
+            done();
+        });
+    });
+
+    it('tail should tail a file', function(done) {
+        var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(tailNode, flow, function() {
+            var tailNode1 = helper.getNode("tailNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var inputCounter = 0;
+            helperNode1.on("input", function(msg) {
+                //console.log(msg);
+                msg.should.have.property('topic', fileToTail);
+                msg.payload.should.equal("Tail message line " + (++inputCounter + 2));
+                if (inputCounter === 2) {
+                    done();
+                }
+            });
+            setTimeout( function() {
+                fs.appendFileSync(fileToTail, "Tail message line 3\n");
+                fs.appendFileSync(fileToTail, "Tail message line 4\n");
+            },100);
+        });
+    });
+
+    it('tail should work in non-split mode', function(done) {
+        var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":false, "filename":fileToTail, "wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(tailNode, flow, function() {
+            var tailNode1 = helper.getNode("tailNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                //console.log(msg);
+                msg.should.have.property('topic', fileToTail);
+                msg.payload.should.equal("Tail message line 5\nTail message line 6\n");
+                done();
+            });
+            setTimeout( function() {
+                fs.appendFileSync(fileToTail, "Tail message line 5\nTail message line 6\n");
+            },150);
+        });
+    });
+
+    it('tail should handle a non-existent file', function(done) {
+        fs.unlinkSync(fileToTail);
+        var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(tailNode, flow, function() {
+            var tailNode1 = helper.getNode("tailNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            helperNode1.on("input", function(msg) {
+                msg.should.have.property('topic', fileToTail);
+                msg.payload.should.equal("Tail message line");
+                done();
+            });
+            setTimeout( function() {
+                fs.writeFileSync(fileToTail, "Tail message line\n");
+            },150);
+        });
+    });
+    /*
+    it('tail should handle file truncation', function(done) {
+        var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
+                    {id:"helperNode1", type:"helper", wires:[]}];
+        helper.load(tailNode, flow, function() {
+            var tailNode1 = helper.getNode("tailNode1");
+            var helperNode1 = helper.getNode("helperNode1");
+            var inputCounter = 0;
+            var warned = false;
+            tailNode1.on("log", function(msg) {
+                if (msg.level == "warn") { warned = true; }
+            });
+            helperNode1.on("input", function(msg) {
+                console.log("inputCounter =",inputCounter);
+                console.log(msg);
+                msg.should.have.property('topic', fileToTail);
+                inputCounter++;
+                if (inputCounter === 1) {
+                    warned.should.be.false;
+                    msg.payload.should.equal("Tail message line append");
+                } else if (inputCounter === 2) {
+                    msg.payload.should.equal("Tail message line truncate");
+                } else {
+                    msg.payload.should.equal("Tail message line append "+inputCounter);
+                }
+                
+                if (inputCounter === 5) {
+                    setTimeout(function() {
+                        warned.should.be.true;
+                        done();
+                    },100);
+                }
+            });
+            var actions = [
+                function() { fs.appendFileSync(fileToTail, "Tail message line append\n");},
+                function() { fs.writeFileSync(fileToTail, "Tail message line truncate\n");},
+                function() { fs.appendFileSync(fileToTail, "Tail message line append 3\n");},
+                function() { fs.appendFileSync(fileToTail, "Tail message line append 4\n");},
+                function() { fs.appendFileSync(fileToTail, "Tail message line append 5\n");}
+            ];
+            
+            function processAction() {
+                var action = actions.shift();
+                action();
+                if (actions.length > 0) {
+                    setTimeout(function() {
+                        processAction();
+                    },250);
+                }
+            }
+            setTimeout( function() {
+                processAction();
+            },150);
+        });
+    });
+    */
+
+});
diff --git a/dgbuilder/test/nodes/helper.js b/dgbuilder/test/nodes/helper.js
new file mode 100644 (file)
index 0000000..9b371ca
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var when = require("when");
+var request = require('supertest');
+var nock;
+if (!process.version.match(/^v0\.[0-9]\./)) {
+    // only set nock for node >= 0.10
+    try {
+        nock = require('nock');
+    } catch (err) {
+        // nevermind, will skip nock tests
+        nock = null;
+    }
+}
+var RED = require("../../red/red.js");
+var redNodes = require("../../red/nodes");
+var flows = require("../../red/nodes/flows");
+var credentials = require("../../red/nodes/credentials");
+var comms = require("../../red/comms.js");
+
+var http = require('http');
+var express = require('express');
+var app = express();
+
+var address = '127.0.0.1';
+var listenPort = 0; // use ephemeral port
+var port;
+var url;
+
+var server;
+
+function helperNode(n) {
+    RED.nodes.createNode(this, n);
+}
+
+module.exports = {
+    load: function(testNode, testFlows, testCredentials, cb) {
+        if (typeof testCredentials === 'function') {
+            cb = testCredentials;
+            testCredentials = {};
+        }
+
+        var storage = {
+            getFlows: function() {
+                var defer = when.defer();
+                defer.resolve(testFlows);
+                return defer.promise;
+            },
+            getCredentials: function() {
+                var defer = when.defer();
+                defer.resolve(testCredentials);
+                return defer.promise;
+            },
+            saveCredentials: function() {
+                // do nothing
+            },
+        };
+        var settings = {
+            available: function() { return false; }
+        };
+
+        redNodes.init(settings, storage);
+        credentials.init(storage);
+        RED.nodes.registerType("helper", helperNode);
+        testNode(RED);
+        flows.load().then(function() {
+            should.deepEqual(testFlows, flows.getFlows());
+            cb();
+        });
+    },
+    unload: function() {
+        // TODO: any other state to remove between tests?
+        redNodes.clearRegistry();
+        return flows.stopFlows();
+    },
+
+    getNode: function(id) {
+        return flows.get(id);
+    },
+
+    credentials: credentials,
+
+    clearFlows: function() {
+        return flows.clear();
+    },
+
+    request: function() {
+        return request(RED.httpAdmin);
+    },
+
+    startServer: function(done) {
+        server = http.createServer(function(req,res){app(req,res);});
+        RED.init(server, {});
+        server.listen(listenPort, address);
+        server.on('listening', function() {
+            port = server.address().port;
+            url = 'http://' + address + ':' + port;
+            comms.start();
+            done();
+        });
+    },
+    //TODO consider saving TCP handshake/server reinit on start/stop/start sequences
+    stopServer: function(done) {
+        if(server) {
+            server.close(done);
+        }
+    },
+
+    url: function() { return url; },
+
+    nock: nock,
+
+};
diff --git a/dgbuilder/test/red/cli/lib/config_spec.js b/dgbuilder/test/red/cli/lib/config_spec.js
new file mode 100644 (file)
index 0000000..68e960a
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var sinon = require("sinon");
+var fs = require("fs");
+
+var config = require("../../../../red/cli/lib/config");
+
+describe("cli config", function() {
+    afterEach(function() {
+        config.unload();
+    });
+    it('loads preferences when target referenced', sinon.test(function() {
+        this.stub(fs,"readFileSync",function() {
+            return '{"target":"http://example.com:1880"}'
+        });
+        config.target.should.eql("http://example.com:1880");
+    }));
+    it('provide default value for target', sinon.test(function() {
+        this.stub(fs,"readFileSync",function() {
+            return '{}'
+        });
+        config.target.should.eql("http://localhost:1880");
+    }));
+    it('saves preferences when target set', sinon.test(function() {
+        this.stub(fs,"readFileSync",function() {
+            return '{"target":"http://another.example.com:1880"}'
+        });
+        this.stub(fs,"writeFileSync",function() {});
+        
+        config.target.should.eql("http://another.example.com:1880");
+        config.target = "http://final.example.com:1880";
+        
+        fs.readFileSync.calledOnce.should.be.true;
+        fs.writeFileSync.calledOnce.should.be.true;
+        
+    }));
+        
+});
\ No newline at end of file
diff --git a/dgbuilder/test/red/cli/lib/request_spec.js b/dgbuilder/test/red/cli/lib/request_spec.js
new file mode 100644 (file)
index 0000000..7d2b5ac
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var sinon = require("sinon");
+var fs = require("fs");
+var request = require("request");
+
+var apiRequest = require("../../../../red/cli/lib/request");
+var config = require("../../../../red/cli/lib/config");
+
+describe("cli request", function() {
+    var sandbox = sinon.sandbox.create();
+    before(function() {
+        sandbox.stub(fs,"readFileSync",function() {
+            return '{"target":"http://example.com:1880"}'
+        });
+    });
+    after(function() {
+        sandbox.restore();
+    });
+                
+    it('returns the json response to a get', sinon.test(function(done) {
+        this.stub(request, 'get').yields(null, {statusCode:200}, JSON.stringify({a: "b"}));
+            
+        apiRequest("/foo",{}).then(function(res) {
+            res.should.eql({a:"b"});
+            done();
+        }).otherwise(function(err) {
+            done(err);
+        });
+    }));
+});
\ No newline at end of file
diff --git a/dgbuilder/test/red/cli/nr-cli_spec.js b/dgbuilder/test/red/cli/nr-cli_spec.js
new file mode 100644 (file)
index 0000000..59a5c64
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
\ No newline at end of file
diff --git a/dgbuilder/test/red/comms_spec.js b/dgbuilder/test/red/comms_spec.js
new file mode 100644 (file)
index 0000000..dce4d83
--- /dev/null
@@ -0,0 +1,189 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var http = require('http');
+var express = require('express');
+var app = express();
+var WebSocket = require('ws');
+
+var comms = require("../../red/comms.js");
+var address = '127.0.0.1';
+var listenPort = 0; // use ephemeral port
+
+describe("comms", function() {
+    describe("with default keepalive", function() {
+        var server;
+        var url;
+        var port;
+        before(function(done) {
+            server = http.createServer(function(req,res){app(req,res)});
+            comms.init(server, {});
+            server.listen(listenPort, address);
+            server.on('listening', function() {
+                port = server.address().port;
+                url = 'http://' + address + ':' + port + '/comms';
+                comms.start();
+                done();
+            });
+        });
+        
+        after(function() {
+            comms.stop();
+        });
+    
+        it('accepts connection', function(done) {
+            var ws = new WebSocket(url);
+            ws.on('open', function() {
+                ws.close();
+                done();
+            });
+        });
+    
+        it('publishes message after subscription', function(done) {
+            var ws = new WebSocket(url);
+            ws.on('open', function() {
+                ws.send('{"subscribe":"topic1"}');
+                comms.publish('topic1', 'foo');
+            });
+            ws.on('message', function(msg) {
+                msg.should.equal('{"topic":"topic1","data":"foo"}');
+                ws.close();
+                done();
+            });
+        });
+    
+        it('publishes retained message for subscription', function(done) {
+            comms.publish('topic2', 'bar', true);
+            var ws = new WebSocket(url);
+            ws.on('open', function() {
+                ws.send('{"subscribe":"topic2"}');
+            });
+            ws.on('message', function(msg) {
+                msg.should.equal('{"topic":"topic2","data":"bar"}');
+                ws.close();
+                done();
+            });
+        });
+    
+        it('retained message is deleted by non-retained message', function(done) {
+            comms.publish('topic3', 'retained', true);
+            comms.publish('topic3', 'non-retained');
+            var ws = new WebSocket(url);
+            ws.on('open', function() {
+                ws.send('{"subscribe":"topic3"}');
+                comms.publish('topic3', 'new');
+            });
+            ws.on('message', function(msg) {
+                msg.should.equal('{"topic":"topic3","data":"new"}');
+                ws.close();
+                done();
+            });
+        });
+    
+        it('malformed messages are ignored',function(done) {
+            var ws = new WebSocket(url);
+            ws.on('open', function() {
+                ws.send('not json');
+                ws.send('[]');
+                ws.send('{"subscribe":"topic3"}');
+                comms.publish('topic3', 'correct');
+            });
+            ws.on('message', function(msg) {
+                msg.should.equal('{"topic":"topic3","data":"correct"}');
+                ws.close();
+                done();
+            });
+        });
+    
+        // The following test currently fails due to minimum viable
+        // implementation. More test should be written to test topic
+        // matching once this one is passing
+    
+        if (0) {
+            it('receives message on correct topic', function(done) {
+                var ws = new WebSocket(url);
+                ws.on('open', function() {
+                    ws.send('{"subscribe":"topic4"}');
+                    comms.publish('topic5', 'foo');
+                    comms.publish('topic4', 'bar');
+                });
+                ws.on('message', function(msg) {
+                    msg.should.equal('{"topic":"topic4","data":"bar"}');
+                    ws.close();
+                    done();
+                });
+            });
+        }
+    });
+
+    describe("keep alives", function() {
+        var server;
+        var url;
+        var port;
+        before(function(done) {
+            server = http.createServer(function(req,res){app(req,res)});
+            comms.init(server, {webSocketKeepAliveTime: 100});
+            server.listen(listenPort, address);
+            server.on('listening', function() {
+                port = server.address().port;
+                url = 'http://' + address + ':' + port + '/comms';
+                comms.start();
+                done();
+            });
+        });
+        after(function() {
+            comms.stop();
+        });
+        it('are sent', function(done) {
+            var ws = new WebSocket(url);
+            var count = 0;
+            ws.on('message', function(data) {
+                var msg = JSON.parse(data);
+                msg.should.have.property('topic','hb');
+                msg.should.have.property('data').be.a.Number;
+                count++;
+                if (count == 3) {
+                    ws.close();
+                    done();
+                }
+            });
+        });
+        it('are not sent if other messages are sent', function(done) {
+            var ws = new WebSocket(url);
+            var count = 0;
+            var interval;
+            ws.on('open', function() {
+                ws.send('{"subscribe":"foo"}');
+                interval = setInterval(function() {
+                    comms.publish('foo', 'bar');
+                }, 50);
+            });
+            ws.on('message', function(data) {
+                var msg = JSON.parse(data);
+                msg.should.have.property('topic', 'foo');
+                msg.should.have.property('data', 'bar');
+                count++;
+                if (count == 5) {
+                    clearInterval(interval);
+                    ws.close();
+                    done();
+                }
+            });
+        });
+    });
+
+});
diff --git a/dgbuilder/test/red/events_spec.js b/dgbuilder/test/red/events_spec.js
new file mode 100644 (file)
index 0000000..2475926
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+
+describe("red/events", function() {
+    it('can be required without errors', function() {
+        require("../../red/events");
+    });
+});
diff --git a/dgbuilder/test/red/library_spec.js b/dgbuilder/test/red/library_spec.js
new file mode 100644 (file)
index 0000000..5225528
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var sinon = require('sinon');
+var request = require('supertest');
+var http = require('http');
+var express = require('express');
+
+var fs = require('fs-extra');
+var path = require('path');
+var when = require('when');
+
+var app = express();
+var RED = require("../../red/red.js");
+var server = require("../../red/server.js");
+var nodes = require("../../red/nodes");
+
+describe("library", function() {
+    var userDir = path.join(__dirname,".testUserHome");
+    before(function(done) {
+        fs.remove(userDir,function(err) {
+            fs.mkdir(userDir,function() {
+                sinon.stub(nodes, 'load', function() {
+                    return when.promise(function(resolve,reject){
+                        resolve([]);
+                    });
+                });
+                RED.init(http.createServer(function(req,res){app(req,res)}),
+                         {userDir: userDir});
+                server.start().then(function () { done(); });
+            });
+        });
+    });
+
+    after(function(done) {
+        fs.remove(userDir,done);
+        server.stop();
+        nodes.load.restore();
+    });
+
+    afterEach(function(done) {
+        fs.remove(userDir,function(err) {
+            fs.mkdir(userDir,done);
+        });
+    });
+
+    describe("flows", function() {
+        it('returns empty result', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/flows')
+                .expect(200)
+                .end(function(err,res) {
+                    if (err) {
+                        throw err;
+                    }
+                    res.body.should.not.have.property('f');
+                    done();
+                });
+        });
+
+        it('returns 404 for non-existent entry', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/flows/foo')
+                .expect(404)
+                .end(done);
+        });
+
+        it('can store and retrieve item', function(done) {
+            var flow = '[]';
+            request(RED.httpAdmin)
+                .post('/library/flows/foo')
+                .set('Content-Type', 'text/plain')
+                .send(flow)
+                .expect(204).end(function (err, res) {
+                    if (err) {
+                        throw err;
+                    }
+                    request(RED.httpAdmin)
+                        .get('/library/flows/foo')
+                        .expect(200)
+                        .end(function(err,res) {
+                            if (err) {
+                                throw err;
+                            }
+                            res.text.should.equal(flow);
+                            done();
+                        });
+                });
+        });
+
+        it('lists a stored item', function(done) {
+            request(RED.httpAdmin)
+                .post('/library/flows/bar')
+                .expect(204)
+                .end(function () {
+                    request(RED.httpAdmin)
+                        .get('/library/flows')
+                        .expect(200)
+                        .end(function(err,res) {
+                            if (err) {
+                                throw err;
+                            }
+                            res.body.should.have.property('f');
+                            should.deepEqual(res.body.f,['bar']);
+                            done();
+                        });
+                });
+        });
+
+        it('returns 403 for malicious access attempt', function(done) {
+            // without the userDir override the malicious url would be
+            // http://127.0.0.1:1880/library/flows/../../package to
+            // obtain package.json from the node-red root.
+            request(RED.httpAdmin)
+                .get('/library/flows/../../../../../package')
+                .expect(403)
+                .end(done);
+        });
+
+        it('returns 403 for malicious access attempt', function(done) {
+            // without the userDir override the malicious url would be
+            // http://127.0.0.1:1880/library/flows/../../package to
+            // obtain package.json from the node-red root.
+            request(RED.httpAdmin)
+                .post('/library/flows/../../../../../package')
+                .expect(403)
+                .end(done);
+        });
+
+    });
+
+    describe("type", function() {
+        before(function() {
+            RED.library.register('test');
+        });
+
+        it('returns empty result', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/test')
+                .expect(200)
+                .end(function(err,res) {
+                    if (err) {
+                        throw err;
+                    }
+                    res.body.should.not.have.property('f');
+                    done();
+                });
+        });
+
+        it('returns 404 for non-existent entry', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/test/foo')
+                .expect(404)
+                .end(done);
+        });
+
+        it('can store and retrieve item', function(done) {
+            var flow = '[]';
+            request(RED.httpAdmin)
+                .post('/library/test/foo')
+                .set('Content-Type', 'text/plain')
+                .send(flow)
+                .expect(204).end(function (err, res) {
+                    if (err) {
+                        throw err;
+                    }
+                    request(RED.httpAdmin)
+                        .get('/library/test/foo')
+                        .expect(200)
+                        .end(function(err,res) {
+                            if (err) {
+                                throw err;
+                            }
+                            res.text.should.equal(flow);
+                            done();
+                        });
+                });
+        });
+
+        it('lists a stored item', function(done) {
+            request(RED.httpAdmin)
+                .post('/library/test/bar')
+                .expect(204)
+                .end(function () {
+                    request(RED.httpAdmin)
+                        .get('/library/test')
+                        .expect(200)
+                        .end(function(err,res) {
+                            if (err) {
+                                throw err;
+                            }
+                            should.deepEqual(res.body,[{ fn: 'bar'}]);
+                            done();
+                        });
+                });
+        });
+
+
+        it('returns 403 for malicious access attempt', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/test/../../../../../../../../../../etc/passwd')
+                .expect(403)
+                .end(done);
+        });
+
+        it('returns 403 for malicious access attempt', function(done) {
+            request(RED.httpAdmin)
+                .get('/library/test/..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd')
+                .expect(403)
+                .end(done);
+        });
+
+        it('returns 403 for malicious access attempt', function(done) {
+            request(RED.httpAdmin)
+                .post('/library/test/../../../../../../../../../../etc/passwd')
+                .set('Content-Type', 'text/plain')
+                .send('root:x:0:0:root:/root:/usr/bin/tclsh')
+                .expect(403)
+                .end(done);
+        });
+
+    });
+});
diff --git a/dgbuilder/test/red/log_spec.js b/dgbuilder/test/red/log_spec.js
new file mode 100644 (file)
index 0000000..0fb0aaf
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+
+describe("red/log", function() {
+    it('can be required without errors', function() {
+        require("../../red/log");
+    });
+});
diff --git a/dgbuilder/test/red/nodes/Node_spec.js b/dgbuilder/test/red/nodes/Node_spec.js
new file mode 100644 (file)
index 0000000..6ac54bd
--- /dev/null
@@ -0,0 +1,297 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var sinon = require('sinon');
+var RedNode = require("../../../red/nodes/Node");
+var comms = require('../../../red/comms');
+
+describe('Node', function() {
+    describe('#constructor',function() {
+        it('is called with an id and a type',function() {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.should.have.property('id','123');
+            n.should.have.property('type','abc');
+            n.should.not.have.property('name');
+            n.wires.should.be.empty;
+        });
+        
+        it('is called with an id, a type and a name',function() {
+            var n = new RedNode({id:'123',type:'abc',name:'barney'});
+            n.should.have.property('id','123');
+            n.should.have.property('type','abc');
+            n.should.have.property('name','barney');
+            n.wires.should.be.empty;
+        });
+        
+        it('is called with an id, a type and some wires',function() {
+            var n = new RedNode({id:'123',type:'abc',wires:['123','456']});
+            n.should.have.property('id','123');
+            n.should.have.property('type','abc');
+            n.should.not.have.property('name');
+            n.wires.should.have.length(2);
+        });
+        
+    });
+    
+    describe('#close', function() {
+        it('emits close event when closed',function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.on('close',function() {
+                done();
+            });
+            var p = n.close();
+            should.not.exist(p);
+        });
+        
+        it('returns a promise when provided a callback with a done parameter',function(testdone) {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.on('close',function(done) {
+                setTimeout(function() {
+                    done();
+                },200);
+            });
+            var p = n.close();
+            should.exist(p);
+            p.then(function() {
+                testdone();
+            });
+        });
+    });
+    
+    
+    describe('#receive', function() {
+        it('emits input event when called', function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            var message = {payload:"hello world"};
+            n.on('input',function(msg) {
+                should.deepEqual(msg,message);
+                done();
+            });
+            n.receive(message);
+        });
+    });
+    
+    describe('#send', function() {
+            
+        it('emits a single message', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+            var message = {payload:"hello world"};
+            
+            n2.on('input',function(msg) {
+                // msg equals message, but is a new copy
+                should.deepEqual(msg,message);
+                should.notStrictEqual(msg,message);
+                done();
+            });
+            
+            n1.send(message);
+        });
+        
+        it('emits multiple messages on a single output', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+            
+            var messages = [
+                {payload:"hello world"},
+                {payload:"hello world again"}
+            ];
+            
+            var rcvdCount = 0;
+            
+            n2.on('input',function(msg) {
+                should.deepEqual(msg,messages[rcvdCount]);
+                should.notStrictEqual(msg,messages[rcvdCount]);
+                rcvdCount += 1;
+                if (rcvdCount == 2) {
+                    done();
+                }
+            });
+            n1.send([messages]);
+        });
+        
+        it('emits messages to multiple outputs', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2'],['n3'],['n4','n5']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+            var n3 = new RedNode({id:'n3',type:'abc'});
+            var n4 = new RedNode({id:'n4',type:'abc'});
+            var n5 = new RedNode({id:'n5',type:'abc'});
+            
+            var messages = [
+                {payload:"hello world"},
+                null,
+                {payload:"hello world again"}
+            ];
+            
+            var rcvdCount = 0;
+            
+            n2.on('input',function(msg) {
+                should.deepEqual(msg,messages[0]);
+                should.notStrictEqual(msg,messages[0]);
+                rcvdCount += 1;
+                if (rcvdCount == 3) {
+                    done();
+                }
+            });
+            
+            n3.on('input',function(msg) {
+                    should.fail(null,null,"unexpected message");
+            });
+            
+            n4.on('input',function(msg) {
+                should.deepEqual(msg,messages[2]);
+                should.notStrictEqual(msg,messages[2]);
+                rcvdCount += 1;
+                if (rcvdCount == 3) {
+                    done();
+                }
+            });
+            
+            n5.on('input',function(msg) {
+                should.deepEqual(msg,messages[2]);
+                should.notStrictEqual(msg,messages[2]);
+                rcvdCount += 1;
+                if (rcvdCount == 3) {
+                    done();
+                }
+            });
+            
+            n1.send(messages);
+        });
+
+        it('emits no messages', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+
+            n2.on('input',function(msg) {
+                should.fail(null,null,"unexpected message");
+            });
+            
+            setTimeout(function() {
+                done();
+            }, 200);
+            
+            n1.send();
+        });
+
+        it('emits messages ignoring non-existent nodes', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n9'],['n2']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+
+            var messages = [
+                {payload:"hello world"},
+                {payload:"hello world again"}
+            ];
+
+            n2.on('input',function(msg) {
+                should.deepEqual(msg,messages[1]);
+                should.notStrictEqual(msg,messages[1]);
+                done();
+            });
+
+            n1.send(messages);
+        });
+
+        it('emits messages without cloning req or res', function(done) {
+            var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
+            var n2 = new RedNode({id:'n2',type:'abc'});
+
+            var req = {};
+            var res = {};
+            var cloned = {};
+            var message = {payload: "foo", cloned: cloned, req: req, res: res};
+
+            n2.on('input',function(msg) {
+                should.deepEqual(msg, message);
+                msg.cloned.should.not.be.exactly(message.cloned);
+                msg.req.should.be.exactly(message.req);
+                msg.res.should.be.exactly(message.res);
+                done();
+            });
+
+            n1.send(message);
+        });
+
+    });
+
+    describe('#log', function() {
+        it('emits a log message', function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.on('log',function(obj) {
+                should.deepEqual({level:"log", id:n.id,
+                                  type:n.type, msg:"a log message"}, obj);
+                done();
+            });
+            n.log("a log message");
+        });
+    });
+
+    describe('#log', function() {
+        it('emits a log message with a name', function(done) {
+            var n = new RedNode({id:'123', type:'abc', name:"barney"});
+            n.on('log',function(obj) {
+                should.deepEqual({level:"log", id:n.id, name: "barney",
+                                  type:n.type, msg:"a log message"}, obj);
+                done();
+            });
+            n.log("a log message");
+        });
+    });
+
+    describe('#warn', function() {
+        it('emits a warning', function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.on('log',function(obj) {
+                should.deepEqual({level:"warn", id:n.id,
+                                  type:n.type, msg:"a warning"}, obj);
+                done();
+            });
+            n.warn("a warning");
+        });
+    });
+
+    describe('#error', function() {
+        it('emits an error message', function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            n.on('log',function(obj) {
+                should.deepEqual({level:"error", id:n.id,
+                                  type:n.type, msg:"an error message"}, obj);
+                done();
+            });
+            n.error("an error message");
+        });
+    });
+
+    describe('#status', function() {
+        after(function() {
+            comms.publish.restore();
+        });
+        it('publishes status', function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            var status = {fill:"green",shape:"dot",text:"connected"};
+            sinon.stub(comms, 'publish', function(topic, message, retain) {
+                topic.should.equal('status/123');
+                message.should.equal(status);
+                retain.should.be.true;
+                done();
+            });
+
+            n.status(status);
+        });
+    });
+
+});
diff --git a/dgbuilder/test/red/nodes/credentials_spec.js b/dgbuilder/test/red/nodes/credentials_spec.js
new file mode 100644 (file)
index 0000000..3d10461
--- /dev/null
@@ -0,0 +1,497 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var sinon = require("sinon");
+var when = require("when");
+var util = require("util");
+
+var index = require("../../../red/nodes/index");
+var credentials = require("../../../red/nodes/credentials");
+
+describe('Credentials', function() {
+    
+    afterEach(function() {
+        index.clearRegistry();
+    });
+    
+    it('loads from storage',function(done) {
+        
+        var storage = {
+            getCredentials: function() {
+                return when.promise(function(resolve,reject) {
+                    resolve({"a":{"b":1,"c":2}});
+                });
+            }
+        };
+        
+        credentials.init(storage);
+        
+        credentials.load().then(function() {
+                
+            credentials.get("a").should.have.property('b',1);
+            credentials.get("a").should.have.property('c',2);
+            
+            done();
+        });
+    });
+    
+    
+    it('saves to storage', function(done) {
+        var storage = {
+            getCredentials: function() {
+                return when.promise(function(resolve,reject) {
+                    resolve({"a":{"b":1,"c":2}});
+                });
+            },
+            saveCredentials: function(creds) {
+                return when(true);
+            }
+        };
+        sinon.spy(storage,"saveCredentials");
+        credentials.init(storage);
+        credentials.load().then(function() {
+            should.not.exist(credentials.get("b"))
+            credentials.add('b',{"d":3});
+            storage.saveCredentials.callCount.should.be.exactly(1);
+            credentials.get("b").should.have.property('d',3);
+            storage.saveCredentials.restore();
+            done();
+        });
+    });
+    
+    it('deletes from storage', function(done) {
+        var storage = {
+            getCredentials: function() {
+                return when.promise(function(resolve,reject) {
+                    resolve({"a":{"b":1,"c":2}});
+                });
+            },
+            saveCredentials: function(creds) {
+                return when(true);
+            }
+        };
+        sinon.spy(storage,"saveCredentials");
+        credentials.init(storage);
+        credentials.load().then(function() {
+            should.exist(credentials.get("a"))
+            credentials.delete('a');
+            storage.saveCredentials.callCount.should.be.exactly(1);
+            should.not.exist(credentials.get("a"));
+            storage.saveCredentials.restore();
+            done();
+        });
+            
+    });
+            
+    it('clean up from storage', function(done) {
+        var storage = {
+            getCredentials: function() {
+                return when.promise(function(resolve,reject) {
+                    resolve({"a":{"b":1,"c":2}});
+                });
+            },
+            saveCredentials: function(creds) {
+                return when(true);
+            }
+        };
+        sinon.spy(storage,"saveCredentials");
+        credentials.init(storage);
+        credentials.load().then(function() {
+            should.exist(credentials.get("a"));
+            credentials.clean(function() {
+                return false;
+            });
+            storage.saveCredentials.callCount.should.be.exactly(1);
+            should.not.exist(credentials.get("a"));
+            storage.saveCredentials.restore();
+            done();
+        });
+    });
+    
+    it('handle error loading from storage', function(done) {
+        var storage = {
+            getCredentials: function() {
+                return when.promise(function(resolve,reject) {
+                    reject("test forcing failure");
+                });
+            },
+            saveCredentials: function(creds) {
+                return when(true);
+            }
+        };
+        var logmsg = 'no errors yet';
+        sinon.stub(util, 'log', function(msg) {
+            logmsg = msg;
+        });
+        
+        credentials.init(storage);
+        credentials.load().then(function() {
+            should.equal('[red] Error loading credentials : test forcing failure', logmsg);
+            util.log.restore();
+            done();
+        }).otherwise(function(err){
+            util.log.restore();
+            done(err);
+        });
+    });
+    
+    it('credential type is not registered when extract', function(done) {
+        var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
+        var storage = {
+                getFlows: function() {
+                    var defer = when.defer();
+                    defer.resolve(testFlows);
+                    return defer.promise;
+                },
+                getCredentials: function() {
+                    return when.promise(function(resolve,reject) {
+                        resolve({"tab1":{"b":1,"c":2}});
+                    });
+                },
+                saveFlows: function(conf) {
+                    var defer = when.defer();
+                    defer.resolve();
+                    should.deepEqual(testFlows, conf);
+                    return defer.promise;
+                },
+                saveCredentials: function(creds) {
+                    return when(true);
+                },
+                getSettings: function() {
+                    return when({});
+                },
+                saveSettings: function(s) {
+                    return when();
+                }
+        };
+        function TestNode(n) {
+            index.createNode(this, n);
+            
+            this.id = 'tab1';
+            this.type = 'test';
+            this.name = 'barney';
+            var node = this;
+
+            this.on("log", function() {
+                // do nothing
+            });
+        }
+        var logmsg = 'nothing logged yet';
+        sinon.stub(util, 'log', function(msg) {
+            logmsg = msg;
+        });
+        var settings = {
+            available: function() { return false;}
+        }
+        index.init(settings, storage);
+        index.registerType('test', TestNode);   
+        index.loadFlows().then(function() {
+            var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
+            credentials.extract(testnode);
+            should.equal(logmsg, 'Credential Type test is not registered.');
+            util.log.restore();
+            done();
+        }).otherwise(function(err){
+            util.log.restore();
+            done(err);
+        });
+    });
+    
+    describe('extract and store credential updates in the provided node', function() {
+        var path = require('path');
+        var fs = require('fs-extra');
+        var http = require('http');
+        var express = require('express');
+        var server = require("../../../red/server");
+        var localfilesystem = require("../../../red/storage/localfilesystem");
+        var app = express();
+        var RED = require("../../../red/red.js");
+        
+        var userDir = path.join(__dirname,".testUserHome");
+        before(function(done) {
+            fs.remove(userDir,function(err) {
+                fs.mkdir(userDir,function() {
+                    sinon.stub(index, 'load', function() {
+                        return when.promise(function(resolve,reject){
+                            resolve([]);
+                        });
+                    });
+                    sinon.stub(localfilesystem, 'getCredentials', function() {
+                         return when.promise(function(resolve,reject) {
+                                resolve({"tab1":{"foo": 2, "pswd":'sticks'}});
+                         });
+                    }) ;
+                    RED.init(http.createServer(function(req,res){app(req,res)}),
+                             {userDir: userDir});
+                    server.start().then(function () {
+                        done(); 
+                     });
+                });
+            });
+        });
+    
+        after(function(done) {
+            fs.remove(userDir,done);
+            server.stop();
+            index.load.restore();
+            localfilesystem.getCredentials.restore();
+        });
+    
+        function TestNode(n) {
+            index.createNode(this, n);
+            var node = this;
+            this.on("log", function() {
+                // do nothing
+            });
+        }
+        
+        it(': credential updated with good value', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.have.property('foo',2);
+                
+                // set credentials to be an updated value and checking this is extracted properly
+                testnode.credentials = {"foo": 3};
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.not.have.property('foo',2);
+                credentials.get('tab1').should.have.property('foo',3);
+                done();                    
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+
+        it(': credential updated with empty value', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
+                // setting value of "foo" credential to be empty removes foo as a property
+                testnode.credentials = {"foo": ''};
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.not.have.property('foo',2);
+                credentials.get('tab1').should.not.have.property('foo');
+                done();                    
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+        it(': undefined credential updated', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
+                // setting value of an undefined credential should not change anything
+                testnode.credentials = {"bar": 4};
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.have.property('foo',2);
+                credentials.get('tab1').should.not.have.property('bar');
+                done();                    
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+        
+        it(': password credential updated', function(done) {
+            index.registerType('password', TestNode, {
+                credentials: {
+                    pswd: {type:"password"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'password',name:'barney'});   
+                // setting value of password credential should update password 
+                testnode.credentials = {"pswd": 'fiddle'};
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.have.property('pswd','fiddle');
+                credentials.get('tab1').should.not.have.property('pswd','sticks');
+                done();                    
+            }).otherwise(function(err){
+                done(err);
+            });
+        });    
+
+        it(': password credential not updated', function(done) {
+            index.registerType('password', TestNode, {
+                credentials: {
+                    pswd: {type:"password"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'password',name:'barney'});   
+                // setting value of password credential should update password 
+                testnode.credentials = {"pswd": '__PWRD__'};
+                credentials.extract(testnode);
+                should.exist(credentials.get('tab1'));
+                credentials.get('tab1').should.have.property('pswd','sticks');
+                credentials.get('tab1').should.not.have.property('pswd','__PWRD__');
+                done();                    
+            }).otherwise(function(err){
+                done(err);
+            });
+        });    
+    
+    })
+
+    describe('registerEndpoint', function() {
+        var path = require('path');
+        var fs = require('fs-extra');
+        var http = require('http');
+        var express = require('express');
+        var request = require('supertest');
+        
+        var server = require("../../../red/server");
+        var localfilesystem = require("../../../red/storage/localfilesystem");
+        var app = express();
+        var RED = require("../../../red/red.js");
+        
+        var userDir = path.join(__dirname,".testUserHome");
+        before(function(done) {
+            fs.remove(userDir,function(err) {
+                fs.mkdir(userDir,function() {
+                    sinon.stub(index, 'load', function() {
+                        return when.promise(function(resolve,reject){
+                            resolve([]);
+                        });
+                    });
+                    sinon.stub(localfilesystem, 'getCredentials', function() {
+                         return when.promise(function(resolve,reject) {
+                                resolve({"tab1":{"foo": 2, "pswd":'sticks'}});
+                         });
+                    }) ;
+                    RED.init(http.createServer(function(req,res){app(req,res)}),
+                             {userDir: userDir});
+                    server.start().then(function () {
+                        done(); 
+                     });
+                });
+            });
+        });
+    
+        after(function(done) {
+            fs.remove(userDir,done);
+            server.stop();
+            index.load.restore();
+            localfilesystem.getCredentials.restore();
+        });
+    
+        function TestNode(n) {
+            index.createNode(this, n);
+            var node = this;
+            this.on("log", function() {
+                // do nothing
+            });
+        }
+        
+        it(': valid credential type', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
+                request(RED.httpAdmin).get('/credentials/test/tab1').expect(200).end(function(err,res) {
+                    if (err) {
+                        done(err);
+                    }
+                    res.body.should.have.property('foo', 2);
+                    done();
+                });              
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+        
+        it(': password credential type', function(done) {
+            index.registerType('password', TestNode, {
+                credentials: {
+                    pswd: {type:"password"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'pswd',name:'barney'});   
+                request(RED.httpAdmin).get('/credentials/password/tab1').expect(200).end(function(err,res) {
+                    if (err) {
+                        done(err);
+                    }
+                    res.body.should.have.property('has_pswd', true);
+                    res.body.should.not.have.property('pswd');
+                    done();
+                });              
+            }).otherwise(function(err){
+                done(err);
+            });
+        });    
+        
+        it(': returns 404 for undefined credential type', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
+                request(RED.httpAdmin).get('/credentials/unknownType/tab1').expect(404).end(done);              
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+        
+        it(': undefined nodeID', function(done) {
+            index.registerType('test', TestNode, {
+                credentials: {
+                    foo: {type:"test"}
+                }
+            });   
+            index.loadFlows().then(function() {
+                var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
+                request(RED.httpAdmin).get('/credentials/test/unknownNode').expect(200).end(function(err,res) {
+                    if (err) {
+                        done(err);
+                    }
+                    var b = res.body;
+                    res.body.should.not.have.property('foo');
+                    done();
+                });              
+            }).otherwise(function(err){
+                done(err);
+            });
+        });
+        
+    })        
+    
+})     
+
diff --git a/dgbuilder/test/red/nodes/flows_spec.js b/dgbuilder/test/red/nodes/flows_spec.js
new file mode 100644 (file)
index 0000000..091bf40
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var sinon = require("sinon");
+var when = require("when");
+var flows = require("../../../red/nodes/flows");
+var RedNode = require("../../../red/nodes/Node");
+var RED = require("../../../red/nodes");
+var events = require("../../../red/events");
+var typeRegistry = require("../../../red/nodes/registry");
+
+
+var settings = {
+    available: function() { return false; }
+}
+
+function loadFlows(testFlows, cb) {
+    var storage = {
+        getFlows: function() {
+            return when.resolve(testFlows);
+        },
+        getCredentials: function() {
+            return when.resolve({});
+        }
+    };
+    RED.init(settings, storage);
+    flows.load().then(function() {
+        should.deepEqual(testFlows, flows.getFlows());
+        cb();
+    });
+}
+
+describe('flows', function() {
+
+    describe('#add',function() {
+        it('should be called by node constructor',function(done) {
+            var n = new RedNode({id:'123',type:'abc'});
+            should.deepEqual(n, flows.get("123"));
+            flows.clear().then(function() {
+                done();
+            });
+        });
+    });
+
+    describe('#each',function() {
+        it('should "visit" all nodes',function(done) {
+            var nodes = [
+                new RedNode({id:'n0'}),
+                new RedNode({id:'n1'})
+            ];
+            var count = 0;
+            flows.each(function(node) {
+                should.deepEqual(nodes[count], node);
+                count += 1;
+                if (count == 2) {
+                    done();
+                }
+            });
+        });
+    });
+
+    describe('#load',function() {
+        it('should load nothing when storage is empty',function(done) {
+            loadFlows([], done);
+        });
+
+        it('should load and start an empty tab flow',function(done) {
+            loadFlows([{"type":"tab","id":"tab1","label":"Sheet 1"}], function() {});
+            events.once('nodes-started', function() { done(); });
+        });
+
+        it('should load and start a registered node type', function(done) {
+            RED.registerType('debug', function() {});
+            var typeRegistryGet = sinon.stub(typeRegistry,"get",function(nt) {
+                return function() {};
+            });
+            loadFlows([{"id":"n1","type":"debug"}], function() { });
+            events.once('nodes-started', function() {
+                typeRegistryGet.restore();
+                done();
+            });
+        });
+
+        it('should load and start when node type is registered', function(done) {
+            var typeRegistryGet = sinon.stub(typeRegistry,"get");
+            typeRegistryGet.onCall(0).returns(null);
+            typeRegistryGet.returns(function(){});
+            
+            loadFlows([{"id":"n2","type":"inject"}], function() {
+                events.emit('type-registered','inject');
+            });
+            events.once('nodes-started', function() {
+                typeRegistryGet.restore();
+                done();
+            });
+        });
+    });
+
+    describe('#setFlows',function() {
+        it('should save and start an empty tab flow',function(done) {
+            var saved = 0;
+            var testFlows = [{"type":"tab","id":"tab1","label":"Sheet 1"}];
+            var storage = {
+                saveFlows: function(conf) {
+                    var defer = when.defer();
+                    defer.resolve();
+                    should.deepEqual(testFlows, conf);
+                    return defer.promise;
+                },
+                saveCredentials: function (creds) {
+                    return when(true);
+                }
+            };
+            RED.init(settings, storage);
+            flows.setFlows(testFlows);
+            events.once('nodes-started', function() { done(); });
+        });
+    });
+
+});
diff --git a/dgbuilder/test/red/nodes/index_spec.js b/dgbuilder/test/red/nodes/index_spec.js
new file mode 100644 (file)
index 0000000..dcb866e
--- /dev/null
@@ -0,0 +1,255 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var fs = require('fs-extra');
+var path = require('path');
+var when = require("when");
+var sinon = require('sinon');
+
+var index = require("../../../red/nodes/index");
+
+describe("red/nodes/index", function() {
+        
+    afterEach(function() {
+        index.clearRegistry();
+    });
+
+    var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
+    var storage = {
+            getFlows: function() {
+                return when(testFlows);
+            },
+            getCredentials: function() {
+                return when({"tab1":{"b":1,"c":2}});
+            },
+            saveFlows: function(conf) {
+                should.deepEqual(testFlows, conf);
+                return when();
+            },
+            saveCredentials: function(creds) {
+                return when(true);
+            }
+    };
+    
+    var settings = {
+        available: function() { return false }
+    };
+
+    function TestNode(n) {
+        index.createNode(this, n);
+        var node = this;
+        this.on("log", function() {
+            // do nothing
+        });
+    }
+    
+   it('nodes are initialised with credentials',function(done) {      
+
+        index.init(settings, storage);
+        index.registerType('test', TestNode);            
+        index.loadFlows().then(function() {
+            var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
+            testnode.credentials.should.have.property('b',1);
+            testnode.credentials.should.have.property('c',2);
+            done();
+        }).otherwise(function(err) {
+            done(err);
+        });
+
+    });
+   
+   it('flows should be initialised',function(done) {      
+        index.init(settings, storage);
+        index.loadFlows().then(function() {
+            should.deepEqual(testFlows, index.getFlows());
+            done();
+        }).otherwise(function(err) {
+            done(err);
+        });
+
+    });
+   
+   describe("registerType should register credentials definition", function() {
+       var http = require('http');
+       var express = require('express');
+       var app = express();
+       var server = require("../../../red/server");
+       var credentials = require("../../../red/nodes/credentials");
+       var localfilesystem = require("../../../red/storage/localfilesystem");
+       var RED = require("../../../red/red.js");
+       
+       var userDir = path.join(__dirname,".testUserHome");
+       before(function(done) {
+           fs.remove(userDir,function(err) {
+               fs.mkdir(userDir,function() {
+                   sinon.stub(index, 'load', function() {
+                       return when.promise(function(resolve,reject){
+                           resolve([]);
+                       });
+                   });
+                   sinon.stub(localfilesystem, 'getCredentials', function() {
+                        return when.promise(function(resolve,reject) {
+                               resolve({"tab1":{"b":1,"c":2}});
+                        });
+                   }) ;
+                   RED.init(http.createServer(function(req,res){app(req,res)}),
+                            {userDir: userDir});
+                   server.start().then(function () {
+                       done(); 
+                    });
+               });
+           });
+       });
+
+       after(function(done) {
+           fs.remove(userDir,done);
+           server.stop();
+           index.load.restore();
+           localfilesystem.getCredentials.restore();
+       });
+       
+       it(': definition defined',function(done) {      
+           index.registerType('test', TestNode, {
+               credentials: {
+                   foo: {type:"test"}
+               }   
+           }); 
+           var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});    
+           credentials.getDefinition("test").should.have.property('foo');
+           done();
+       });
+
+   });
+   
+   describe('allows nodes to be added/remove/enabled/disabled from the registry', function() {
+       var registry = require("../../../red/nodes/registry");
+       var randomNodeInfo = {id:"5678",types:["random"]};
+       
+       before(function() {
+           sinon.stub(registry,"getNodeInfo",function(id) {
+               if (id == "test") {
+                   return {id:"1234",types:["test"]};
+               } else if (id == "doesnotexist") {
+                   return null;
+               } else {
+                   return randomNodeInfo;
+               }
+           });
+           sinon.stub(registry,"removeNode",function(id) {
+               return randomNodeInfo;
+           });
+           sinon.stub(registry,"disableNode",function(id) {
+               return randomNodeInfo;
+           });
+       });
+       after(function() {
+           registry.getNodeInfo.restore();
+           registry.removeNode.restore();
+           registry.disableNode.restore();
+       });
+
+       it(': allows an unused node type to be removed',function(done) {      
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                var info = index.removeNode("5678");
+                registry.removeNode.calledOnce.should.be.true;
+                registry.removeNode.calledWith("5678").should.be.true;
+                info.should.eql(randomNodeInfo);
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+       });
+       
+       it(': allows an unused node type to be disabled',function(done) {      
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                var info = index.disableNode("5678");
+                registry.disableNode.calledOnce.should.be.true;
+                registry.disableNode.calledWith("5678").should.be.true;
+                info.should.eql(randomNodeInfo);
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+       });
+
+       it(': prevents removing a node type that is in use',function(done) {      
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                /*jshint immed: false */
+                (function() {
+                    index.removeNode("test");
+                }).should.throw();    
+                
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+       });
+       
+       it(': prevents disabling a node type that is in use',function(done) {
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                /*jshint immed: false */
+                (function() {
+                    index.disabledNode("test");
+                }).should.throw();    
+                
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+       });
+       
+       it(': prevents removing a node type that is unknown',function(done) {      
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                /*jshint immed: false */
+                (function() {
+                    index.removeNode("doesnotexist");
+                }).should.throw();    
+                
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        });
+       it(': prevents disabling a node type that is unknown',function(done) {      
+            index.init(settings, storage);
+            index.registerType('test', TestNode);            
+            index.loadFlows().then(function() {
+                /*jshint immed: false */
+                (function() {
+                    index.disableNode("doesnotexist");
+                }).should.throw();    
+                
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        });
+
+    });
+   
+   
+});
diff --git a/dgbuilder/test/red/nodes/registry_spec.js b/dgbuilder/test/red/nodes/registry_spec.js
new file mode 100644 (file)
index 0000000..81c1a2c
--- /dev/null
@@ -0,0 +1,808 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var sinon = require("sinon");
+var path = require("path");
+var when = require("when");
+
+var RedNodes = require("../../../red/nodes");
+var RedNode = require("../../../red/nodes/Node");
+var typeRegistry = require("../../../red/nodes/registry");
+var events = require("../../../red/events");
+
+afterEach(function() {
+    typeRegistry.clear();
+});
+
+describe('NodeRegistry', function() {
+    
+    var resourcesDir = __dirname+ path.sep + "resources" + path.sep;
+    
+    function stubSettings(s,available) {
+        s.available =  function() {return available;}
+        s.set = function(s,v) { return when.resolve()},
+        s.get = function(s) { return null;}
+        return s
+    }
+    var settings = stubSettings({},false);
+    var settingsWithStorage = stubSettings({},true);
+    
+    it('automatically registers new nodes',function() {
+        var testNode = RedNodes.getNode('123');
+        should.not.exist(n);
+        var n = new RedNode({id:'123',type:'abc'});
+        
+        var newNode = RedNodes.getNode('123');
+        
+        should.strictEqual(n,newNode);
+    });
+    
+    it('handles nodes that export a function', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "TestNode1",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode1.js");
+            list[0].should.have.property("types",["test-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            
+            var nodeConstructor = typeRegistry.get("test-node-1");
+            nodeConstructor.should.be.type("function");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+            
+    });
+    
+    
+    it('handles nodes that export a function returning a resolving promise', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "TestNode2",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode2.js");
+            list[0].should.have.property("types",["test-node-2"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            var nodeConstructor = typeRegistry.get("test-node-2");
+            nodeConstructor.should.be.type("function");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+            
+    });
+    
+    it('handles nodes that export a function returning a rejecting promise', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "TestNode3",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode3.js");
+            list[0].should.have.property("types",["test-node-3"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.have.property("err","fail");
+
+            var nodeConstructor = typeRegistry.get("test-node-3");
+            (nodeConstructor === null).should.be.true;
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+            
+    });
+    
+    it('handles files containing multiple nodes', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "MultipleNodes1",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","MultipleNodes1.js");
+            list[0].should.have.property("types",["test-node-multiple-1a","test-node-multiple-1b"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            
+            var nodeConstructor = typeRegistry.get("test-node-multiple-1a");
+            nodeConstructor.should.be.type("function");
+
+            nodeConstructor = typeRegistry.get("test-node-multiple-1b");
+            nodeConstructor.should.be.type("function");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('handles nested directories', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","NestedNode.js");
+            list[0].should.have.property("types",["nested-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('emits type-registered and node-icon-dir events', function(done) {
+        var eventEmitSpy = sinon.spy(events,"emit");
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "NestedDirectoryNode",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("name","NestedNode.js");
+            list[0].should.have.property("types",["nested-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            
+            eventEmitSpy.callCount.should.equal(2);
+            
+            eventEmitSpy.firstCall.args[0].should.be.equal("node-icon-dir");
+            eventEmitSpy.firstCall.args[1].should.be.equal(
+                    resourcesDir + "NestedDirectoryNode" + path.sep + "NestedNode" + path.sep + "icons");
+
+            eventEmitSpy.secondCall.args[0].should.be.equal("type-registered");
+            eventEmitSpy.secondCall.args[1].should.be.equal("nested-node-1");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            eventEmitSpy.restore();
+        });
+    });
+    
+    it('rejects a duplicate node type registration', function(done) {
+        
+        typeRegistry.init(stubSettings({
+            nodesDir:[resourcesDir + "TestNode1",resourcesDir + "DuplicateTestNode"]
+        },false));
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            
+            list.should.be.an.Array.and.have.lengthOf(2);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode1.js");
+            list[0].should.have.property("types",["test-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            
+            list[1].should.have.property("id");
+            list[1].id.should.not.equal(list[0].id);
+            
+            list[1].should.have.property("name","TestNode1.js");
+            list[1].should.have.property("types",["test-node-1"]);
+            list[1].should.have.property("enabled",true);
+            list[1].should.have.property("err");
+            /already registered/.test(list[1].err).should.be.true;
+
+            var nodeConstructor = typeRegistry.get("test-node-1");
+            // Verify the duplicate node hasn't replaced the original one
+            nodeConstructor.name.should.be.equal("TestNode");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('handles nodesDir as a string', function(done) {
+
+        typeRegistry.init(stubSettings({
+            nodesDir :resourcesDir + "TestNode1"
+        },false));
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("types",["test-node-1"]);
+            done();
+        }).catch(function(e) {
+            done("Loading of non-existing nodesDir should succeed");
+        });
+            
+    });
+    
+    it('handles invalid nodesDir',function(done) {
+
+        typeRegistry.init(stubSettings({
+            nodesDir : "wontexist"
+        },false));
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            done();
+        }).catch(function(e) {
+            done("Loading of non-existing nodesDir should succeed");
+        });
+    });
+    
+    it('returns nothing for an unregistered type config', function() {
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function(){
+            var config = typeRegistry.getNodeConfig("imaginary-shark");
+            (config === null).should.be.true;
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('excludes node files listed in nodesExcludes',function(done) {
+        typeRegistry.init(stubSettings({
+            nodesExcludes: [ "TestNode1.js" ],
+            nodesDir:[resourcesDir + "TestNode1",resourcesDir + "TestNode2"]
+        },false));
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("types",["test-node-2"]);
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('returns the node configurations', function(done) {
+        typeRegistry.init(stubSettings({
+            nodesDir:[resourcesDir + "TestNode1",resourcesDir + "TestNode2"]
+        },false));
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            
+            var nodeConfigs = typeRegistry.getNodeConfigs();
+            
+            // TODO: this is brittle...
+            nodeConfigs.should.equal("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n<script type=\"text/x-red\" data-template-name=\"test-node-2\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-2\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-2',{});</script>\n<style></style>\n");
+            
+            var nodeId = list[0].id;
+            var nodeConfig = typeRegistry.getNodeConfig(nodeId);
+            nodeConfig.should.equal("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n");
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('stores the node list', function(done) {
+        var settings = {
+            nodesDir:[resourcesDir + "TestNode1",resourcesDir + "TestNode2",resourcesDir + "TestNode3"],
+            available: function() { return true; },
+            set: function(s,v) {return when.resolve();},
+            get: function(s) { return null;}
+        }
+        var settingsSave = sinon.spy(settings,"set");
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.Array.and.have.length(3);
+            
+            settingsSave.callCount.should.equal(1);
+            settingsSave.firstCall.args[0].should.be.equal("nodes");
+            var savedList = settingsSave.firstCall.args[1];
+            
+            savedList[list[0].id].name == list[0].name;
+            savedList[list[1].id].name == list[1].name;
+            savedList[list[2].id].name == list[2].name;
+            
+            savedList[list[0].id].should.not.have.property("err");
+            savedList[list[1].id].should.not.have.property("err");
+            savedList[list[2].id].should.not.have.property("err");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            settingsSave.restore();
+        });
+            
+    });
+    
+    it('allows nodes to be added by filename', function(done) {
+        var settings = {
+            available: function() { return true; },
+            set: function(s,v) {return when.resolve();},
+            get: function(s) { return null;}
+        }            
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            typeRegistry.addNode(resourcesDir + "TestNode1/TestNode1.js").then(function(node) {
+                list = typeRegistry.getNodeList();
+                list[0].should.have.property("id");
+                list[0].should.have.property("name","TestNode1.js");
+                list[0].should.have.property("types",["test-node-1"]);
+                list[0].should.have.property("enabled",true);
+                list[0].should.not.have.property("err");
+                
+                node.should.be.an.Array.and.have.lengthOf(1);
+                node.should.eql(list);
+                
+                done();
+            }).catch(function(e) {
+                done(e);
+            });
+            
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('fails to add non-existent filename', function(done) {
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            typeRegistry.addNode(resourcesDir + "DoesNotExist/DoesNotExist.js").then(function(nodes) {
+                nodes.should.be.an.Array.and.have.lengthOf(1);
+                nodes[0].should.have.property("id");
+                nodes[0].should.have.property("types",[]);
+                nodes[0].should.have.property("err");
+                done();
+            }).otherwise(function(e) {
+                done(e);
+            });
+            
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('returns node info by type or id', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load(resourcesDir + "TestNode1",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            
+            var id = list[0].id;
+            var type = list[0].types[0];
+            
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode1.js");
+            list[0].should.have.property("types",["test-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+            
+            var info = typeRegistry.getNodeInfo(id);
+            list[0].should.eql(info);
+
+            var info2 = typeRegistry.getNodeInfo(type);
+            list[0].should.eql(info2);
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+            
+    });
+    
+    
+    it('rejects adding duplicate nodes', function(done) {
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load(resourcesDir + "TestNode1",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            
+            typeRegistry.addNode({file:resourcesDir + "TestNode1" + path.sep + "TestNode1.js"}).then(function(node) {
+                done(new Error("duplicate node loaded"));
+            }).otherwise(function(e) {
+                var list = typeRegistry.getNodeList();
+                list.should.be.an.Array.and.have.lengthOf(1);
+                done();
+            });
+            
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('removes nodes from the registry', function(done) {
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load(resourcesDir + "TestNode1",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode1.js");
+            list[0].should.have.property("types",["test-node-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.have.property("loaded",true);
+
+            typeRegistry.getNodeConfigs().length.should.be.greaterThan(0);
+            
+            var info = typeRegistry.removeNode(list[0].id);
+            
+            info.should.have.property("id",list[0].id);
+            info.should.have.property("enabled",false);
+            info.should.have.property("loaded",false);
+            
+            typeRegistry.getNodeList().should.be.an.Array.and.be.empty;
+            typeRegistry.getNodeConfigs().length.should.equal(0);
+            
+            var nodeConstructor = typeRegistry.get("test-node-1");
+            (typeof nodeConstructor).should.be.equal("undefined");
+            
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('rejects removing unknown nodes from the registry', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+
+            
+            /*jshint immed: false */
+            (function() {
+                typeRegistry.removeNode("1234");
+            }).should.throw();
+
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('scans the node_modules path for node files', function(done) {
+        var fs = require("fs");
+        var path = require("path");
+        
+        var eventEmitSpy = sinon.spy(events,"emit");
+        var pathJoin = (function() {
+            var _join = path.join;
+            return sinon.stub(path,"join",function() {
+                if (arguments.length  == 3 && arguments[2] == "package.json") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]);
+                }
+                if (arguments.length == 2 && arguments[1] == "TestNodeModule") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]);
+                }
+                return _join.apply(this,arguments);
+            });
+        })();
+        
+        var readdirSync = (function() {
+            var originalReaddirSync = fs.readdirSync;
+            var callCount = 0;
+            return sinon.stub(fs,"readdirSync",function(dir) {
+                var result = [];
+                if (callCount == 1) {
+                    result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules");
+                }
+                callCount++;
+                return result;
+            });
+        })();
+        
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",false).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(2);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNodeModule:TestNodeMod1");
+            list[0].should.have.property("types",["test-node-mod-1"]);
+            list[0].should.have.property("enabled",true);
+            list[0].should.not.have.property("err");
+
+            list[1].should.have.property("id");
+            list[1].should.have.property("name","TestNodeModule:TestNodeMod2");
+            list[1].should.have.property("types",["test-node-mod-2"]);
+            list[1].should.have.property("enabled",true);
+            list[1].should.have.property("err");
+            
+            
+            eventEmitSpy.callCount.should.equal(2);
+            
+            eventEmitSpy.firstCall.args[0].should.be.equal("node-icon-dir");
+            eventEmitSpy.firstCall.args[1].should.be.equal(
+                    resourcesDir + "TestNodeModule" + path.sep+ "node_modules" + path.sep + "TestNodeModule" + path.sep + "icons");
+
+            eventEmitSpy.secondCall.args[0].should.be.equal("type-registered");
+            eventEmitSpy.secondCall.args[1].should.be.equal("test-node-mod-1");
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            readdirSync.restore();
+            pathJoin.restore();
+            eventEmitSpy.restore();
+        });
+    });
+    
+    it('allows nodes to be added by module name', function(done) {
+        var fs = require("fs");
+        var path = require("path");
+
+        var pathJoin = (function() {
+            var _join = path.join;
+            return sinon.stub(path,"join",function() {
+                if (arguments.length  == 3 && arguments[2] == "package.json") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]);
+                }
+                if (arguments.length == 2 && arguments[1] == "TestNodeModule") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]);
+                }
+                return _join.apply(this,arguments);
+            });
+        })();
+        
+        var readdirSync = (function() {
+            var originalReaddirSync = fs.readdirSync;
+            var callCount = 0;
+            return sinon.stub(fs,"readdirSync",function(dir) {
+                var result = [];
+                if (callCount == 1) {
+                    result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules");
+                }
+                callCount++;
+                return result;
+            });
+        })();
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            typeRegistry.addModule("TestNodeModule").then(function(node) {
+                list = typeRegistry.getNodeList();
+                list.should.be.an.Array.and.have.lengthOf(2);
+                list[0].should.have.property("id");
+                list[0].should.have.property("name","TestNodeModule:TestNodeMod1");
+                list[0].should.have.property("types",["test-node-mod-1"]);
+                list[0].should.have.property("enabled",true);
+                list[0].should.not.have.property("err");
+
+                list[1].should.have.property("id");
+                list[1].should.have.property("name","TestNodeModule:TestNodeMod2");
+                list[1].should.have.property("types",["test-node-mod-2"]);
+                list[1].should.have.property("enabled",true);
+                list[1].should.have.property("err");
+                
+                node.should.eql(list);
+                
+                done();
+            }).catch(function(e) {
+                done(e);
+            });
+            
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            readdirSync.restore();
+            pathJoin.restore();
+        });
+    });
+    
+    
+    it('rejects adding duplicate node modules', function(done) {
+        var fs = require("fs");
+        var path = require("path");
+
+        var pathJoin = (function() {
+            var _join = path.join;
+            return sinon.stub(path,"join",function() {
+                if (arguments.length  == 3 && arguments[2] == "package.json") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]);
+                }
+                if (arguments.length == 2 && arguments[1] == "TestNodeModule") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]);
+                }
+                return _join.apply(this,arguments);
+            });
+        })();
+        
+        var readdirSync = (function() {
+            var originalReaddirSync = fs.readdirSync;
+            var callCount = 0;
+            return sinon.stub(fs,"readdirSync",function(dir) {
+                var result = [];
+                if (callCount == 1) {
+                    result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules");
+                }
+                callCount++;
+                return result;
+            });
+        })();
+
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load('wontexist',false).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(2);
+            typeRegistry.addModule("TestNodeModule").then(function(node) {
+                done(new Error("addModule resolved"));
+            }).otherwise(function(err) {
+                done();
+            });
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            readdirSync.restore();
+            pathJoin.restore();
+        });
+    });
+    
+    
+    it('fails to add non-existent module name', function(done) {
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            typeRegistry.addModule("DoesNotExistModule").then(function(node) {
+                done(new Error("ENOENT not thrown"));
+            }).otherwise(function(e) {
+                e.code.should.eql("MODULE_NOT_FOUND");
+                done();
+            });
+            
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('removes nodes from the registry by module', function(done) {
+        var fs = require("fs");
+        var path = require("path");
+
+        var pathJoin = (function() {
+            var _join = path.join;
+            return sinon.stub(path,"join",function() {
+                if (arguments.length  == 3 && arguments[2] == "package.json") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]);
+                }
+                if (arguments.length == 2 && arguments[1] == "TestNodeModule") {
+                    return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]);
+                }
+                return _join.apply(this,arguments);
+            });
+        })();
+        
+        var readdirSync = (function() {
+            var originalReaddirSync = fs.readdirSync;
+            var callCount = 0;
+            return sinon.stub(fs,"readdirSync",function(dir) {
+                var result = [];
+                if (callCount == 1) {
+                    result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules");
+                }
+                callCount++;
+                return result;
+            });
+        })();
+
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load('wontexist',false).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(2);
+            var res = typeRegistry.removeModule("TestNodeModule");
+            
+            res.should.be.an.Array.and.have.lengthOf(2);
+            res[0].should.have.a.property("id",list[0].id);
+            res[1].should.have.a.property("id",list[1].id);
+            
+            list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        }).finally(function() {
+            readdirSync.restore();
+            pathJoin.restore();
+        });
+            
+    });
+    
+    it('fails to remove non-existent module name', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function(){
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            /*jshint immed: false */
+            (function() {
+                typeRegistry.removeModule("DoesNotExistModule");
+            }).should.throw();
+            
+            done();
+            
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    
+    it('allows nodes to be enabled and disabled', function(done) {
+        typeRegistry.init(settingsWithStorage);
+        typeRegistry.load(resourcesDir+path.sep+"TestNode1",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.have.lengthOf(1);
+            list[0].should.have.property("id");
+            list[0].should.have.property("name","TestNode1.js");
+            list[0].should.have.property("enabled",true);
+            
+            var nodeConfig = typeRegistry.getNodeConfigs();
+            nodeConfig.length.should.be.greaterThan(0);
+            
+            var info = typeRegistry.disableNode(list[0].id);
+            info.should.have.property("id",list[0].id);
+            info.should.have.property("enabled",false);
+            
+            var list2 = typeRegistry.getNodeList();
+            list2.should.be.an.Array.and.have.lengthOf(1);
+            list2[0].should.have.property("enabled",false);
+            
+            typeRegistry.getNodeConfigs().length.should.equal(0);
+            
+            var info2 = typeRegistry.enableNode(list[0].id);
+            info2.should.have.property("id",list[0].id);
+            info2.should.have.property("enabled",true);
+            
+            var list3 = typeRegistry.getNodeList();
+            list3.should.be.an.Array.and.have.lengthOf(1);
+            list3[0].should.have.property("enabled",true);
+            
+            var nodeConfig2 = typeRegistry.getNodeConfigs();
+            nodeConfig2.should.eql(nodeConfig);
+
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+    
+    it('fails to enable/disable non-existent nodes', function(done) {
+        typeRegistry.init(settings);
+        typeRegistry.load("wontexist",true).then(function() {
+            var list = typeRegistry.getNodeList();
+            list.should.be.an.Array.and.be.empty;
+            
+            /*jshint immed: false */
+            (function() {
+                    typeRegistry.disableNode("123");
+            }).should.throw();
+            
+            /*jshint immed: false */
+            (function() {
+                typeRegistry.enableNode("123");
+            }).should.throw();
+            
+            done();
+        }).catch(function(e) {
+            done(e);
+        });
+    });
+});
diff --git a/dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.html b/dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.html
new file mode 100644 (file)
index 0000000..b637ede
--- /dev/null
@@ -0,0 +1,3 @@
+<script type="text/x-red" data-template-name="test-node-1"></script>
+<script type="text/x-red" data-help-name="test-node-1"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-1',{});</script>
diff --git a/dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.js b/dgbuilder/test/red/nodes/resources/DuplicateTestNode/TestNode1.js
new file mode 100644 (file)
index 0000000..e812141
--- /dev/null
@@ -0,0 +1,5 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function DuplicateTestNode(n) {}
+    RED.nodes.registerType("test-node-1",DuplicateTestNode);
+}
diff --git a/dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.html b/dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.html
new file mode 100644 (file)
index 0000000..5359644
--- /dev/null
@@ -0,0 +1,6 @@
+<script type="text/x-red" data-template-name="test-node-multiple-1a"></script>
+<script type="text/x-red" data-help-name="test-node-multiple-1a"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-multiple-1a',{});</script>
+<script type="text/x-red" data-template-name="test-node-multiple-1b"></script>
+<script type="text/x-red" data-help-name="test-node-multiple-1b"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-multiple-1b',{});</script>
diff --git a/dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.js b/dgbuilder/test/red/nodes/resources/MultipleNodes1/MultipleNodes1.js
new file mode 100644 (file)
index 0000000..55747c0
--- /dev/null
@@ -0,0 +1,7 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function TestNode1(n) {}
+    RED.nodes.registerType("test-node-multiple-1a",TestNode1);
+    function TestNode2(n) {}
+    RED.nodes.registerType("test-node-multiple-1b",TestNode2);
+}
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.html b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.html
new file mode 100644 (file)
index 0000000..abc823e
--- /dev/null
@@ -0,0 +1,4 @@
+<script type="text/x-red" data-template-name="nested-node-1"></script>
+<script type="text/x-red" data-help-name="nested-node-1"></script>
+<script type="text/javascript">RED.nodes.registerType('nested-node-1',{});</script>
+<style></style>
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.js b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/NestedNode.js
new file mode 100644 (file)
index 0000000..cd3148a
--- /dev/null
@@ -0,0 +1,5 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function TestNode(n) {}
+    RED.nodes.registerType("nested-node-1",TestNode);
+}
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/icons/file.txt b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/icons/file.txt
new file mode 100644 (file)
index 0000000..59a29af
--- /dev/null
@@ -0,0 +1,3 @@
+This file exists just to ensure the 'icons' directory is in the repository.
+TODO: a future test needs to ensure the right icon files are loaded - this
+      directory can be used for that
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html
new file mode 100644 (file)
index 0000000..ac9235d
--- /dev/null
@@ -0,0 +1,4 @@
+<script type="text/x-red" data-template-name="should-not-load-1"></script>
+<script type="text/x-red" data-help-name="should-not-load-1"></script>
+<script type="text/javascript">RED.nodes.registerType('should-not-load-1',{});</script>
+<style></style>
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js
new file mode 100644 (file)
index 0000000..8af249b
--- /dev/null
@@ -0,0 +1,5 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function TestNode(n) {}
+    RED.nodes.registerType("should-not-load-1",TestNode);
+}
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html
new file mode 100644 (file)
index 0000000..4212fd5
--- /dev/null
@@ -0,0 +1,4 @@
+<script type="text/x-red" data-template-name="should-not-load-3"></script>
+<script type="text/x-red" data-help-name="should-not-load-3"></script>
+<script type="text/javascript">RED.nodes.registerType('should-not-load-3',{});</script>
+<style></style>
diff --git a/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js b/dgbuilder/test/red/nodes/resources/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js
new file mode 100644 (file)
index 0000000..5856ada
--- /dev/null
@@ -0,0 +1,5 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function TestNode(n) {}
+    RED.nodes.registerType("should-not-load-3",TestNode);
+}
diff --git a/dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.html b/dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.html
new file mode 100644 (file)
index 0000000..97dbf17
--- /dev/null
@@ -0,0 +1,5 @@
+<script type="text/x-red" data-template-name="test-node-1"></script>
+<script type="text/x-red" data-help-name="test-node-1"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-1',{});</script>
+<style></style>
+<p>this should be filtered out</p>
diff --git a/dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.js b/dgbuilder/test/red/nodes/resources/TestNode1/TestNode1.js
new file mode 100644 (file)
index 0000000..bfa3b65
--- /dev/null
@@ -0,0 +1,5 @@
+// A test node that exports a function
+module.exports = function(RED) {
+    function TestNode(n) {}
+    RED.nodes.registerType("test-node-1",TestNode);
+}
diff --git a/dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.html b/dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.html
new file mode 100644 (file)
index 0000000..66b6590
--- /dev/null
@@ -0,0 +1,4 @@
+<script type="text/x-red" data-template-name="test-node-2"></script>
+<script type="text/x-red" data-help-name="test-node-2"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-2',{});</script>
+<style></style>
diff --git a/dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.js b/dgbuilder/test/red/nodes/resources/TestNode2/TestNode2.js
new file mode 100644 (file)
index 0000000..faf61a8
--- /dev/null
@@ -0,0 +1,10 @@
+// A test node that exports a function which returns a resolving promise
+
+var when = require("when");
+module.exports = function(RED) {
+    return when.promise(function(resolve,reject) {
+        function TestNode(n) {}
+        RED.nodes.registerType("test-node-2",TestNode);
+        resolve();
+    });
+}
diff --git a/dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.html b/dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.html
new file mode 100644 (file)
index 0000000..9a0f6f7
--- /dev/null
@@ -0,0 +1,3 @@
+<script type="text/x-red" data-template-name="test-node-3"></script>
+<script type="text/x-red" data-help-name="test-node-3"></script>
+<script type="text/javascript">RED.nodes.registerType('test-node-3',{});</script>
diff --git a/dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.js b/dgbuilder/test/red/nodes/resources/TestNode3/TestNode3.js
new file mode 100644 (file)
index 0000000..756dc13
--- /dev/null
@@ -0,0 +1,8 @@
+// A test node that exports a function which returns a rejecting promise
+
+var when = require("when");
+module.exports = function(RED) {
+    return when.promise(function(resolve,reject) {
+        reject("fail");
+    });
+}
diff --git a/dgbuilder/test/red/red_spec.js b/dgbuilder/test/red/red_spec.js
new file mode 100644 (file)
index 0000000..f61fd55
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+
+describe("red/red", function() {
+    it('can be required without errors', function() {
+        require("../../red/red");
+    });
+});
diff --git a/dgbuilder/test/red/server_spec.js b/dgbuilder/test/red/server_spec.js
new file mode 100644 (file)
index 0000000..b20249c
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+
+describe("red/server", function() {
+    it('can be required without errors', function() {
+        require("../../red/server");
+    });
+});
diff --git a/dgbuilder/test/red/settings_spec.js b/dgbuilder/test/red/settings_spec.js
new file mode 100644 (file)
index 0000000..fb4cbad
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var when = require("when");
+
+var settings = require("../../red/settings");
+
+
+describe("red/settings", function() {
+        
+    afterEach(function() {
+        settings.reset();
+    });
+    
+    it('wraps the user settings as read-only properties', function() {
+        var userSettings = {
+            a: 123,
+            b: "test",
+            c: [1,2,3]
+        }
+        settings.init(userSettings);
+        
+        settings.available().should.be.false;
+        
+        settings.a.should.equal(123);
+        settings.b.should.equal("test");
+        settings.c.should.be.an.Array.with.lengthOf(3);
+        
+        settings.get("a").should.equal(123);
+        settings.get("b").should.equal("test");
+        settings.get("c").should.be.an.Array.with.lengthOf(3);
+        
+        /*jshint immed: false */
+        (function() {
+            settings.a = 456;
+        }).should.throw();
+        
+        settings.c.push(5);
+        settings.c.should.be.an.Array.with.lengthOf(4);
+
+        /*jshint immed: false */
+        (function() {
+            settings.set("a",456);
+        }).should.throw();
+        
+        /*jshint immed: false */
+        (function() {
+            settings.set("a",456);
+        }).should.throw();
+
+        /*jshint immed: false */
+        (function() {
+            settings.get("unknown");
+        }).should.throw();
+
+        /*jshint immed: false */
+        (function() {
+            settings.set("unknown",456);
+        }).should.throw();
+        
+    });
+    
+    it('loads global settings from storage', function(done) {
+        var userSettings = {
+            a: 123,
+            b: "test",
+            c: [1,2,3]
+        }
+        var savedSettings = null;
+        var storage = {
+            getSettings: function() {
+                return when.resolve({globalA:789});
+            },
+            saveSettings: function(settings) {
+                savedSettings = settings;
+                return when.resolve();
+            }
+        }
+        settings.init(userSettings);
+
+        settings.available().should.be.false;
+        
+        /*jshint immed: false */
+        (function() {
+            settings.get("unknown");
+        }).should.throw();
+
+        settings.load(storage).then(function() {
+            settings.available().should.be.true;
+            settings.get("globalA").should.equal(789);
+            settings.set("globalA","abc").then(function() {
+                    savedSettings.globalA.should.equal("abc");
+                    done();
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+        
+        
+    });
+});
diff --git a/dgbuilder/test/red/storage/index_spec.js b/dgbuilder/test/red/storage/index_spec.js
new file mode 100644 (file)
index 0000000..4b60ba8
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+
+describe("red/storage/index", function() {
+    
+    it('rejects the promise when settings suggest loading a bad module', function(done) {
+        
+        var wrongModule = {
+                storageModule : "thisaintloading"
+        };
+        
+        var storage = require("../../../red/storage/index");
+       storage.init(wrongModule).then( function() {
+           var one = 1;
+           var zero = 0;
+           try {
+               zero.should.equal(one, "The initialization promise should never get resolved");   
+           } catch(err) {
+               done(err);
+           }
+       }).catch(function(e) {
+           done(); //successfully rejected promise
+       });
+    });
+    
+    it('non-string storage module', function(done) {
+        var initSetsMeToTrue = false;
+        
+        var moduleWithBooleanSettingInit = {
+                init : function() {
+                    initSetsMeToTrue = true;
+                }
+        };
+        
+        var setsBooleanModule = {
+                storageModule : moduleWithBooleanSettingInit
+        };
+        
+        var storage = require("../../../red/storage/index");
+        storage.init(setsBooleanModule);
+        initSetsMeToTrue.should.be.true;
+        done();
+    });
+    
+    it('respects storage interface', function(done) {
+        var calledFlagGetFlows = false;
+        var calledFlagGetCredentials = false;
+        var calledFlagGetAllFlows = false;
+        var calledInit = false;
+        
+        var interfaceCheckerModule = {
+                init : function (settings) {
+                    settings.should.be.an.Object;
+                    calledInit = true;
+                },
+                getFlows : function() {
+                    calledFlagGetFlows = true;
+                },
+                saveFlows : function (flows) {
+                    flows.should.be.true;
+                },
+                getCredentials : function() {
+                    calledFlagGetCredentials = true;
+                },
+                saveCredentials : function(credentials) {
+                    credentials.should.be.true;
+                },
+                getAllFlows : function() {
+                    calledFlagGetAllFlows = true;
+                },
+                getFlow : function(fn) {
+                    fn.should.equal("name");
+                },
+                saveFlow : function(fn, data) {
+                    fn.should.equal("name");
+                    data.should.be.true;
+                },
+                getLibraryEntry : function(type, path) {
+                    type.should.be.true;
+                    path.should.equal("name");
+                },
+                saveLibraryEntry : function(type, path, meta, body) {
+                    type.should.be.true;
+                    path.should.equal("name");
+                    meta.should.be.true;
+                    body.should.be.true;
+                }
+        };
+        
+        var moduleToLoad = {
+                storageModule : interfaceCheckerModule
+        };
+        var storage = require("../../../red/storage/index");
+        
+        storage.init(moduleToLoad);
+        storage.getFlows();
+        storage.saveFlows(true);
+        storage.getCredentials(); 
+        storage.saveCredentials(true);
+        storage.getAllFlows();
+        storage.getFlow("name");
+        storage.saveFlow("name", true);
+        storage.getLibraryEntry(true, "name");
+        storage.saveLibraryEntry(true, "name", true, true);
+        
+        calledInit.should.be.true;
+        calledFlagGetFlows.should.be.true;
+        calledFlagGetCredentials.should.be.true;
+        calledFlagGetAllFlows.should.be.true;
+        
+        done();
+    });
+    
+});
diff --git a/dgbuilder/test/red/storage/localfilesystem_spec.js b/dgbuilder/test/red/storage/localfilesystem_spec.js
new file mode 100644 (file)
index 0000000..a131170
--- /dev/null
@@ -0,0 +1,367 @@
+/**
+ * Copyright 2013, 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var should = require("should");
+var fs = require('fs-extra');
+var path = require('path');
+
+var localfilesystem = require("../../../red/storage/localfilesystem");
+
+describe('LocalFileSystem', function() {
+    var userDir = path.join(__dirname,".testUserHome");
+    var testFlow = [{"type":"tab","id":"d8be2a6d.2741d8","label":"Sheet 1"}];
+    beforeEach(function(done) {
+        fs.remove(userDir,function(err) {
+            fs.mkdir(userDir,done);
+        });
+    });
+    afterEach(function(done) {
+        fs.remove(userDir,done);
+    });
+
+    it('should initialise the user directory',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            fs.existsSync(path.join(userDir,"lib")).should.be.true;
+            fs.existsSync(path.join(userDir,"lib",'flows')).should.be.true;
+            done();
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should handle missing flow file',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            var flowFile = 'flows_'+require('os').hostname()+'.json';
+            var flowFilePath = path.join(userDir,flowFile);
+            fs.existsSync(flowFilePath).should.be.false;
+            localfilesystem.getFlows().then(function(flows) {
+                flows.should.eql([]);
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should save flows to the default file',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            var flowFile = 'flows_'+require('os').hostname()+'.json';
+            var flowFilePath = path.join(userDir,flowFile);
+            var flowFileBackupPath = path.join(userDir,"flows.backup");
+            fs.existsSync(flowFilePath).should.be.false;
+            fs.existsSync(flowFileBackupPath).should.be.false;
+            localfilesystem.saveFlows(testFlow).then(function() {
+                fs.existsSync(flowFilePath).should.be.true;
+                fs.existsSync(flowFileBackupPath).should.be.false;
+                localfilesystem.getFlows().then(function(flows) {
+                    flows.should.eql(testFlow);
+                    done();
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should save flows to the specified file',function(done) {
+        var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
+        var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
+        var flowFile = 'test.json';
+        var flowFilePath = path.join(userDir,flowFile);
+
+        localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
+            fs.existsSync(defaultFlowFilePath).should.be.false;
+            fs.existsSync(flowFilePath).should.be.false;
+
+            localfilesystem.saveFlows(testFlow).then(function() {
+                fs.existsSync(defaultFlowFilePath).should.be.false;
+                fs.existsSync(flowFilePath).should.be.true;
+                localfilesystem.getFlows().then(function(flows) {
+                    flows.should.eql(testFlow);
+                    done();
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should backup the flows file', function(done) {
+        var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
+        var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
+        var flowFile = 'test.json';
+        var flowFilePath = path.join(userDir,flowFile);
+        var flowFileBackupPath = path.join(userDir,"flows.backup");
+
+        localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
+            fs.existsSync(defaultFlowFilePath).should.be.false;
+            fs.existsSync(flowFilePath).should.be.false;
+            fs.existsSync(flowFileBackupPath).should.be.false;
+
+            localfilesystem.saveFlows(testFlow).then(function() {
+                fs.existsSync(flowFileBackupPath).should.be.false;
+                fs.existsSync(defaultFlowFilePath).should.be.false;
+                fs.existsSync(flowFilePath).should.be.true;
+                var content = fs.readFileSync(flowFilePath,'utf8');
+                var testFlow2 = [{"type":"tab","id":"bc5672ad.2741d8","label":"Sheet 2"}];
+                
+                localfilesystem.saveFlows(testFlow2).then(function() {
+                    fs.existsSync(flowFileBackupPath).should.be.true;
+                    fs.existsSync(defaultFlowFilePath).should.be.false;
+                    fs.existsSync(flowFilePath).should.be.true;
+                    var backupContent = fs.readFileSync(flowFileBackupPath,'utf8');
+                    content.should.equal(backupContent);
+                    var content2 = fs.readFileSync(flowFilePath,'utf8');
+                    content2.should.not.equal(backupContent);
+                    done();
+                    
+                }).otherwise(function(err) {
+                    done(err);
+                });
+                
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+            
+            
+    });
+    
+    it('should handle missing credentials', function(done) {
+        var flowFile = 'test.json';
+        var flowFilePath = path.join(userDir,flowFile);
+        var credFile = path.join(userDir,"test_cred.json");
+        localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
+            fs.existsSync(credFile).should.be.false;
+
+            localfilesystem.getCredentials().then(function(creds) {
+                creds.should.eql({});
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should handle credentials', function(done) {
+        var flowFile = 'test.json';
+        var flowFilePath = path.join(userDir,flowFile);
+        var credFile = path.join(userDir,"test_cred.json");
+
+        localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
+
+            fs.existsSync(credFile).should.be.false;
+
+            var credentials = {"abc":{"type":"creds"}};
+
+            localfilesystem.saveCredentials(credentials).then(function() {
+                fs.existsSync(credFile).should.be.true;
+                localfilesystem.getCredentials().then(function(creds) {
+                    creds.should.eql(credentials);
+                    done();
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return an empty list of library flows',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            localfilesystem.getAllFlows().then(function(flows) {
+                flows.should.eql({});
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return a valid list of library flows',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            var flowLib = path.join(userDir,"lib","flows");
+            fs.closeSync(fs.openSync(path.join(flowLib,"A.json"),"w"));
+            fs.closeSync(fs.openSync(path.join(flowLib,"B.json"),"w"));
+            fs.mkdirSync(path.join(flowLib,"C"));
+            fs.closeSync(fs.openSync(path.join(flowLib,"C","D.json"),"w"));
+            var testFlowsList = {"d":{"C":{"f":["D"]}},"f":["A","B"]};
+
+            localfilesystem.getAllFlows().then(function(flows) {
+                flows.should.eql(testFlowsList);
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should fail a non-existent flow', function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            localfilesystem.getFlow("a/b/c.json").then(function(flow) {
+                should.fail(flow,"No flow","Flow found");
+            }).otherwise(function(err) {
+                // err should be null, so this will pass
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return a flow',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            var testflowString = JSON.stringify(testFlow);
+            localfilesystem.saveFlow("a/b/c/d.json",testflowString).then(function() {
+                localfilesystem.getFlow("a/b/c/d.json").then(function(flow) {
+                    flow.should.eql(testflowString);
+                    done();
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return an empty list of library objects',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            localfilesystem.getLibraryEntry('object','').then(function(flows) {
+                flows.should.eql({});
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return an error for a non-existent library object',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            localfilesystem.getLibraryEntry('object','A/B').then(function(flows) {
+                should.fail(null,null,"non-existent flow");
+            }).otherwise(function(err) {
+                should.exist(err);
+                done();
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    function createObjectLibrary() {
+        var objLib = path.join(userDir,"lib","object");
+        fs.mkdirSync(objLib);
+        fs.mkdirSync(path.join(objLib,"A"));
+        fs.mkdirSync(path.join(objLib,"B"));
+        fs.mkdirSync(path.join(objLib,"B","C"));
+        fs.writeFileSync(path.join(objLib,"file1.js"),"// abc: def\n// not a metaline \n\n Hi",'utf8');
+        fs.writeFileSync(path.join(objLib,"B","file2.js"),"// ghi: jkl\n// not a metaline \n\n Hi",'utf8');
+    }
+
+    it('should return a directory listing of library objects',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            createObjectLibrary();
+
+            localfilesystem.getLibraryEntry('object','').then(function(flows) {
+                flows.should.eql([ 'A', 'B', { abc: 'def', fn: 'file1.js' } ]);
+                localfilesystem.getLibraryEntry('object','B').then(function(flows) {
+                    flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
+                    localfilesystem.getLibraryEntry('object','B/C').then(function(flows) {
+                        flows.should.eql([]);
+                        done();
+                    }).otherwise(function(err) {
+                        done(err);
+                    });
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return a library object',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            createObjectLibrary();
+            localfilesystem.getLibraryEntry('object','B/file2.js').then(function(body) {
+                body.should.eql("// not a metaline \n\n Hi");
+                done();
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+    it('should return a newly saved library object',function(done) {
+        localfilesystem.init({userDir:userDir}).then(function() {
+            createObjectLibrary();
+            localfilesystem.getLibraryEntry('object','B').then(function(flows) {
+                flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
+                localfilesystem.saveLibraryEntry('object','B/D/file3.js',{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() {
+                    localfilesystem.getLibraryEntry('object','B/D').then(function(flows) {
+                        flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]);
+                        localfilesystem.getLibraryEntry('object','B/D/file3.js').then(function(body) {
+                            body.should.eql("// another non meta line\n\n Hi There");
+                            done();
+                        }).otherwise(function(err) {
+                            done(err);
+                        });
+                    }).otherwise(function(err) {
+                        done(err);
+                    });
+                }).otherwise(function(err) {
+                    done(err);
+                });
+            }).otherwise(function(err) {
+                done(err);
+            });
+        }).otherwise(function(err) {
+            done(err);
+        });
+    });
+
+});
diff --git a/dgbuilder/test/red/ui_spec.js b/dgbuilder/test/red/ui_spec.js
new file mode 100644 (file)
index 0000000..b9de7bf
--- /dev/null
@@ -0,0 +1,177 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var request = require("supertest");
+var express = require("express");
+var redUI = require("../../red/ui");
+
+
+describe("red/ui icon handler", function() {
+    it('returns the default icon when getting an unknown icon', function(done) {
+        var app = express();
+        redUI({},app);
+        request(app)
+            .get("/icons/youwonthaveme.png")
+            .expect('Content-Type', /image\/png/)
+            .expect(200)
+            .end(function(err, res){
+                if (err){
+                    return done(err);
+                }
+                done();
+              });
+    });
+    
+    it('returns an icon from disk', function(done) {
+        var app = express();
+        redUI({},app);
+        request(app)
+            .get("/icons/arduino.png")
+            .expect('Content-Type', /image\/png/)
+            .expect(200)
+            .end(function(err, res){
+                if (err){
+                    return done(err);
+                }
+                done();
+              });
+    });
+});
+
+describe("icon cache handler", function() {
+    var fs = require('fs-extra');
+    var path = require('path');
+    var events = require("../../red/events");
+    
+    var tempDir = path.join(__dirname,".tmp/");
+    var cachedFakePNG = tempDir + "cacheMe.png";
+    
+    
+    beforeEach(function(done) {
+        fs.remove(tempDir,function(err) {
+            fs.mkdirSync(tempDir);
+            fs.writeFileSync(cachedFakePNG, "Hello PNG\n");
+            done();
+        });     
+    });
+    afterEach(function(done) {
+        fs.exists(cachedFakePNG, function(exists) {
+          if(exists) {
+              fs.unlinkSync(cachedFakePNG);
+          } 
+          fs.remove(tempDir,done);
+        })
+    });
+    
+    /*
+     * This test case test that:
+     * 1) any directory can be added to the path lookup (such as /tmp) by
+     * calling the right event
+     * 2) that a file we know exists gets cached so that the lookup/verification
+     * of actual existence doesn't occur again when a subsequent request comes in
+     * 
+     * The second point verifies that the cache works. If the cache wouldn't work
+     * the default PNG would be served
+     */
+    it('returns an icon using icon cache', function(done) {        
+        var app = express();
+        redUI({},app);
+        events.emit("node-icon-dir", tempDir);
+        request(app)
+            .get("/icons/cacheMe.png")
+            .expect('Content-Type', /image\/png/)
+            .expect(200)
+            .end(function(err, res){
+                if (err){
+                    return done(err);
+                }
+                fs.unlink(cachedFakePNG, function(err) {
+                    if(err) {
+                        return done(err);
+                    }
+                    request(app)
+                    .get("/icons/cacheMe.png")
+                    .expect('Content-Type', /text\/html/)
+                    .expect(404)
+                    .end(function(err, res){
+                        if (err){
+                            return done(err);
+                        }
+                        done();
+                      });
+                });
+              });
+    });
+});
+
+describe("red/ui settings handler", function() {
+    it('returns the provided settings', function(done) {
+        var settings = {
+                httpNodeRoot: "testHttpNodeRoot",
+                version: "testVersion",
+        };
+        var app = express();
+        redUI(settings,app);
+        request(app)
+            .get("/settings")
+            .expect('Content-Type', /application\/json/)
+            .expect(200, "{\n  \"httpNodeRoot\": \"testHttpNodeRoot\",\n  \"version\": \"testVersion\"\n}")
+            .end(function(err, res){
+                if (err){
+                    return done(err);
+                }
+                done();
+            });
+        
+    });
+});
+
+describe("red/ui root handler", function() {
+    it('server up the main page', function(done) {
+        var app = express();
+        redUI({},app);
+        
+        request(app)
+            .get("/")
+            .expect('Content-Type', /text\/html/)
+            .expect(200)
+            .end(function(err, res){
+                if (err){
+                    return done(err);
+                }
+                done();
+            });
+        
+    });
+    
+    it('redirects to path ending with /', function(done) {
+        var rapp = express();
+        redUI({},rapp);
+
+        var app = express().use('/root', rapp);
+        
+        request(app)
+        .get("/root")
+        .expect('Content-Type', /text\/plain/)
+        .expect(302)
+        .end(function(err, res){
+            if (err){
+                return done(err);
+            }
+            done();
+          });
+        
+    });
+});
diff --git a/dgbuilder/test/red/util_spec.js b/dgbuilder/test/red/util_spec.js
new file mode 100644 (file)
index 0000000..5200ef1
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Copyright 2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+var should = require("should");
+var util = require("../../red/util");
+
+describe("red/util", function() {
+    describe('ensureString', function() {
+        it('strings are preserved', function() {
+            util.ensureString('string').should.equal('string');
+        });
+        it('Buffer is converted', function() {
+            var s = util.ensureString(new Buffer('foo'));
+            s.should.equal('foo');
+            (typeof s).should.equal('string');
+        });
+        it('Object is converted to JSON', function() {
+            var s = util.ensureString({foo: "bar"});
+            (typeof s).should.equal('string');
+            should.deepEqual(JSON.parse(s), {foo:"bar"});
+        });
+        it('stringifies other things', function() {
+            var s = util.ensureString(123);
+            (typeof s).should.equal('string');
+            s.should.equal('123');
+        });
+    });
+
+    describe('ensureBuffer', function() {
+        it('Buffers are preserved', function() {
+            var b = new Buffer('');
+            util.ensureBuffer(b).should.equal(b);
+        });
+        it('string is converted', function() {
+            var b = util.ensureBuffer('foo');
+            var expected = new Buffer('foo');
+            for (var i = 0; i < expected.length; i++) {
+                b[i].should.equal(expected[i]);
+            }
+            Buffer.isBuffer(b).should.equal(true);
+        });
+        it('Object is converted to JSON', function() {
+            var obj = {foo: "bar"}
+            var b = util.ensureBuffer(obj);
+            Buffer.isBuffer(b).should.equal(true);
+            should.deepEqual(JSON.parse(b), obj);
+        });
+        it('stringifies other things', function() {
+            var b = util.ensureBuffer(123);
+            Buffer.isBuffer(b).should.equal(true);
+            var expected = new Buffer('123');
+            for (var i = 0; i < expected.length; i++) {
+                b[i].should.equal(expected[i]);
+            }
+        });
+    });
+});
+
diff --git a/dgbuilder/test/resources/70-HTML-test-file.html b/dgbuilder/test/resources/70-HTML-test-file.html
new file mode 100644 (file)
index 0000000..a0932e1
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<h1>This is a test page for node 70-HTML</h1>
+
+<p>There's nothing to read here.</p>
+
+<ol id="colours">
+    <li>Blue</li>
+    <li>Red</li>
+</ol>
+
+<ul id="fruits">
+    <li>Apple</li>
+    <li>Pear</li>
+</ul>
+
+<ul id="vegetables">
+    <li>Potato</li>
+    <li>Parsnip</li>
+</ul>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/dgbuilder/tools/FormatXml.java b/dgbuilder/tools/FormatXml.java
new file mode 100644 (file)
index 0000000..7c6915f
--- /dev/null
@@ -0,0 +1,49 @@
+import javax.xml.transform.*;
+import javax.xml.transform.stream.*;
+import java.io.*;
+import java.util.*;
+import java.nio.file.Paths;
+import java.nio.file.Files;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.Charset;
+public class FormatXml{
+public static String formatXml(String input, int indent) {
+    try {
+        Source xmlInput = new StreamSource(new StringReader(input));
+        StringWriter stringWriter = new StringWriter();
+        StreamResult xmlOutput = new StreamResult(stringWriter);
+        TransformerFactory transformerFactory = TransformerFactory.newInstance();
+        transformerFactory.setAttribute("indent-number", indent);
+        Transformer transformer = transformerFactory.newTransformer(); 
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        transformer.transform(xmlInput, xmlOutput);
+        return xmlOutput.getWriter().toString();
+    } catch (Exception e) {
+        throw new RuntimeException(e); // simple exception handling, please review it
+    }
+}
+
+public static String prettyFormat(String input) {
+    return formatXml(input, 2);
+}
+
+public static String readFile(String path, Charset encoding) 
+  throws IOException 
+{
+  byte[] encoded = Files.readAllBytes(Paths.get(path));
+  return new String(encoded, encoding);
+}
+
+public static void main(String[] args){
+try{
+       if (args != null && args.length != 1){
+               System.out.println("Usage:java FormatXml xmlStr");
+               System.exit(-1);
+       }
+       String xmlStr = readFile(args[0], StandardCharsets.UTF_8);
+       System.out.println(prettyFormat(xmlStr));
+}catch(Exception e){
+       e.printStackTrace();
+}
+}
+}
diff --git a/dgbuilder/tools/PrintYangToProp.java b/dgbuilder/tools/PrintYangToProp.java
new file mode 100644 (file)
index 0000000..93aaac7
--- /dev/null
@@ -0,0 +1,1424 @@
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.FileDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.io.*;
+import javax.json.*;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.CaseFormat;
+
+public class PrintYangToProp {
+
+       private static final Logger LOG = LoggerFactory.getLogger(PrintYangToProp.class);
+       public static final String PROPERTIES_FILE="/opt/bvc/controller/configuration/flowred.properties";
+       private static Properties properties;
+       
+       static {
+
+               // Trick class loader into loading builders. Some of
+               // these will be needed later by Reflection classes, but need
+               // to explicitly "new" them here to get class loader to load them.
+/*
+               ServiceInformationBuilder b2 = new ServiceInformationBuilder();
+               ServiceDataBuilder b3 = new ServiceDataBuilder();
+               SdncRequestHeaderBuilder b4 = new SdncRequestHeaderBuilder();
+               RequestInformationBuilder b6 = new RequestInformationBuilder();
+
+                FlowredGroupInformationDataBuilder b29 = new FlowredGroupInformationDataBuilder();
+                FlowredInformationDataBuilder b48 = new FlowredInformationDataBuilder();
+
+               OperStatusBuilder b41 = new OperStatusBuilder();
+*/
+
+
+       }
+
+       public static void loadProperties() {
+               /*
+
+               File file = new File(PROPERTIES_FILE); 
+               properties = new Properties();
+               InputStream input = null;
+               if (file.isFile() && file.canRead()) {
+                       try     {
+                               input = new FileInputStream(file);
+                               properties.load(input);
+                               LOG.info("Loaded properties from " + PROPERTIES_FILE );
+                       } catch (Exception e) {
+                               LOG.error("Failed to load properties " + PROPERTIES_FILE +"\n",e);
+                       } finally {
+                               if (input != null) {
+                                       try {
+                                               input.close();
+                                       } catch (IOException e) {
+                                               LOG.error("Failed to close properties file " + PROPERTIES_FILE +"\n",e);
+                                       }
+                               }
+                       }
+               }
+               */
+       }
+       
+       public static Properties toProperties(Properties props, Object fromObj) {
+               Class fromClass = null;
+               
+               if (fromObj != null)
+               {
+                       fromClass = fromObj.getClass();
+               }
+               return (toProperties(props, "", fromObj, fromClass));
+       }
+       
+       public static Properties toProperties(Properties props, String pfx, Object fromObj)
+       {
+               Class fromClass = null;
+               
+               if (fromObj != null)
+               {
+                       fromClass = fromObj.getClass();
+               }
+               
+               return(toProperties(props, pfx, fromObj, fromClass));
+       }
+
+       public static Properties toProperties(Properties props, String pfx,
+                       Object fromObj, Class fromClass) {
+
+               if (fromObj == null) {
+                       return (props);
+               }
+       
+               
+               String simpleName = fromClass.getSimpleName();
+
+               //LOG.debug("Extracting properties from " + fromClass.getName()
+               //              + " class");
+               if (fromObj instanceof List) {
+
+                       // Class is a List. List should contain yang-generated classes.
+                       //LOG.debug(fromClass.getName() + " is a List");
+
+                       List fromList = (List) fromObj;
+
+                       for (int i = 0; i < fromList.size(); i++) {
+                               toProperties(props, pfx + "[" + i + "]", fromList.get(i), fromClass);
+                       }
+                       props.setProperty(pfx + "_length", "" + fromList.size());
+
+               } else if (isYangGenerated(fromClass)) {
+                       // Class is yang generated.
+                       //LOG.debug(fromClass.getName() + " is a Yang-generated class");
+
+                       String propNamePfx = null;
+
+                       // If called from a list (so prefix ends in ']'), don't
+                       // add class name again
+                       if (pfx.endsWith("]")) {
+                               propNamePfx = pfx;
+                       } else {
+                               if ((pfx != null) && (pfx.length() > 0)) {
+                                       propNamePfx = pfx ;
+                               } else {
+                                       propNamePfx = toLowerHyphen(fromClass.getSimpleName());
+                               }
+
+                               if (propNamePfx.endsWith("-builder")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-builder".length());
+                               }
+
+                               if (propNamePfx.endsWith("-impl")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-impl".length());
+                               }
+                       }
+                       
+                       // Iterate through getter methods to figure out values we need to
+                       // save from
+
+                       for (Method m : fromClass.getMethods()) {
+                               // LOG.debug("Checking " + m.getName() + " method");
+                               if (isGetter(m)) {
+                                       // LOG.debug(m.getName() + " is a getter");
+                                       Class returnType = m.getReturnType();
+                                       String fieldName = toLowerHyphen(m.getName().substring(3));
+                                       if(m != null && m.getName().matches("^is[A-Z].*")){
+                                               fieldName = toLowerHyphen(m.getName().substring(2));
+                                       }
+
+                                       fieldName = fieldName.substring(0, 1).toLowerCase()
+                                                       + fieldName.substring(1);
+
+                                       // Is the return type a yang generated class?
+                                       if (isYangGenerated(returnType)) {
+                                               // Is it an enum?
+                                               if (returnType.isEnum()) {
+                                                       // Return type is a typedef. Save its value.
+                                                       try {
+                                                               boolean isAccessible = m.isAccessible();
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(true);
+                                                               }
+
+                                                               Object retValue = m.invoke(fromObj);
+
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(isAccessible);
+                                                               }
+                                                               if (retValue != null) {
+                                                                       String propName = propNamePfx + "."
+                                                                                       + fieldName;
+                                                                       String propVal = retValue.toString();
+                                                                       String yangProp = "yang." + fieldName + "." + propVal;
+                                                                       if ( properties.containsKey(yangProp)) {
+                                                                               propVal = properties.getProperty(yangProp);
+                                                                               //LOG.debug("Adjusting property " + yangProp + " " + propVal);
+                                                                       }
+                                                                       //LOG.debug("Setting property " + propName
+                                                                       //              + " to " + propVal);
+                                                                       props.setProperty(propName, propVal);
+                                                               }
+                                                       } catch (Exception e) {
+                                                               LOG.error(
+                                                                               "Caught exception trying to convert Yang-generated enum returned by "
+                                                                                               + fromClass.getName() + "."
+                                                                                               + m.getName()
+                                                                                               + "() to Properties entry", e);
+                                                       }
+                                               } else if (isIpv4Address(returnType)) {
+                                                       // Save its value
+                                                       try {
+                                                               String propName = propNamePfx + "." + fieldName;
+                                                               boolean isAccessible = m.isAccessible();
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(true);
+                                                               }
+                                                               Ipv4Address retValue = (Ipv4Address) m.invoke(fromObj);
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(isAccessible);
+                                                               }
+
+                                                               if (retValue != null) {
+                                                                       String propVal = retValue.getValue().toString();
+                                                                       //LOG.debug("Setting property " + propName
+                                                                       //              + " to " + propVal);
+                                                                       props.setProperty(propName, propVal);
+
+                                                               }
+                                                       } catch (Exception e) {
+                                                               LOG.error(
+                                                                               "Caught exception trying to convert value returned by "
+                                                                                               + fromClass.getName() + "."
+                                                                                               + m.getName()
+                                                                                               + "() to Properties entry", e);
+                                                       }
+                                               } else if (isIpv6Address(returnType)) {
+                                                       // Save its value
+                                                       try {
+                                                               String propName = propNamePfx + "." + fieldName;
+                                                               boolean isAccessible = m.isAccessible();
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(true);
+                                                               }
+                                                               Ipv6Address retValue = (Ipv6Address) m.invoke(fromObj);
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(isAccessible);
+                                                               }
+
+                                                               if (retValue != null) {
+                                                                       String propVal = retValue.getValue().toString();
+                                                                       //LOG.debug("Setting property " + propName
+                                                                       //              + " to " + propVal);
+                                                                       props.setProperty(propName, propVal);
+
+                                                               }
+                                                       } catch (Exception e) {
+                                                               LOG.error(
+                                                                               "Caught exception trying to convert value returned by "
+                                                                                               + fromClass.getName() + "."
+                                                                                               + m.getName()
+                                                                                               + "() to Properties entry", e);
+                                                       }
+                                               } else {
+                                                       try {
+                                                               boolean isAccessible = m.isAccessible();
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(true);
+                                                               }
+                                                               Object retValue = m.invoke(fromObj);
+                                                               if (!isAccessible) {
+                                                                       m.setAccessible(isAccessible);
+                                                               }
+                                                               if (retValue != null) {
+                                                                       toProperties(props, propNamePfx + "." + fieldName, retValue, returnType);
+                                                               }
+                                                       } catch (Exception e) {
+                                                               LOG.error(
+                                                                               "Caught exception trying to convert Yang-generated class returned by"
+                                                                                               + fromClass.getName() + "."
+                                                                                               + m.getName()
+                                                                                               + "() to Properties entry", e);
+                                                       }
+                                               }
+                                       } else if (returnType.equals(Class.class)) {
+
+                                               //LOG.debug(m.getName()
+                                               //              + " returns a Class object - not interested");
+
+                                       } else if (List.class.isAssignableFrom(returnType)) {
+
+                                               // This getter method returns a list.
+                                               try {
+                                                       boolean isAccessible = m.isAccessible();
+                                                       if (!isAccessible) {
+                                                               m.setAccessible(true);
+                                                       }
+                                                       Object retList = m.invoke(fromObj);
+                                                       if (!isAccessible) {
+                                                               m.setAccessible(isAccessible);
+                                                       }
+                                                       // Figure out what type of elements are stored in this array.
+                                                       Type paramType = m.getGenericReturnType();
+                                                       Type elementType = ((ParameterizedType) paramType)
+                                                                       .getActualTypeArguments()[0];
+                                                       toProperties(props, propNamePfx + "." + fieldName,
+                                                                       retList, (Class)elementType);
+                                               } catch (Exception e) {
+                                                       LOG.error(
+                                                                       "Caught exception trying to convert List returned by "
+                                                                                       + fromClass.getName() + "."
+                                                                                       + m.getName()
+                                                                                       + "() to Properties entry", e);
+                                               }
+
+                                       } else {
+
+                                               // Method returns something that is not a List and not
+                                               // yang-generated.
+                                               // Save its value
+                                               try {
+                                                       String propName = propNamePfx + "." + fieldName;
+                                                       boolean isAccessible = m.isAccessible();
+                                                       if (!isAccessible) {
+                                                               m.setAccessible(true);
+                                                       }
+                                                       Object propValObj = m.invoke(fromObj);
+                                                       if (!isAccessible) {
+                                                               m.setAccessible(isAccessible);
+                                                       }
+
+                                                       if (propValObj != null) {
+                                                               String propVal = propValObj.toString();
+                                                               //LOG.debug("Setting property " + propName
+                                                               //              + " to " + propVal);
+                                                               props.setProperty(propName, propVal);
+
+                                                       }
+                                               } catch (Exception e) {
+                                                       LOG.error(
+                                                                       "Caught exception trying to convert value returned by "
+                                                                                       + fromClass.getName() + "."
+                                                                                       + m.getName()
+                                                                                       + "() to Properties entry", e);
+                                               }
+                                       }
+
+                               }
+                       }
+
+               } else {
+                       // Class is not yang generated and not a list
+                       // Do nothing.
+
+               }
+
+               return (props);
+       }
+
+       public static Object toBuilder(Properties props, Object toObj) {
+
+               return (toBuilder(props, "", toObj));
+       }
+
+       public static List toList(Properties props, String pfx, List toObj,
+                       Class elemType) {
+
+               int maxIdx = -1;
+               boolean foundValue = false;
+
+               //LOG.debug("Saving properties to List<" + elemType.getName()
+               //              + ">  from " + pfx);
+
+               // Figure out array size
+               for (Object pNameObj : props.keySet()) {
+                       String key = (String) pNameObj;
+
+                       if (key.startsWith(pfx + "[")) {
+                               String idxStr = key.substring(pfx.length() + 1);
+                               int endloc = idxStr.indexOf("]");
+                               if (endloc != -1) {
+                                       idxStr = idxStr.substring(0, endloc);
+                               }
+
+                               try {
+                                       int curIdx = Integer.parseInt(idxStr);
+                                       if (curIdx > maxIdx) {
+                                               maxIdx = curIdx;
+                                       }
+                               } catch (Exception e) {
+                                       LOG.error("Illegal subscript in property " + key);
+                               }
+
+                       }
+               }
+
+               //LOG.debug(pfx + " has max index of " + maxIdx);
+               for (int i = 0; i <= maxIdx; i++) {
+
+                       String curBase = pfx + "[" + i + "]";
+
+                       if (isYangGenerated(elemType)) {
+                               String builderName = elemType.getName() + "Builder";
+                               try {
+                                       Class builderClass = Class.forName(builderName);
+                                       Object builderObj = builderClass.newInstance();
+                                       Method buildMethod = builderClass.getMethod("build");
+                                       builderObj = toBuilder(props, curBase, builderObj, true);
+                                       if (builderObj != null) {
+                                               //LOG.debug("Calling " + builderObj.getClass().getName()
+                                               //              + "." + buildMethod.getName() + "()");
+                                               Object builtObj = buildMethod.invoke(builderObj);
+                                               toObj.add(builtObj);
+                                               foundValue = true;
+                                       }
+
+                               } catch (ClassNotFoundException e) {
+                                       LOG.warn("Could not find builder class " + builderName, e);
+                               } catch (Exception e) {
+                                       LOG.error("Caught exception trying to populate list from "
+                                                       + pfx);
+                               }
+                       }
+
+               }
+
+               if (foundValue) {
+                       return (toObj);
+               } else {
+                       return (null);
+               }
+
+       }
+       
+       public static Object toBuilder(Properties props, String pfx, Object toObj) {
+               return(toBuilder(props, pfx, toObj, false));
+       }
+
+       public static Object toBuilder(Properties props, String pfx, Object toObj, boolean preservePfx) {
+               Class toClass = toObj.getClass();
+               boolean foundValue = false;
+
+               //LOG.debug("Saving properties to " + toClass.getName() + " class from "
+               //              + pfx);
+
+               Ipv4Address addr;
+
+               if (isYangGenerated(toClass)) {
+                       // Class is yang generated.
+                       //LOG.debug(toClass.getName() + " is a Yang-generated class");
+
+                       String propNamePfx = null;
+                       if (preservePfx) {
+                               propNamePfx = pfx;
+                       } else {
+
+                               if ((pfx != null) && (pfx.length() > 0)) {
+                                       propNamePfx = pfx + "."
+                                                       + toLowerHyphen(toClass.getSimpleName());
+                               } else {
+                                       propNamePfx = toLowerHyphen(toClass.getSimpleName());
+                               }
+
+                               if (propNamePfx.endsWith("-builder")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-builder".length());
+                               }
+
+                               if (propNamePfx.endsWith("-impl")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-impl".length());
+                               }
+                       }
+
+                       if (toObj instanceof Identifier) {
+                               //LOG.debug(toClass.getName() + " is a Key - skipping");
+                               return (toObj);
+                       }
+
+                       // Iterate through getter methods to figure out values we need to
+                       // set
+
+                       for (Method m : toClass.getMethods()) {
+                               // LOG.debug("Is " + m.getName() + " method a setter?");
+                               if (isSetter(m)) {
+                                       // LOG.debug(m.getName() + " is a setter");
+                                       Class paramTypes[] = m.getParameterTypes();
+                                       Class paramClass = paramTypes[0];
+
+                                       String fieldName = toLowerHyphen(m.getName().substring(3));
+                                       fieldName = fieldName.substring(0, 1).toLowerCase()
+                                                       + fieldName.substring(1);
+
+                                       String propName = propNamePfx + "." + fieldName;
+
+                                       String paramValue = props.getProperty(propName);
+                                       if (paramValue == null) {
+                                               //LOG.debug(propName + " is unset");
+                                       } else {
+                                               //LOG.debug(propName + " = " + paramValue);
+                                       }
+
+                                       // Is the return type a yang generated class?
+                                       if (isYangGenerated(paramClass)) {
+                                               // Is it an enum?
+                                               if (paramClass.isEnum()) {
+
+                                                       //LOG.debug(m.getName() + " expects an Enum");
+                                                       // Param type is a typedef.
+                                                       if (paramValue != null) {
+                                                               Object paramObj = null;
+
+                                                               try {
+                                                                       paramObj = Enum.valueOf(paramClass,
+                                                                                       toUpperCamelCase(paramValue));
+                                                               } catch (Exception e) {
+                                                                       LOG.error(
+                                                                                       "Caught exception trying to convert field "
+                                                                                                       + propName + " to enum "
+                                                                                                       + paramClass.getName(), e);
+                                                               }
+
+                                                               try {
+                                                                       boolean isAccessible = m.isAccessible();
+                                                                       if (!isAccessible) {
+                                                                               m.setAccessible(true);
+                                                                       }
+
+                                                                       //LOG.debug("Calling "
+                                                                       //              + toObj.getClass().getName() + "."
+                                                                       //              + m.getName() + "(" + paramValue
+                                                                       //              + ")");
+                                                                       m.invoke(toObj, paramObj);
+
+                                                                       if (!isAccessible) {
+                                                                               m.setAccessible(isAccessible);
+                                                                       }
+                                                                       foundValue = true;
+
+                                                               } catch (Exception e) {
+                                                                       LOG.error(
+                                                                                       "Caught exception trying to create Yang-generated enum expected by"
+                                                                                                       + toClass.getName()
+                                                                                                       + "."
+                                                                                                       + m.getName()
+                                                                                                       + "() from Properties entry",
+                                                                                       e);
+                                                               }
+                                                       }
+                                               } else {
+
+                                                       String simpleName = paramClass.getSimpleName();
+
+                                                       if ("Ipv4Address".equals(simpleName)
+                                                                       || "Ipv6Address".equals(simpleName)) {
+                                                               
+                                                               if (paramValue != null) {
+                                                                       try {
+                                                                               IpAddress ipAddr = IpAddressBuilder
+                                                                                               .getDefaultInstance(paramValue);
+
+
+                                                                               if ("Ipv4Address".equals(simpleName))
+                                                                               {
+                                                                                       m.invoke(toObj, ipAddr.getIpv4Address());
+                                                                               }
+                                                                               else
+                                                                               {
+                                                                                       m.invoke(toObj, ipAddr.getIpv6Address());
+
+                                                                               }
+                                                                               foundValue = true;
+                                                                       } catch (Exception e) {
+                                                                               LOG.error(
+                                                                                               "Caught exception calling "
+                                                                                                               + toClass.getName() + "."
+                                                                                                               + m.getName() + "("
+                                                                                                               + paramValue + ")", e);
+
+                                                                       }
+                                                               }
+
+                                                       } else {
+                                                               // setter expects a yang-generated class. Need
+                                                               // to
+                                                               // create a builder to set it.
+
+                                                               String builderName = paramClass.getName()
+                                                                               + "Builder";
+                                                               Class builderClass = null;
+                                                               Object builderObj = null;
+                                                               Object paramObj = null;
+
+                                                               //LOG.debug(m.getName()
+                                                               //              + " expects a yang-generated class - looking for builder "
+                                                               //              + builderName);
+                                                               try {
+                                                                       builderClass = Class.forName(builderName);
+                                                                       builderObj = builderClass.newInstance();
+                                                                       paramObj = toBuilder(props, propNamePfx,
+                                                                                       builderObj);
+                                                               } catch (ClassNotFoundException e) {
+                                                                       Object constObj = null;
+                                                                       try {
+                                                                               // See if I can find a constructor I can
+                                                                               // use
+                                                                               Constructor[] constructors = paramClass
+                                                                                               .getConstructors();
+                                                                               // Is there a String constructor?
+                                                                               for (Constructor c : constructors) {
+                                                                                       Class[] cParms = c
+                                                                                                       .getParameterTypes();
+                                                                                       if ((cParms != null)
+                                                                                                       && (cParms.length == 1)) {
+                                                                                               if (String.class
+                                                                                                               .isAssignableFrom(cParms[0])) {
+                                                                                                       constObj = c
+                                                                                                                       .newInstance(paramValue);
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               if (constObj == null) {
+                                                                                       // Is there a Long constructor?
+                                                                                       for (Constructor c : constructors) {
+                                                                                               Class[] cParms = c
+                                                                                                               .getParameterTypes();
+                                                                                               if ((cParms != null)
+                                                                                                               && (cParms.length == 1)) {
+                                                                                                       if (Long.class
+                                                                                                                       .isAssignableFrom(cParms[0])) {
+                                                                                                               constObj = c
+                                                                                                                               .newInstance(Long
+                                                                                                                                               .parseLong(paramValue));
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+
+                                                                               }
+
+                                                                               if (constObj != null) {
+                                                                                       try {
+                                                                                               m.invoke(toObj, constObj);
+                                                                                               foundValue = true;
+                                                                                       } catch (Exception e2) {
+                                                                                               LOG.error(
+                                                                                                               "Caught exception trying to call "
+                                                                                                                               + m.getName(),
+                                                                                                               e2);
+                                                                                       }
+                                                                               }
+                                                                       } catch (Exception e1) {
+                                                                               LOG.warn(
+                                                                                               "Could not find a suitable constructor for "
+                                                                                                               + paramClass.getName(),
+                                                                                               e1);
+                                                                       }
+
+                                                                       if (paramObj == null) {
+                                                                               LOG.warn("Could not find builder class "
+                                                                                               + builderName
+                                                                                               + " and could not find a String or Long constructor - trying just to set passing paramValue");
+
+                                                                       }
+
+                                                               } catch (Exception e) {
+                                                                       LOG.error(
+                                                                                       "Caught exception trying to create builder "
+                                                                                                       + builderName, e);
+                                                               }
+
+                                                               if (paramObj != null) {
+
+                                                                       try {
+
+                                                                               Method buildMethod = builderClass
+                                                                                               .getMethod("build");
+                                                                               //LOG.debug("Calling "
+                                                                               //              + paramObj.getClass().getName()
+                                                                               //              + "." + buildMethod.getName()
+                                                                               //              + "()");
+                                                                               Object builtObj = buildMethod
+                                                                                               .invoke(paramObj);
+
+                                                                               boolean isAccessible = m.isAccessible();
+                                                                               if (!isAccessible) {
+                                                                                       m.setAccessible(true);
+                                                                               }
+
+                                                                               //LOG.debug("Calling "
+                                                                               //              + toObj.getClass().getName()
+                                                                               //              + "." + m.getName() + "()");
+                                                                               m.invoke(toObj, builtObj);
+                                                                               if (!isAccessible) {
+                                                                                       m.setAccessible(isAccessible);
+                                                                               }
+                                                                               foundValue = true;
+
+                                                                       } catch (Exception e) {
+                                                                               LOG.error(
+                                                                                               "Caught exception trying to set Yang-generated class expected by"
+                                                                                                               + toClass.getName()
+                                                                                                               + "."
+                                                                                                               + m.getName()
+                                                                                                               + "() from Properties entry",
+                                                                                               e);
+                                                                       }
+                                                               } else {
+                                                                       try {
+                                                                               boolean isAccessible = m.isAccessible();
+                                                                               if (!isAccessible) {
+                                                                                       m.setAccessible(true);
+                                                                               }
+                                                                               //LOG.debug("Calling "
+                                                                               //              + toObj.getClass().getName()
+                                                                               //              + "." + m.getName() + "("
+                                                                               //              + paramValue + ")");
+                                                                               m.invoke(toObj, paramValue);
+                                                                               if (!isAccessible) {
+                                                                                       m.setAccessible(isAccessible);
+                                                                               }
+                                                                               foundValue = true;
+
+                                                                       } catch (Exception e) {
+                                                                               LOG.error(
+                                                                                               "Caught exception trying to convert value returned by"
+                                                                                                               + toClass.getName()
+                                                                                                               + "."
+                                                                                                               + m.getName()
+                                                                                                               + "() to Properties entry",
+                                                                                               e);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       } else {
+
+                                               // Setter's argument is not a yang-generated class. See
+                                               // if it is a List.
+
+                                               if (List.class.isAssignableFrom(paramClass)) {
+
+                                                       //LOG.debug("Parameter class " + paramClass.getName()
+                                                       //              + " is a List");
+
+                                                       // Figure out what type of args are in List and pass
+                                                       // that to toList().
+
+                                                       Type paramType = m.getGenericParameterTypes()[0];
+                                                       Type elementType = ((ParameterizedType) paramType)
+                                                                       .getActualTypeArguments()[0];
+                                                       Object paramObj = new LinkedList();
+                                                       try {
+                                                               paramObj = toList(props, propName,
+                                                                               (List) paramObj, (Class) elementType);
+                                                       } catch (Exception e) {
+                                                               LOG.error("Caught exception trying to create list expected as argument to "
+                                                                               + toClass.getName() + "." + m.getName());
+                                                       }
+
+                                                       if (paramObj != null) {
+                                                               try {
+                                                                       boolean isAccessible = m.isAccessible();
+                                                                       if (!isAccessible) {
+                                                                               m.setAccessible(true);
+                                                                       }
+                                                                       //LOG.debug("Calling "
+                                                                       //              + toObj.getClass().getName() + "."
+                                                                       //              + m.getName() + "(" + paramValue
+                                                                       //              + ")");
+                                                                       m.invoke(toObj, paramObj);
+                                                                       if (!isAccessible) {
+                                                                               m.setAccessible(isAccessible);
+                                                                       }
+                                                                       foundValue = true;
+
+                                                               } catch (Exception e) {
+                                                                       LOG.error(
+                                                                                       "Caught exception trying to convert List returned by"
+                                                                                                       + toClass.getName() + "."
+                                                                                                       + m.getName()
+                                                                                                       + "() to Properties entry",
+                                                                                       e);
+                                                               }
+                                                       }
+                                               } else {
+
+                                                       // Setter expects something that is not a List and
+                                                       // not yang-generated. Just pass the parameter value
+
+                                                       //LOG.debug("Parameter class "
+                                                       //              + paramClass.getName()
+                                                       //              + " is not a yang-generated class or a List");
+
+                                                       if (paramValue != null) {
+
+                                                               Object constObj = null;
+
+                                                               try {
+                                                                       // See if I can find a constructor I can use
+                                                                       Constructor[] constructors = paramClass
+                                                                                       .getConstructors();
+                                                                       // Is there a String constructor?
+                                                                       for (Constructor c : constructors) {
+                                                                               Class[] cParms = c.getParameterTypes();
+                                                                               if ((cParms != null)
+                                                                                               && (cParms.length == 1)) {
+                                                                                       if (String.class
+                                                                                                       .isAssignableFrom(cParms[0])) {
+                                                                                               constObj = c
+                                                                                                               .newInstance(paramValue);
+                                                                                       }
+                                                                               }
+                                                                       }
+
+                                                                       if (constObj == null) {
+                                                                               // Is there a Long constructor?
+                                                                               for (Constructor c : constructors) {
+                                                                                       Class[] cParms = c
+                                                                                                       .getParameterTypes();
+                                                                                       if ((cParms != null)
+                                                                                                       && (cParms.length == 1)) {
+                                                                                               if (Long.class
+                                                                                                               .isAssignableFrom(cParms[0])) {
+                                                                                                       constObj = c
+                                                                                                                       .newInstance(Long
+                                                                                                                                       .parseLong(paramValue));
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                       }
+
+                                                                       if (constObj != null) {
+                                                                               try {
+                                                                                       //LOG.debug("Calling "
+                                                                                       //              + toObj.getClass()
+                                                                                       //                              .getName() + "."
+                                                                                       //              + m.getName() + "("
+                                                                                       //              + constObj + ")");
+                                                                                       m.invoke(toObj, constObj);
+                                                                                       foundValue = true;
+                                                                               } catch (Exception e2) {
+                                                                                       LOG.error(
+                                                                                                       "Caught exception trying to call "
+                                                                                                                       + m.getName(), e2);
+                                                                               }
+                                                                       } else {
+                                                                               try {
+                                                                                       boolean isAccessible = m
+                                                                                                       .isAccessible();
+                                                                                       if (!isAccessible) {
+                                                                                               m.setAccessible(true);
+                                                                                       }
+                                                                                       //LOG.debug("Calling "
+                                                                                       //              + toObj.getClass()
+                                                                                       //                              .getName() + "."
+                                                                                       //              + m.getName() + "("
+                                                                                       //              + paramValue + ")");
+                                                                                       m.invoke(toObj, paramValue);
+                                                                                       if (!isAccessible) {
+                                                                                               m.setAccessible(isAccessible);
+                                                                                       }
+                                                                                       foundValue = true;
+
+                                                                               } catch (Exception e) {
+                                                                                       LOG.error(
+                                                                                                       "Caught exception trying to convert value returned by"
+                                                                                                                       + toClass.getName()
+                                                                                                                       + "."
+                                                                                                                       + m.getName()
+                                                                                                                       + "() to Properties entry",
+                                                                                                       e);
+                                                                               }
+                                                                       }
+                                                               } catch (Exception e1) {
+                                                                       LOG.warn(
+                                                                                       "Could not find a suitable constructor for "
+                                                                                                       + paramClass.getName(), e1);
+                                                               }
+
+                                                               /*
+                                                                * try { boolean isAccessible =
+                                                                * m.isAccessible(); if (!isAccessible) {
+                                                                * m.setAccessible(true); } LOG.debug("Calling "
+                                                                * + toObj.getClass().getName() + "." +
+                                                                * m.getName() + "(" + paramValue + ")");
+                                                                * m.invoke(toObj, paramValue); if
+                                                                * (!isAccessible) {
+                                                                * m.setAccessible(isAccessible); } foundValue =
+                                                                * true;
+                                                                * 
+                                                                * } catch (Exception e) { LOG.error(
+                                                                * "Caught exception trying to convert value returned by"
+                                                                * + toClass.getName() + "." + m.getName() +
+                                                                * "() to Properties entry", e); }
+                                                                */
+                                                       }
+                                               }
+                                       }
+                               } // End of section handling "setter" method
+                       } // End of loop through Methods
+               } // End of section handling yang-generated class
+
+               if (foundValue) {
+                       return (toObj);
+               } else {
+                       return (null);
+               }
+       }
+
+/*
+       public static void printPropertyList(PrintStream pstr, String pfx,
+                       Class toClass) {
+               boolean foundValue = false;
+
+               //LOG.debug("Analyzing " + toClass.getName() + " class : pfx " + pfx);
+
+               if (isYangGenerated(toClass)
+                               && (!Identifier.class.isAssignableFrom(toClass))) {
+                       // Class is yang generated.
+                       //LOG.debug(toClass.getName() + " is a Yang-generated class");
+
+                       if (toClass.getName().endsWith("Key")) {
+                               if (Identifier.class.isAssignableFrom(toClass)) {
+                                       //LOG.debug(Identifier.class.getName()
+                                       //              + " is assignable from " + toClass.getName());
+                               } else {
+
+                                       //LOG.debug(Identifier.class.getName()
+                                       //              + " is NOT assignable from " + toClass.getName());
+                               }
+                       }
+
+                       String propNamePfx = null;
+                       if (pfx.endsWith("]")) {
+                               propNamePfx = pfx;
+                       } else {
+
+                               if ((pfx != null) && (pfx.length() > 0)) {
+                                       propNamePfx = pfx + "."
+                                                       + toLowerHyphen(toClass.getSimpleName());
+                               } else {
+                                       propNamePfx = toLowerHyphen(toClass.getSimpleName());
+                               }
+
+                               if (propNamePfx.endsWith("-builder")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-builder".length());
+                               }
+
+                               if (propNamePfx.endsWith("-impl")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-impl".length());
+                               }
+                       }
+
+                       // Iterate through getter methods to figure out values we need to
+                       // set
+
+                       for (Method m : toClass.getMethods()) {
+                               //LOG.debug("Is " + m.getName() + " method a getter?");
+                               if (isGetter(m)) {
+                                       //LOG.debug(m.getName() + " is a getter");
+                                       Class returnClass = m.getReturnType();
+
+                                       String fieldName = toLowerHyphen(m.getName().substring(3));
+                                       fieldName = fieldName.substring(0, 1).toLowerCase()
+                                                       + fieldName.substring(1);
+
+                                       String propName = propNamePfx + "." + fieldName;
+
+                                       // Is the return type a yang generated class?
+                                       if (isYangGenerated(returnClass)) {
+                                               // Is it an enum?
+                                               if (returnClass.isEnum()) {
+                                                       //System.out.println(returnClass.getSimpleName());
+                                                       //System.out.println(Arrays.asList(returnClass.getEnumConstants()));
+
+                                                       //LOG.debug(m.getName() + " is an Enum");
+                                                       pstr.print("\n" + propName + ":Enum:" + Arrays.asList(returnClass.getEnumConstants()) + "\n");
+
+                                               } else {
+                                                       
+                                                       String simpleName = returnClass.getSimpleName();
+                                                       
+                                                       if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName)) {
+                                                               //LOG.debug(m.getName()+" is an "+simpleName);
+                                                               pstr.print("\n" + propName + ":" + simpleName + "\n");
+                                                       } else {
+                                                               printPropertyList(pstr, propNamePfx, returnClass);
+                                                       }
+
+                                               }
+                                       } else {
+
+                                               // Setter's argument is not a yang-generated class. See
+                                               // if it is a List.
+
+                                               if (List.class.isAssignableFrom(returnClass)) {
+
+                                                       //LOG.debug("Parameter class "
+                                                                       //+ returnClass.getName() + " is a List");
+
+                                                       // Figure out what type of args are in List and pass
+                                                       // that to toList().
+
+                                                       Type returnType = m.getGenericReturnType();
+                                                       Type elementType = ((ParameterizedType) returnType)
+                                                                       .getActualTypeArguments()[0];
+                                                       Class elementClass = (Class) elementType;
+                                                       //LOG.debug("Calling printPropertyList on list type ("
+                                                                       //+ elementClass.getName()
+                                                                       //+ "), pfx is ("
+                                                               //      + pfx
+                                                               //      + "), toClass is ("
+                                                               //      + toClass.getName() + ")");
+                                                       printPropertyList(
+                                                                       pstr,
+                                                                       propNamePfx
+                                                                                       + "."
+                                                                                       + toLowerHyphen(elementClass
+                                                                                                       .getSimpleName()) + "[]",
+                                                                       elementClass);
+
+                                               } else if (!returnClass.equals(Class.class)) {
+
+                                                       // Setter expects something that is not a List and
+                                                       // not yang-generated. Just pass the parameter value
+
+                                                       //LOG.debug("Parameter class "
+                                                       //              + returnClass.getName()
+                                                       //              + " is not a yang-generated class or a List");
+                                                       String className=returnClass.getName();
+                                                       
+                                                       //"org.opendaylight.yangtools.yang.binding.Identifier" 
+                                                       int nClassNameIndex = className.lastIndexOf('.');
+                                                       String nClassName = className;
+                                                       if(nClassNameIndex != -1){
+                                                               nClassName=className.substring(nClassNameIndex+1);
+                                                       }
+                                                       pstr.print("\n" + propName +":" + nClassName +"\n");
+
+                                               }
+                                       }
+                               } // End of section handling "setter" method
+                       } // End of loop through Methods
+               } // End of section handling yang-generated class
+
+       }
+*/
+
+       public static Properties prop = new Properties();
+       public static ArrayList<String> propList = new ArrayList<String>();
+       public static Properties getProperties(PrintStream pstr, String pfx,
+                       Class toClass) {
+               boolean foundValue = false;
+
+               //LOG.debug("Analyzing " + toClass.getName() + " class : pfx " + pfx);
+
+               if (isYangGenerated(toClass)
+                               && (!Identifier.class.isAssignableFrom(toClass))) {
+                       // Class is yang generated.
+                       //LOG.debug(toClass.getName() + " is a Yang-generated class");
+
+                       if (toClass.getName().endsWith("Key")) {
+                               if (Identifier.class.isAssignableFrom(toClass)) {
+                                       //LOG.debug(Identifier.class.getName()
+                                       //              + " is assignable from " + toClass.getName());
+                               } else {
+
+                                       //LOG.debug(Identifier.class.getName()
+                                       //              + " is NOT assignable from " + toClass.getName());
+                               }
+                       }
+
+                       String propNamePfx = null;
+                       if (pfx.endsWith("]")) {
+                               propNamePfx = pfx;
+                       }else if(pfx.indexOf(".CLASS_FOUND") != -1){
+                               pfx = pfx.replace(".CLASS_FOUND","");   
+                               propNamePfx = pfx + "."
+                                       + toLowerHyphen(toClass.getSimpleName());
+                       } else {
+
+                               if ((pfx != null) && (pfx.length() > 0)) {
+                                       propNamePfx = pfx + "."
+                                                       + toLowerHyphen(toClass.getSimpleName());
+                               } else {
+                                       propNamePfx = toLowerHyphen(toClass.getSimpleName());
+                               }
+
+                               if (propNamePfx.endsWith("-builder")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-builder".length());
+                               }
+
+                               if (propNamePfx.endsWith("-impl")) {
+                                       propNamePfx = propNamePfx.substring(0, propNamePfx.length()
+                                                       - "-impl".length());
+                               }
+                       }
+
+                       // Iterate through getter methods to figure out values we need to
+                       // set
+
+                       for (Method m : toClass.getMethods()) {
+                               //LOG.debug("Is " + m.getName() + " method a getter?");
+                               if (isGetter(m)) {
+                               //      LOG.debug(m.getName() + " is a getter");
+                                       Class returnClass = m.getReturnType();
+
+                                       String fieldName = toLowerHyphen(m.getName().substring(3));
+                                       if(m != null && m.getName().matches("^is[A-Z].*")){
+                                               fieldName = toLowerHyphen(m.getName().substring(2));
+                                       }
+                                       fieldName = fieldName.substring(0, 1).toLowerCase()
+                                                       + fieldName.substring(1);
+
+                                       String propName = propNamePfx + "." + fieldName;
+                                       //System.out.println("****" + propName);
+
+                                       // Is the return type a yang generated class?
+                                       if (isYangGenerated(returnClass)) {
+                                               // Is it an enum?
+                                               if (returnClass.isEnum()) {
+
+                                                       //LOG.debug(m.getName() + " is an Enum");
+                                                       //pstr.print("\n" + propName);
+                                                       //pstr.print("\n" + propName + ":Enum:" + Arrays.asList(returnClass.getEnumConstants()) + "\n");
+                                                       pstr.print("\"" + propName + ":Enum:" + Arrays.asList(returnClass.getEnumConstants()) + "\",");
+                                                       prop.setProperty(propName,"");
+                                                       propList.add(propName);
+
+                                               } else {
+                                                       
+                                                       String simpleName = returnClass.getSimpleName();
+                                                       //System.out.println("simpleName:" + simpleName);
+                                                       
+                                                       if ("Ipv4Address".equals(simpleName) || "Ipv6Address".equals(simpleName) || "IpAddress".equals(simpleName)) {
+                                                               //LOG.debug(m.getName()+" is an "+simpleName);
+                                                               //pstr.print("\n" + propName);
+                                                               //pstr.print("\n" + propName + ":" + simpleName + "\n");
+                                                               pstr.print("\"" + propName + ":" + simpleName + "\",");
+                                                               prop.setProperty(propName,"");
+                                                               propList.add(propName);
+                                                       } else {
+                                                               boolean isString = false;
+                                                               boolean isNumber = false;
+                                                               boolean isBoolean = false;
+                                                               boolean isIdentifier = false;
+                                                               //System.out.println("simpleName:" + simpleName);
+                                                               //System.out.println("propName:" + propName);
+                                                               for(Method mthd : returnClass.getMethods()){
+                                                                       String methodName = mthd.getName();
+                                                                       //System.out.println("methodName:" + methodName);
+                                                                       if(methodName.equals("getValue")){
+                                                                               Class retType = mthd.getReturnType();
+                                                                               //System.out.println("retType:" + retType);
+                                                                               isString = String.class.isAssignableFrom(retType);
+                                                                               isNumber = Number.class.isAssignableFrom(retType);
+                                                                               isBoolean = Boolean.class.isAssignableFrom(retType);
+                                                                               isIdentifier = Identifier.class.isAssignableFrom(retType);
+                                                                               //System.out.println("isString:" + isString);
+                                                                               //System.out.println("isNumber:" + isNumber);
+                                                                               //System.out.println("isNumber:" + isNumber);
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if(isString){
+                                                                       pstr.print("\"" + propName + ":String\",");
+                                                                       prop.setProperty(propName,"");
+                                                                       propList.add(propName);
+                                                               }else if(isNumber){
+                                                                       pstr.print("\"" + propName + ":Number\",");
+                                                                       prop.setProperty(propName,"");
+                                                                       propList.add(propName);
+                                                               }else if(isBoolean){
+                                                                       pstr.print("\"" + propName + ":Boolean\",");
+                                                                       prop.setProperty(propName,"");
+                                                                       propList.add(propName);
+                                                               }else if(isIdentifier){
+                                                                       //System.out.println("isIdentifier");
+                                                                       //isIdentifer so skipping 
+                                                                       continue;
+                                                               }else{
+                                                               /*
+                                                               System.out.println("fieldName:" + fieldName);
+                                                               System.out.println("simpleName:" + simpleName);
+                                                               System.out.println("returnClass:" + returnClass);
+                                                               System.out.println("pstr:" + pstr);
+                                                               System.out.println("propNamePfx:" + propNamePfx);
+                                                               */
+                                                               getProperties(pstr, propNamePfx + ".CLASS_FOUND", returnClass);
+                                                               }
+                                                       }
+
+                                               }
+                                       } else {
+
+                                               // Setter's argument is not a yang-generated class. See
+                                               // if it is a List.
+
+                                               if (List.class.isAssignableFrom(returnClass)) {
+
+                                                       //LOG.debug("Parameter class "
+                                                       //              + returnClass.getName() + " is a List");
+
+                                                       // Figure out what type of args are in List and pass
+                                                       // that to toList().
+
+                                                       Type returnType = m.getGenericReturnType();
+                                                       Type elementType = ((ParameterizedType) returnType)
+                                                                       .getActualTypeArguments()[0];
+                                                       Class elementClass = (Class) elementType;
+                                                       //LOG.debug("Calling printPropertyList on list type ("
+                                                                       //+ elementClass.getName()
+                                                               //      + "), pfx is ("
+                                                               //      + pfx
+                                                               //      + "), toClass is ("
+                                                               //      + toClass.getName() + ")");
+                                                       //System.out.println("List propNamePfx:" + propNamePfx+ "." + toLowerHyphen(elementClass.getSimpleName()) + "[]");
+                                                       if(String.class.isAssignableFrom(elementClass)){
+                                                               pstr.print("\"" + propName + ":[String,String,...]\",");
+                                                               prop.setProperty(propName,"");
+                                                               propList.add(propName);
+                                                       }else if(Number.class.isAssignableFrom(elementClass)){
+                                                               pstr.print("\"" + propName + ":[Number,Number,...]\",");
+                                                               prop.setProperty(propName,"");
+                                                               propList.add(propName);
+                                                       }else if(Boolean.class.isAssignableFrom(elementClass)){
+                                                               pstr.print("\"" + propName + ":[Boolean,Boolean,...]\",");
+                                                               prop.setProperty(propName,"");
+                                                               propList.add(propName);
+                                                       }else if(Identifier.class.isAssignableFrom(elementClass)){
+                                                               continue;
+                                                       }else{
+                                                               getProperties(
+                                                                       pstr,
+                                                                       propNamePfx
+                                                                                       + "."
+                                                                                       + toLowerHyphen(elementClass
+                                                                                                       .getSimpleName()) + "[]",
+                                                                       elementClass);
+                                                       }
+
+                                               } else if (!returnClass.equals(Class.class)) {
+
+                                                       // Setter expects something that is not a List and
+                                                       // not yang-generated. Just pass the parameter value
+
+                                                       //LOG.debug("Parameter class "
+                                                       //              + returnClass.getName()
+                                                       //              + " is not a yang-generated class or a List");
+
+                                                       //pstr.print("\n" + propName);
+                                                       String className=returnClass.getName();
+                                                       int nClassNameIndex = className.lastIndexOf('.');
+                                                       String nClassName = className;
+                                                       if(nClassNameIndex != -1){
+                                                               nClassName=className.substring(nClassNameIndex+1);
+                                                       }
+                                                       boolean isString = String.class.isAssignableFrom(returnClass);
+                                                       boolean isNumber = Number.class.isAssignableFrom(returnClass);
+                                                       boolean isBoolean = Boolean.class.isAssignableFrom(returnClass);
+                                                       //pstr.print("\n" + propName +":" + nClassName +"\n");
+                                                       boolean isIdentifier = Identifier.class.isAssignableFrom(returnClass);
+                                                       if(!isIdentifier && !nClassName.equals("[C")){
+                                                               if(isNumber){
+                                                                       pstr.print("\"" + propName +":Number\",");
+                                                               }else if(isBoolean){
+                                                                       pstr.print("\"" + propName +":Boolean\",");
+                                                               }else{
+                                                                       if(nClassName.equals("[B")){
+                                                                               pstr.print("\"" + propName +":Binary\",");
+                                                                       }else{
+                                                                               pstr.print("\"" + propName +":" + nClassName +"\",");
+                                                                       }
+                                                               }
+                                                               prop.setProperty(propName,"");
+                                                               propList.add(propName);
+                                                       }
+
+                                               }
+                                       }
+                               } // End of section handling "setter" method
+                       } // End of loop through Methods
+               } // End of section handling yang-generated class
+
+               return prop;
+       }
+
+       public static boolean isYangGenerated(Class c) {
+               if (c == null) {
+                       return (false);
+               } else {
+                       //System.out.println(c.getName());
+                       return (c.getName().startsWith("org.opendaylight.yang.gen."));
+               }
+       }
+       
+       public static boolean isIpv4Address(Class c) {
+               
+               if (c == null ) {
+                       return (false);
+               }
+               String simpleName = c.getSimpleName();
+               return ("Ipv4Address".equals(simpleName)) ;
+       }
+       
+       public static boolean isIpv6Address(Class c) {
+               
+               if (c == null ) {
+                       return (false);
+               } 
+               String simpleName = c.getSimpleName();
+               return ("Ipv6Address".equals(simpleName)) ;
+       }
+
+       public static String toLowerHyphen(String inStr) {
+               if (inStr == null) {
+                       return (null);
+               }
+
+               String str = inStr.substring(0, 1).toLowerCase();
+               if (inStr.length() > 1) {
+                       str = str + inStr.substring(1);
+               }
+
+               String regex = "(([a-z0-9])([A-Z]))";
+               String replacement = "$2-$3";
+
+               String retval = str.replaceAll(regex, replacement).toLowerCase();
+
+               //LOG.debug("Converting " + inStr + " => " + str + " => " + retval);
+               return (retval);
+       }
+
+       public static String toUpperCamelCase(String inStr) {
+               if (inStr == null) {
+                       return (null);
+               }
+
+               String[] terms = inStr.split("-");
+               StringBuffer sbuff = new StringBuffer();
+               // Check if string begins with a digit
+               if (Character.isDigit(inStr.charAt(0))) {
+                       sbuff.append('_');
+               }
+               for (String term : terms) {
+                       sbuff.append(term.substring(0, 1).toUpperCase());
+                       if (term.length() > 1) {
+                               sbuff.append(term.substring(1));
+                       }
+               }
+               return (sbuff.toString());
+
+       }
+
+       public static boolean isGetter(Method m) {
+               //System.out.println(m);
+               if (m == null) {
+                       return (false);
+               }
+
+               if (Modifier.isPublic(m.getModifiers())
+                               && (m.getParameterTypes().length == 0)) {
+                       if ((m.getName().matches("^is[A-Z].*") || m.getName().matches("^get[A-Z].*"))
+                                       && m.getReturnType().equals(Boolean.class)) {
+                               return (true);
+                       }
+                       if (m.getName().matches("^get[A-Z].*")
+                                       && !m.getReturnType().equals(void.class)) {
+                               return (true);
+                       }
+
+               }
+
+               return (false);
+       }
+
+       public static boolean isSetter(Method m) {
+               if (m == null) {
+                       return (false);
+               }
+
+               if (Modifier.isPublic(m.getModifiers())
+                               && (m.getParameterTypes().length == 1)) {
+                       if (m.getName().matches("^set[A-Z].*")) {
+                               Class[] paramTypes = m.getParameterTypes();
+                               if (paramTypes[0].isAssignableFrom(Identifier.class)
+                                               || Identifier.class.isAssignableFrom(paramTypes[0])) {
+                                       return (false);
+                               } else {
+                                       return (true);
+                               }
+                       }
+
+               }
+
+               return (false);
+       }
+
+       public static void main(String[] args){
+               try{
+                       PrintStream ps = new PrintStream(new FileOutputStream(FileDescriptor.out));
+                       PrintYangToProp printYangToProp = new PrintYangToProp();
+                       String className = args[0];
+                       //ClassLoader classLoader = PrintYangToProp.class.getClassLoader();
+                       //Class aClass = classLoader.loadClass(className);
+                       Class cl = Class.forName(className);
+                       //printPropertyList(ps,"",cl);
+                       //JsonObject jsonObj = Json.createObjectBuilder().build();
+                       Properties p = getProperties(ps,"",cl); 
+                       //System.out.println(p);
+
+               }catch(Exception e){
+                       e.printStackTrace();
+               }
+       }
+
+
+}
diff --git a/dgbuilder/tools/dot_to_json.js b/dgbuilder/tools/dot_to_json.js
new file mode 100644 (file)
index 0000000..7ff80e8
--- /dev/null
@@ -0,0 +1,138 @@
+var obj={};
+function dotToJson(str,value,obj){
+    //var objArr = path.split("."), part;
+    var objArr = str.split(".");
+       var prevStr;
+       var currObj;
+       var prevObj;
+       //console.log(str);
+       var isArray = false;
+       var prevObjIsArray = false;
+       for(var i=0;i<objArr.length -1;i++){
+               var subStr= objArr[i] ;
+               if(isArray){
+                       prevObjIsArray = true;  
+               }
+               isArray = false;
+               if(subStr.indexOf(']') == subStr.length -1){
+                       subStr = subStr.substring(0,subStr.length -2);
+                       isArray = true;
+               }
+               //console.log("subStr:" + subStr + isArray);
+               //console.dir(prevObj);
+               if(isArray){
+                       if(i==0 && obj[subStr] == undefined ){
+                               //console.log("i==0 && obj[subStr] ");
+                               obj[subStr]=[];
+                       }else if(i==0 && obj[subStr][0] == undefined ){
+                                               obj[subStr][0]={};
+                       }else if(i==0 && obj[subStr][0] != undefined ){
+                               currObj= obj[subStr][0];
+                       }else{
+                               if(i == 1){
+                                       //console.log("i==1 && obj[prevStr] ");
+                                       prevObj=obj[prevStr];
+                                       if(prevObj[subStr] != undefined && prevObj[subStr][0] == undefined){
+                                               prevObj[subStr] = [];
+                                               prevObj[subStr][0] = {};
+                                               currObj = prevObj[subStr][0];
+                                       }else if(prevObj[subStr] != undefined && prevObj[subStr][0] != undefined){
+                                                       currObj = prevObj[subStr][0];
+                                       }else if(prevObj[subStr] == undefined){
+                                               prevObj[subStr] = [];
+                                               prevObj[subStr][0] = {};
+                                               currObj = prevObj[subStr][0];
+                                       }
+                               }else{
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr]=[];
+                                               prevObj[subStr][0]={};
+                                               currObj = prevObj[subStr][0];
+                                       }else{
+                                               currObj = prevObj[subStr][0];
+                                       }
+                               }
+                       }
+               }else{
+                       if(i==0 && obj[subStr] == undefined ){
+                               obj[subStr] = {};
+                               currObj= obj[subStr];
+                       }else if(i==0 && obj[subStr] != undefined ){
+                               currObj=obj[subStr];
+                       //console.log("in gkjgjkg");
+                       }else{
+                               if(i == 1){
+                                       prevObj=obj[prevStr];
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr] = {};
+                                               currObj = prevObj[subStr];
+                                       }else{
+                                               currObj = prevObj[subStr];
+                                       }
+                               }else{
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr] = {};
+                                               currObj = prevObj[subStr];
+                                       }else{
+                                               currObj = prevObj[subStr];
+                                       }
+                               }
+                       }
+               }
+               prevStr=subStr;
+               if(i <objArr.length-2){
+                       //console.dir(currObj);
+                       prevObj=currObj;        
+               }
+       }
+       var lastStr = objArr[objArr.length-1];
+       if(isArray){
+               currObj[lastStr] = value;
+       }else{
+               currObj[lastStr] = value;
+       }
+       //prevObj[lastStr] = value;
+       //console.dir(currObj);
+       return obj;
+}
+function printObj(obj){
+for( j in obj){
+       console.log(j + ":" + obj[j]);
+       if(typeof obj[j] == "object" ){
+               printObj(obj[j]);
+       }
+
+}
+}
+
+/*
+var nObj={};
+for(var i=0;i<a.length;i++){
+       dotToJson(a[i],'',nObj);
+}
+*/
+var sliValuesObj = require(process.argv[2]);
+var moduleName = process.argv[3];
+//console.dir(sliValuesObj);
+var a= sliValuesObj[moduleName + "_VALUES"];  
+var rpcs= sliValuesObj[moduleName + "_RPCS"];  
+var nObj={};
+nObj['moduleName'] = moduleName;
+console.log("module.exports = ");
+for(var i=0;i<a.length;i++){
+       var key =a[i].substring(0,a[i].indexOf(':'));
+       //console.log(key);
+       var value =a[i].substring(a[i].indexOf(':') +1);
+       if(value == undefined) value ="";
+       dotToJson(key,value,nObj);
+}
+
+nObj[moduleName + "_PROPS"] =[];
+for(var i=0;i<a.length;i++){
+       var key =a[i].substring(0,a[i].indexOf(':'));
+       nObj[moduleName + "_PROPS"].push(key);
+}
+
+nObj[moduleName + "_RPCS"] = rpcs;
+
+console.log(JSON.stringify(nObj,null,4));
diff --git a/dgbuilder/tools/formatXml.py b/dgbuilder/tools/formatXml.py
new file mode 100644 (file)
index 0000000..913456a
--- /dev/null
@@ -0,0 +1,11 @@
+import xml.dom.minidom
+import lxml.etree as etree
+import sys
+
+xml_fname=sys.argv[1]
+#xml = xml.dom.minidom.parse(xml_fname) # or xml.dom.minidom.parseString(xml_string)
+#pretty_xml_as_string = xml.toprettyxml()
+#print pretty_xml_as_string
+
+x = etree.parse(xml_fname)
+print etree.tostring(x, pretty_print = True)
diff --git a/dgbuilder/tools/format_json.sh b/dgbuilder/tools/format_json.sh
new file mode 100755 (executable)
index 0000000..f86ad3c
--- /dev/null
@@ -0,0 +1,6 @@
+if [ "$#" != "1" ]
+then
+        echo "Usage: $0 jsonFileFullPath"
+        exit
+fi
+cat $1|python -m json.tool
diff --git a/dgbuilder/tools/format_xml.sh b/dgbuilder/tools/format_xml.sh
new file mode 100755 (executable)
index 0000000..c66153e
--- /dev/null
@@ -0,0 +1,16 @@
+if [ "$#" != "1" ]
+then
+        echo "Usage: $0 xmlFileFullPath"
+        exit
+fi
+
+if [ -z "$PROJECT_HOME" ]
+then
+        export PROJECT_HOME=$(pwd)/..
+fi
+if [ -e "$1" ]
+then
+       python $PROJECT_HOME/tools/formatXml.py $1
+else
+       echo "File $1 does not exist" 
+fi
diff --git a/dgbuilder/tools/generate_props_from_yang.sh b/dgbuilder/tools/generate_props_from_yang.sh
new file mode 100755 (executable)
index 0000000..70162c6
--- /dev/null
@@ -0,0 +1,96 @@
+if [ -z "$PROJECT_HOME" ] 
+then
+       export PROJECT_HOME=$(pwd)/..
+fi
+
+toolsDir=$PROJECT_HOME/tools
+rm -rf ${toolsDir}/tmpws 
+mkdir ${toolsDir}/tmpws
+mkdir ${toolsDir}/tmpws/logs
+mkdir ${toolsDir}/tmpws/jars
+mkdir ${toolsDir}/tmpws/tmp
+if [ "$#" != "1" ]
+then
+       echo "Command line:$0 $*" >${toolsDir}/tmpws/logs/err.log
+       echo "Usage: $0 yangFile" >>${toolsDir}/tmpws/logs/err.log
+       exit
+fi
+
+isZipFile="N"
+echo "$1" | grep "\.zip$" >/dev/null 2>&1
+if [ "$?" -eq "0" ]
+then
+       isZipFile="Y"
+fi
+
+if [ "$isZipFile" = "Y" ]
+then 
+       #zip file of yangs provided
+       zipFile=$(basename $1)
+       unzip -o -d $PROJECT_HOME/tools/tmpws/tmp $1 >/dev/null 2>&1
+       rm $1 >/dev/null 2>&1
+       cd $PROJECT_HOME/tools/tmpws/tmp        
+       fName="${zipFile}"
+       extension="${fName##*.}"
+        moduleName="${fName%.*}"       
+       #echo "ModuleName is :$moduleName"
+       rm -rf $PROJECT_HOME/yangFiles/$moduleName
+       mkdir $PROJECT_HOME/yangFiles/$moduleName
+       mv *.yang $PROJECT_HOME/yangFiles/$moduleName
+       cd $PROJECT_HOME/tools
+       yangFilesFullPath=${PROJECT_HOME}/yangFiles/$moduleName
+       cd ${toolsDir}/tmpws
+       mkdir -p yangApp/model/src/main/yang
+       mkdir -p yangApp/model/src/main/yang-gen-sal
+       cp -r ${yangFilesFullPath}/* yangApp/model/src/main/yang
+       cp ${toolsDir}/pom.xml_base yangApp/model/pom.xml
+       cd ${toolsDir}/tmpws/yangApp/model
+
+       #Maven Compile  
+       mvn clean install >${toolsDir}/tmpws/logs/mvn_install.log 2>${toolsDir}/tmpws/logs/err.log
+       yangApp_model_jar="yangApp-model-1.0.0-SNAPSHOT.jar"
+
+       #Copy the built jar to jars directory
+       cp ${toolsDir}/tmpws/yangApp/model/target/${yangApp_model_jar} ${toolsDir}/tmpws/jars
+       . ${toolsDir}/setClasspath
+       
+       mv  ${toolsDir}/output_js/${moduleName}_inputs.js ${toolsDir}/output_js/${moduleName}_inputs_prev.js >/dev/null 2>&1
+
+       ${toolsDir}/getRpcsClassFromYang.sh ${yangFilesFullPath}/${moduleName}.yang ${toolsDir}/tmpws/yangApp/model/target/${yangApp_model_jar} > ${toolsDir}/output_js/${moduleName}.js
+
+       node ${toolsDir}/dot_to_json.js ${toolsDir}/output_js/${moduleName}.js $moduleName >${toolsDir}/output_js/${moduleName}_inputs.js
+
+       cp ${toolsDir}/output_js/${moduleName}_inputs.js $PROJECT_HOME/generatedJS
+else
+       #Single yang provided
+       yangFileFullPath=$1
+       cd ${toolsDir}/tmpws
+       mkdir -p yangApp/model/src/main/yang
+       mkdir -p yangApp/model/src/main/yang-gen-sal
+       cp ${yangFileFullPath} yangApp/model/src/main/yang
+       cp ${toolsDir}/pom.xml_base yangApp/model/pom.xml
+       cd ${toolsDir}/tmpws/yangApp/model
+       
+       #Maven Compile  
+       mvn clean install >${toolsDir}/tmpws/logs/mvn_install.log 2>${toolsDir}/tmpws/logs/err.log
+       yangApp_model_jar="yangApp-model-1.0.0-SNAPSHOT.jar"
+
+       #Copy the built jar to jars directory
+       cp ${toolsDir}/tmpws/yangApp/model/target/${yangApp_model_jar} ${toolsDir}/tmpws/jars
+       . ${toolsDir}/setClasspath
+       
+       moduleName=$(cat $yangFileFullPath|egrep "module .*{"|cut -d' ' -f2|cut -d'{' -f1)
+
+       mv  ${toolsDir}/output_js/${moduleName}_inputs.js ${toolsDir}/output_js/${moduleName}_inputs_prev.js >/dev/null 2>&1
+
+       ${toolsDir}/getRpcsClassFromYang.sh ${yangFileFullPath} ${toolsDir}/tmpws/yangApp/model/target/${yangApp_model_jar} > ${toolsDir}/output_js/${moduleName}.js
+
+       node ${toolsDir}/dot_to_json.js ${toolsDir}/output_js/${moduleName}.js $moduleName >${toolsDir}/output_js/${moduleName}_inputs.js
+
+       cp ${toolsDir}/output_js/${moduleName}_inputs.js $PROJECT_HOME/generatedJS
+
+
+fi
+
+echo "Done..."
+
diff --git a/dgbuilder/tools/getModuleName.sh b/dgbuilder/tools/getModuleName.sh
new file mode 100755 (executable)
index 0000000..cf0db19
--- /dev/null
@@ -0,0 +1,2 @@
+module=$(cat $1|egrep "module .*{"|awk '{print $2}'|sed -e 's/{//g')
+echo $module
diff --git a/dgbuilder/tools/getRpcsClassFromYang.sh b/dgbuilder/tools/getRpcsClassFromYang.sh
new file mode 100755 (executable)
index 0000000..b070315
--- /dev/null
@@ -0,0 +1,85 @@
+toolsDir=$PROJECT_HOME/tools
+. ${toolsDir}/setClasspath
+if [ "$#" != "2" ]
+then
+       echo "Usage $0 yang_file generated_jar_file"
+       echo "example $0 /home/users/sdnc/src/sample.yang  /home/users/sdnc/target/sample.model-1.0.0.jar"
+       exit
+fi
+yangFile="$1"
+jarFile="$2"
+module=$(cat $yangFile|egrep "module .*{"|awk '{print $2}'|sed -e 's/{//g')
+#echo "        \"$module\" : ["
+rpcs=$(grep rpc $yangFile|grep -v leaf|sed -e 's/^\s\+rpc//g'|awk '{print $1}')
+#echo ${rpcs}
+for i in `find ${PROJECT_HOME}/svclogic/lib -name "*.jar" -print`
+do
+#echo $i
+export CLASSPATH=$CLASSPATH:$i
+done
+export CLASSPATH=$CLASSPATH:${toolsDir}/printYangToProp.jar:.
+allProps=""
+for rpc in $rpcs
+do
+rpcVal=$(echo $rpc|sed -e "s/\b\(.\)/\u\1/g"|sed s/\-//g)
+className=$(jar -tvf ${jarFile}|grep "org/opendaylight/yang/gen/"|grep  -w "${rpcVal}Input.class"|grep -v grep|awk '{print $NF}'|sed -e 's/\//./g'|sed -e 's/.class$//g')
+inputProps=""
+if [ "$className" != "" ]
+then
+       #java -cp $CLASSPATH PrintYangToProp $className 2>/dev/null|grep '*' |cut -d'*' -f2|sed -e "s/^[ \t]*//g"|sed -e "s/^/\t\t\"/g"|sed -e "s/$/\",/g"
+       inputProps=$(java -cp $CLASSPATH PrintYangToProp $className 2>${toolsDir}/tmpws/logs/err.log)
+fi
+className=$(jar -tvf ${jarFile}|grep "org/opendaylight/yang/gen/"|grep -w "${rpcVal}Output"|grep -v grep|awk '{print $NF}'|sed -e 's/\//./g'|sed -e 's/.class$//g')
+#echo $inputProps
+#echo $className
+outputProps=""
+if [ "$className" != "" ]
+then
+       #java -cp $CLASSPATH PrintYangToProp $className 2>/dev/null|grep '*' |cut -d'*' -f2|sed -e "s/^[ \t]*//g"|sed -e "s/^/\t\t\"/g"|sed -e "s/$/\",/g"
+       outputProps=$(java -cp $CLASSPATH PrintYangToProp $className 2>${toolsDir}/tmpws/logs/err.log)
+fi
+if [ -z "$allProps" ]
+then
+       allProps=$(echo ${inputProps}${outputProps}|sed -e s/,$//g)
+else
+       allProps=$(echo ${allProps},${inputProps}${outputProps}|sed -e s/,$//g)
+fi
+done
+#allProps=$(echo ${inputProps}${outputProps}|sed -e s/,$//g)
+#echo $allProps
+#OIFS=$IFS
+#IFS=','
+#arr2=$allProps
+#for x in $arr2
+#do
+#    echo "$x"
+#done
+#IFS=$OIFS
+#echo "        ]"
+echo "module.exports = {"
+echo "\"moduleName\" : \"${module}\","
+echo "'${module}_VALUES' : "
+echo "[ $allProps ]"|python -m json.tool
+echo ","
+echo "'${module}_RPCS' : ["
+
+cnt=0
+#numOfRpcs=${#rpcs[@]}
+numOfRpcs=0;
+for rpc in $rpcs
+do
+       numOfRpcs=$((numOfRpcs+1))
+done
+
+for rpc in $rpcs
+do
+       cnt=$((cnt+1))
+       if [ $cnt -eq $numOfRpcs ]
+       then
+               echo "          \"$rpc\""
+       else
+               echo "          \"$rpc\","
+        fi
+done
+echo " ]"
+echo "}"
diff --git a/dgbuilder/tools/jsonTool.js b/dgbuilder/tools/jsonTool.js
new file mode 100644 (file)
index 0000000..d95ae10
--- /dev/null
@@ -0,0 +1,119 @@
+var obj={};
+function dotToJson(str,value,obj){
+    //var objArr = path.split("."), part;
+    var objArr = str.split(".");
+       var prevStr;
+       var currObj;
+       var prevObj;
+       //console.log(str);
+       var isArray = false;
+       var prevObjIsArray = false;
+       for(var i=0;i<objArr.length -1;i++){
+               var subStr= objArr[i] ;
+               if(isArray){
+                       prevObjIsArray = true;  
+               }
+               isArray = false;
+               if(subStr.indexOf(']') == subStr.length -1){
+                       subStr = subStr.substring(0,subStr.length -2);
+                       isArray = true;
+               }
+               //console.log("subStr:" + subStr + isArray);
+               //console.dir(prevObj);
+               if(isArray){
+                       if(i==0 && obj[subStr] == undefined ){
+                               //console.log("i==0 && obj[subStr] ");
+                               obj[subStr]=[];
+                       }else if(i==0 && obj[subStr][0] == undefined ){
+                                               obj[subStr][0]={};
+                       }else if(i==0 && obj[subStr][0] != undefined ){
+                               currObj= obj[subStr][0];
+                       }else{
+                               if(i == 1){
+                                       //console.log("i==1 && obj[prevStr] ");
+                                       prevObj=obj[prevStr];
+                                       if(prevObj[subStr][0] == undefined){
+                                               prevObj[subStr] = [];
+                                               prevObj[subStr][0] = {};
+                                               currObj = prevObj[subStr][0];
+                                       }else{
+                                               currObj = prevObj[subStr][0];
+                                       }
+                               }else{
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr]=[];
+                                               prevObj[subStr][0]={};
+                                               currObj = prevObj[subStr][0];
+                                       }else{
+                                               currObj = prevObj[subStr][0];
+                                       }
+                               }
+                       }
+               }else{
+                       if(i==0 && obj[subStr] == undefined ){
+                               obj[subStr] = {};
+                               currObj= obj[subStr];
+                       }else if(i==0 && obj[subStr] != undefined ){
+                               currObj=obj[subStr];
+                       //console.log("in gkjgjkg");
+                       }else{
+                               if(i == 1){
+                                       prevObj=obj[prevStr];
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr] = {};
+                                               currObj = prevObj[subStr];
+                                       }else{
+                                               currObj = prevObj[subStr];
+                                       }
+                               }else{
+                                       if(prevObj[subStr] == undefined){
+                                               prevObj[subStr] = {};
+                                               currObj = prevObj[subStr];
+                                       }else{
+                                               currObj = prevObj[subStr];
+                                       }
+                               }
+                       }
+               }
+               prevStr=subStr;
+               if(i <objArr.length-2){
+                       //console.dir(currObj);
+                       prevObj=currObj;        
+               }
+       }
+       var lastStr = objArr[objArr.length-1];
+       if(isArray){
+               currObj[lastStr] = value;
+       }else{
+               currObj[lastStr] = value;
+       }
+       //prevObj[lastStr] = value;
+       //console.dir(currObj);
+       return obj;
+}
+function printObj(obj){
+for( j in obj){
+       console.log(j + ":" + obj[j]);
+       if(typeof obj[j] == "object" ){
+               printObj(obj[j]);
+       }
+
+}
+}
+
+var a=[];
+var nObj={};
+for(var i=0;i<a.length;i++){
+       dotToJson(a[i],'',nObj);
+}
+
+var nObj={};
+for(var i=0;i<a.length;i++){
+       var key =a[i].substring(0,a[i].indexOf(':'));
+       console.log(key);
+       var value =a[i].substring(a[i].indexOf(':') +1);
+       if(value == undefined) value ="";
+       dotToJson(key,value,nObj);
+}
+console.log(JSON.stringify(nObj,null,4));
+//console.log (stringToObj('abc.ebg.h',"",{}));
diff --git a/dgbuilder/tools/json_to_html b/dgbuilder/tools/json_to_html
new file mode 100644 (file)
index 0000000..51afe45
--- /dev/null
@@ -0,0 +1,139 @@
+try{ 
+var jsonStr='{}';
+jsonObj=JSON.parse(jsonStr);
+var objectId =0;
+var level=0;
+var htmlStr=""
+htmlStr += "<html>";
+htmlStr += "<head>";
+htmlStr += "<script>";
+htmlStr += "function show(idVal){";
+htmlStr += "   var val = \"<table border='1'>\" + document.getElementById(idVal).value + \"</table>\";";
+htmlStr += "   document.getElementById('displayId').innerHTML = val;";
+htmlStr += "document.getElementById('displayId').style.display = \"block\";";
+//htmlStr += "alert(idVal);";
+//htmlStr += "alert(val);";
+htmlStr += "}";
+htmlStr += "</script>";
+htmlStr += "</head>";
+htmlStr += "<div id='displayId' style='display:none'></div>";
+htmlStr += "<div>\n<table border='1'>\n";
+printObjectValues(jsonObj,level);
+htmlStr += "\n</table>\n</div>";
+//var pattern = new RegExp("\\n","g");
+//htmlstr =htmlStr.replace(pattern,'');
+htmlStr += "</html>";
+console.log(htmlStr);
+
+function tabs(level){
+return '';     
+}
+function tabsOrig(level){
+       var tabs="";
+       for(var i=0;i<level;i++){
+               tabs += "\t";
+       }
+       return tabs;
+}
+
+function printObjectValues(jsonObj,level){
+var output="";
+var objectHtmlStr="";
+try{
+for (var key in jsonObj) {
+//console.log(key +":" + jsonObj.hasOwnProperty(key));
+  if (jsonObj.hasOwnProperty(key)) {
+       var v = jsonObj[key];
+       if(typeof v === 'object' && Array.isArray(v) === false){
+               var idVal = objectId++;
+               level++;
+               objectHtmlStr += tabs(level) + "<div>\n" ;
+               objectHtmlStr += tabs(level+1 ) +"<table border='1'>\n" ;
+
+               var str=printObjectValues(v,level+2);
+               if(str != null && str != ''){
+                       htmlStr += tabs(level+2) + objectHtmlStr + "<tr><td style='background-color:green'><a href=\"javascript:show('obj_" + idVal + "')\">" + key + "</a>\n";
+                       htmlStr +="<input id='obj_" + idVal + "' type='hidden' value='" + str.trim() + "'>\n";
+               }
+
+               htmlStr += tabs(level+1) + "</table>\n" ;
+               htmlStr += tabs(level) + "</div>\n";
+       }else if(typeof v === 'object' && Array.isArray(v) === true){
+               var idVal = objectId++;
+               level++;
+               objectHtmlStr += tabs(level) + "<div>\n";
+               objectHtmlStr += tabs(level+1) + "<table border='1'>\n";
+
+               var str = printArrayValues(v,key,level+2);
+               if(str != null && str != ''){
+                       htmlStr += tabs(level+2) + objectHtmlStr + "<tr><td style='background-color:blue'><a href=\"javascript:show('obj_" + idVal + "')\">" + key + "</a>\n";
+               htmlStr+="<input id='obj_" + objectId + "' type='hidden' value='" +  str.trim() + "'>\n";
+               }
+
+               htmlStr += tabs(level+1) + "</table>\n" ;
+               htmlStr += tabs(level) + "</div>\n";
+       }else{
+               output += tabs(level) +"<tr><td>" + key + "</td><td>" + printValue(v) + "</td></tr>\n";
+       }
+  }
+}
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+}catch(err){ 
+console.log( err );
+}
+
+function printArrayValues(arrObj,key,level){
+var output ="";
+var arrayHtmlStr ="";
+try{
+       for(var i=0;arrObj != null && i<arrObj.length;i++){
+               var o=arrObj[i];
+               if(typeof o === 'object' && Array.isArray(o) === false){
+                       var idVal = objectId++;
+                       level++;
+                       arrayHtmlStr += tabs(level) + "<div>\n" ;
+                       arrayHtmlStr += tabs(level+1 ) +"<table border='1'>\n" ;
+
+                       var str = printObjectValues(o,level+2);
+                       if(str != null && str != ''){
+                               htmlStr += tabs(level+2 ) + arrayHtmlStr + "<tr><td><a href=\"javascript:show('obj_" + idVal + "')\">" +key + "[" + i + "]"  + "</a>\n";
+                               htmlStr+="<input id='obj_" + idVal + "' type='hidden' value='" +str.trim() + "'>\n";
+                       }
+                       htmlStr += tabs(level+1) + "</table>\n";
+                       htmlStr += tabs(level) + "</div>\n";
+               }else if(typeof o === 'object' && Array.isArray(v) === true){
+                       var idVal = objectId++;
+                       level++;
+                       arrayHtmlStr += tabs(level) + "<div>\n" ;
+                       arrayHtmlStr += tabs(level+1 ) +"<table border='1'>\n" ;
+
+                       var str = printArrayValues(o,key,level);
+                       if(str != null && str != ''){
+                               htmlStr += tabs(level+2 ) + arrayHtmlStr + "<tr><td><a href=\"javascript:show('obj_" + idVal + "')\">Array</a>\n";
+                               htmlStr+="<input id='obj_" + idVal + "' type='hidden' value='" +str.trim() + "'>\n";
+                       }
+
+                       htmlStr += tabs(level+1) + "</table>\n";
+                       htmlStr += tabs(level) + "</div>\n";
+               }else{
+                       output += tabs(level) + "<tr><td>" + printValue(o) + "</td></tr>\n";
+               }
+       }
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+function printValue(obj){
+       if(obj != undefined){
+               return obj;
+       }else{
+               return "";
+       }
+}
diff --git a/dgbuilder/tools/json_to_html_table b/dgbuilder/tools/json_to_html_table
new file mode 100755 (executable)
index 0000000..20c9cfe
--- /dev/null
@@ -0,0 +1,144 @@
+try{ 
+var jsonStr='{}'; 
+jsonObj=JSON.parse(jsonStr);
+var htmlObj ={};
+var objectId =0;
+var level=0;
+var htmlStr=""
+htmlStr += "<html>";
+htmlStr += "<head>";
+htmlStr += "<script>";
+htmlStr += "function show(idVal){";
+htmlStr += "   var val = \"<table border='1'>\" + document.getElementById(idVal).value + \"</table>\";";
+htmlStr += "   document.getElementById('displayId').innerHTML = val;";
+htmlStr += "document.getElementById('displayId').style.display = \"block\";";
+//htmlStr += "alert(idVal);";
+//htmlStr += "alert(val);";
+htmlStr += "}";
+htmlStr += "</script>";
+htmlStr += "</head>";
+htmlStr += "<div id='displayId' style='display:none'></div>";
+htmlStr += "<div>\n<table border='1'>\n";
+console.log("<html><table border='1'>");
+printObjectValues(jsonObj,null,level);
+console.log("</table></html>");
+htmlStr += "\n</table>\n</div>";
+//var pattern = new RegExp("\\n","g");
+//htmlstr =htmlStr.replace(pattern,'');
+htmlStr += "</html>";
+//console.log(htmlStr);
+
+//console.dir(htmlObj);
+var keyObj={};
+for (var key in htmlObj) {
+       var idx = key.lastIndexOf(".");
+       if(idx != -1){
+               var str = key.substr(0,idx);
+               keyObj[str] ='';
+       }else{
+               keyObj[key] ='';
+       }       
+       //console.log(str);
+}
+
+console.dir(keyObj);
+console.log("<ul>");
+for (var key in keyObj) {
+       console.log("<li>" + key + "</li>");
+}
+console.log("</ul>");
+
+function tabs(level){
+return '';     
+}
+function tabsOrig(level){
+       var tabs="";
+       for(var i=0;i<level;i++){
+               tabs += "\t";
+       }
+       return tabs;
+}
+
+function printObjectValues(jsonObj,pkey,level){
+var output="";
+var objectHtmlStr="";
+try{
+for (var key in jsonObj) {
+  if (jsonObj.hasOwnProperty(key)) {
+       var v = jsonObj[key];
+       if(typeof v === 'object' && Array.isArray(v) === false){
+               var nkey="";
+               if(pkey != null){
+                       nkey = pkey + "." + key;        
+               }else{
+                       nkey = key;
+               }
+               var str=printObjectValues(v,nkey,level+2);
+       }else if(typeof v === 'object' && Array.isArray(v) === true){
+               var nkey="";
+               if(pkey != null){
+                       nkey = pkey + "." + key;        
+               }else{
+                       nkey = key;
+               }
+               var str = printArrayValues(v,nkey,level+2);
+       }else{
+               if(pkey != null){
+                       //console.log(pkey + "." + key + ":" +printValue(v) );
+                       console.log("<tr><td>" + pkey + "." + key + "</td><td>" +printValue(v) + "</td></tr>" );
+                       htmlObj[pkey +  "." + key ] = printValue(v);
+               }else{
+                       //console.log( key + ":" +printValue(v) );
+                       console.log("<tr><td>" + key + "</td><td>" +printValue(v) + "</td></tr>" );
+                       htmlObj[key ] = printValue(v);
+               }
+               //printValue(v); 
+       }
+  }
+}
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+}catch(err){ 
+console.log( err );
+}
+
+function printArrayValues(arrObj,pkey,level){
+var output ="";
+var arrayHtmlStr ="";
+try{
+       for(var i=0;arrObj != null && i<arrObj.length;i++){
+               var o=arrObj[i];
+               if(typeof o === 'object' && Array.isArray(o) === false){
+                       var nkey = pkey +"[" + i + "]"  ;
+                       var str = printObjectValues(o,nkey,level+2);
+               }else if(typeof o === 'object' && Array.isArray(v) === true){
+                       var nkey = pkey +"[" + i + "]"  ;
+                       var str = printArrayValues(o,nkey,level);
+               }else{
+                       console.log("<tr><td>" + pkey + "." + key + "</td><td>" +printValue(o) + "</td></tr>" );
+                       htmlObj[pkey +  "." + key ] = printValue(o);
+                       //console.log(pkey + ":" +printValue(o) );
+                       //output += tabs(level) + "<tr><td>" + printValue(o) + "</td></tr>\n";
+               }
+       }
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+function printValue(obj){
+       if(obj != undefined){
+               if(typeof obj == 'string'){
+                       return "'" +  obj + "'";
+               }else{
+                       return obj;
+               }
+       }else{
+               return "";
+       }
+}
diff --git a/dgbuilder/tools/json_to_prop b/dgbuilder/tools/json_to_prop
new file mode 100755 (executable)
index 0000000..f8830f3
--- /dev/null
@@ -0,0 +1,116 @@
+try{ 
+var jsonStr='{}';
+jsonObj=JSON.parse(jsonStr);
+var htmlObj ={};
+var objectId =0;
+var level=0;
+var htmlStr=""
+htmlStr += "<html>";
+htmlStr += "<head>";
+htmlStr += "<script>";
+htmlStr += "function show(idVal){";
+htmlStr += "   var val = \"<table border='1'>\" + document.getElementById(idVal).value + \"</table>\";";
+htmlStr += "   document.getElementById('displayId').innerHTML = val;";
+htmlStr += "document.getElementById('displayId').style.display = \"block\";";
+//htmlStr += "alert(idVal);";
+//htmlStr += "alert(val);";
+htmlStr += "}";
+htmlStr += "</script>";
+htmlStr += "</head>";
+htmlStr += "<div id='displayId' style='display:none'></div>";
+htmlStr += "<div>\n<table border='1'>\n";
+printObjectValues(jsonObj,null,level);
+htmlStr += "\n</table>\n</div>";
+//var pattern = new RegExp("\\n","g");
+//htmlstr =htmlStr.replace(pattern,'');
+htmlStr += "</html>";
+//console.log(htmlStr);
+
+function tabs(level){
+return '';     
+}
+function tabsOrig(level){
+       var tabs="";
+       for(var i=0;i<level;i++){
+               tabs += "\t";
+       }
+       return tabs;
+}
+
+function printObjectValues(jsonObj,pkey,level){
+var output="";
+var objectHtmlStr="";
+try{
+for (var key in jsonObj) {
+  if (jsonObj.hasOwnProperty(key)) {
+       var v = jsonObj[key];
+       if(typeof v === 'object' && Array.isArray(v) === false){
+               var nkey="";
+               if(pkey != null){
+                       nkey = pkey + "." + key;        
+               }else{
+                       nkey = key;
+               }
+               var str=printObjectValues(v,nkey,level+2);
+       }else if(typeof v === 'object' && Array.isArray(v) === true){
+               var nkey="";
+               if(pkey != null){
+                       nkey = pkey + "." + key;        
+               }else{
+                       nkey = key;
+               }
+               var str = printArrayValues(v,nkey,level+2);
+       }else{
+               if(pkey != null){
+                       console.log(pkey + "." + key + ":" +printValue(v) );
+               }else{
+                       console.log(key + ":" +printValue(v) );
+               }
+               //printValue(v); 
+       }
+  }
+}
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+}catch(err){ 
+console.log( err );
+}
+
+function printArrayValues(arrObj,pkey,level){
+var output ="";
+var arrayHtmlStr ="";
+try{
+       for(var i=0;arrObj != null && i<arrObj.length;i++){
+               var o=arrObj[i];
+               if(typeof o === 'object' && Array.isArray(o) === false){
+                       var nkey = pkey +"[" + i + "]"  ;
+                       var str = printObjectValues(o,nkey,level+2);
+               }else if(typeof o === 'object' && Array.isArray(v) === true){
+                       var nkey = pkey +"[" + i + "]"  ;
+                       var str = printArrayValues(o,nkey,level);
+               }else{
+                       console.log(pkey + ":" +printValue(o) );
+                       //output += tabs(level) + "<tr><td>" + printValue(o) + "</td></tr>\n";
+               }
+       }
+}catch(err){
+       console.log(err);
+}
+return output;
+}
+
+function printValue(obj){
+       if(obj != undefined){
+               if(typeof obj == 'string'){
+                       return "'" +  obj + "'";
+               }else{
+                       return obj;
+               }
+       }else{
+               return "";
+       }
+}
diff --git a/dgbuilder/tools/output_js/.gitignore b/dgbuilder/tools/output_js/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/dgbuilder/tools/pom.xml_base b/dgbuilder/tools/pom.xml_base
new file mode 100644 (file)
index 0000000..b54c27f
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.onap.ccsdk.distribution</groupId>
+               <artifactId>distribution-root</artifactId>      
+                <version>0.1.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>yangApp-model</artifactId>
+       <packaging>bundle</packaging>
+        <version>1.0.0-SNAPSHOT</version>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <extensions>true</extensions>
+                               <configuration>
+                                       <instructions>
+                                               <Import-Package>*</Import-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.opendaylight.yangtools</groupId>
+                               <artifactId>yang-maven-plugin</artifactId>
+                               <version>${odl.yangtools.yang.maven.plugin.version}</version>
+                               <dependencies>
+                                       <dependency>
+                                               <groupId>org.opendaylight.mdsal</groupId>
+                                               <artifactId>maven-sal-api-gen-plugin</artifactId>
+                                               <version>${odl.sal.api.gen.plugin.version}</version>
+                                               <type>jar</type>
+                                       </dependency>
+                               </dependencies>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>generate-sources</goal>
+                                               </goals>
+                                               <configuration>
+                                                       <yangFilesRootDir>${yang.file.directory}</yangFilesRootDir>
+                                                       <codeGenerators>
+                                                               <generator>
+                                                                       <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                                                       <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                                               </generator>
+                                                       </codeGenerators>
+                                                       <inspectDependencies>true</inspectDependencies>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal</groupId>
+                       <artifactId>yang-binding</artifactId>
+                       <version>${odl.mdsal.yang.binding.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.yangtools</groupId>
+                       <artifactId>yang-common</artifactId>
+                       <version>${odl.yangtools.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal.model</groupId>
+                       <artifactId>ietf-inet-types</artifactId>
+                       <version>${odl.ietf-inet-types.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.opendaylight.mdsal.model</groupId>
+                       <artifactId>ietf-yang-types</artifactId>
+                       <version>${odl.ietf-yang-types.version}</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/dgbuilder/tools/printYangProps.sh b/dgbuilder/tools/printYangProps.sh
new file mode 100755 (executable)
index 0000000..7d1d0fa
--- /dev/null
@@ -0,0 +1,8 @@
+toolsDir=$PROJECT_HOME/tools
+. ${toolsDir}/setClasspath
+if [ "$#" != "1" ]
+then
+       echo "Usage $0 className_without_the_dot_class_ext"
+       exit
+fi
+ java PrintYangToProp $1 
diff --git a/dgbuilder/tools/printYangToProp.jar b/dgbuilder/tools/printYangToProp.jar
new file mode 100644 (file)
index 0000000..01b7310
Binary files /dev/null and b/dgbuilder/tools/printYangToProp.jar differ
diff --git a/dgbuilder/tools/rs b/dgbuilder/tools/rs
new file mode 100755 (executable)
index 0000000..3d92b62
--- /dev/null
@@ -0,0 +1,2 @@
+#replaces / with a .
+echo $1|sed -e s%/%.%g
diff --git a/dgbuilder/tools/setClasspath b/dgbuilder/tools/setClasspath
new file mode 100755 (executable)
index 0000000..898ef35
--- /dev/null
@@ -0,0 +1,13 @@
+toolsDir=${PROJECT_HOME}/tools
+svcLogicLib=${PROJECT_HOME}/svclogic/lib
+
+export CLASSPATH=
+for i in `find ${svcLogicLib} -name "*.jar" -print`
+do
+export CLASSPATH=$CLASSPATH:$i
+done
+
+for i in `find ${toolsDir}/tmpws/jars -name "*.jar" -print`
+do
+export CLASSPATH=$CLASSPATH:$i
+done
diff --git a/dgbuilder/yangFiles/.gitignore b/dgbuilder/yangFiles/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/pom.xml b/pom.xml
index 62a1372..525f231 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -31,5 +31,6 @@
         <module>ubuntu</module>
         <module>opendaylight</module>
         <module>odlsli</module>
+        <module>dgbuilder</module>
     </modules>
 </project>