From noreply at r-forge.r-project.org Thu Jan 2 16:39:43 2014 From: noreply at r-forge.r-project.org (noreply at r-forge.r-project.org) Date: Thu, 2 Jan 2014 16:39:43 +0100 (CET) Subject: [Rpad-commits] r3 - in pkg/Rpad: . R inst inst/basehtml inst/basehtml/server man Message-ID: <20140102153943.D4521183CC5@r-forge.r-project.org> Author: jedick Date: 2014-01-02 16:39:42 +0100 (Thu, 02 Jan 2014) New Revision: 3 Added: pkg/Rpad/inst/basehtml/index.html pkg/Rpad/inst/basehtml/server/ pkg/Rpad/inst/basehtml/server/R_process.pl pkg/Rpad/inst/basehtml/server/Rpad_process.pl pkg/Rpad/man/Rpad-package.Rd Removed: pkg/Rpad/inst/basehtml/LocalDefault.Rpad Modified: pkg/Rpad/DESCRIPTION pkg/Rpad/R/LocalVersion.R pkg/Rpad/inst/NEWS pkg/Rpad/inst/README pkg/Rpad/inst/basehtml/DojoTest.html pkg/Rpad/inst/basehtml/Example1.Rpad pkg/Rpad/inst/basehtml/Rpad.css pkg/Rpad/inst/basehtml/Rpad_body.js pkg/Rpad/inst/basehtml/ServerNotes.html pkg/Rpad/man/RpadLocalServer.Rd Log: restore some functionality to the server version Modified: pkg/Rpad/DESCRIPTION =================================================================== --- pkg/Rpad/DESCRIPTION 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/DESCRIPTION 2014-01-02 15:39:42 UTC (rev 3) @@ -1,6 +1,6 @@ Package: Rpad Title: Workbook-style, web-based interface to R -Version: 1.3.99.0 +Version: 1.3.99.1 Author: Tom Short (EPRI), Philippe Grosjean (UMH EcoNum), Jeffrey Dick Description: A workbook-style user interface to R through a web browser. Provides convenient interaction with an R process Modified: pkg/Rpad/R/LocalVersion.R =================================================================== --- pkg/Rpad/R/LocalVersion.R 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/R/LocalVersion.R 2014-01-02 15:39:42 UTC (rev 3) @@ -36,13 +36,13 @@ "Rpad" <- -function(file = "", defaultfile = "LocalDefault.Rpad", port = 8079) { +function(file = "", defaultfile = "index.html", port = 8079) { startRpadServer(defaultfile, port) browseURL(paste("http://127.0.0.1:", port, "/", file, sep = "")) } "startRpadServer" <- -function(defaultfile = "LocalDefault.Rpad", port = 8079) { +function(defaultfile = "index.html", port = 8079) { require("tcltk") # This is the main function that starts the server # This function implements a basic http server on 'port' Modified: pkg/Rpad/inst/NEWS =================================================================== --- pkg/Rpad/inst/NEWS 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/inst/NEWS 2014-01-02 15:39:42 UTC (rev 3) @@ -1,3 +1,20 @@ +CHANGES IN Rpad 1.3.99.1 (2014-01-02) +------------------------------------- + +- Restore Perl files related to server version of Rpad + (Rpad_process.pl, R_process.pl). + +- Rename LocalDefault.Rpad to index.html (used in both the local and + server versions). + +- Remove outdated Debian and Windows sections in ServerNotes.html, but + move some of the notes to "Additional Notes". + +- Major revision of R_process.pl. Now uses a recent Statistics::R + (tested with version 0.32), forks a background Perl process, + uses Linux:Inotify to become aware of R commands and Time:Out + to self-destruct. + CHANGES IN Rpad 1.3.99.0 (2013-12-31) ------------------------------------- Modified: pkg/Rpad/inst/README =================================================================== --- pkg/Rpad/inst/README 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/inst/README 2014-01-02 15:39:42 UTC (rev 3) @@ -1,13 +1,14 @@ This is the Rpad "inst" directory -README this file -ChangeLog old ChangeLog, from Rpad 1.3.0 (April 2007) -NEWS current NEWS -tcl/ HTTP server written in TCL -server/ Perl files for the server version of Rpad -basehtml/ The Javascript, CSS and example HTML files for Rpad -app.profile.js Application build profile for Dojo customization -LICENSE.dojo License for the Dojo toolkit (http://dojotoolkit.org/) +README This file +ChangeLog Old ChangeLog, from Rpad 1.3.0 (April 2007) +NEWS Current NEWS +tcl/ Local HTTP server in TCL +basehtml/ The Javascript, CSS and example HTML files for Rpad +basehtml/server/ Perl files for the server version of Rpad +perl_interface/ Statistics::Rpad Perl module, based on Statistics::R +app.profile.js Application build profile for Dojo customization +LICENSE.dojo License for the Dojo toolkit (http://dojotoolkit.org/) -------- Parts of app.profile.js were adapted from the Dojo boilerplate: Modified: pkg/Rpad/inst/basehtml/DojoTest.html =================================================================== --- pkg/Rpad/inst/basehtml/DojoTest.html 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/inst/basehtml/DojoTest.html 2014-01-02 15:39:42 UTC (rev 3) @@ -29,7 +29,7 @@
The heading immediately above should say "Hello Dojo!" then change to "Hello" a few seconds later. This confirms that Dojo is loaded and can locate modules programmatically (in JavaScript).
+The heading immediately above should say "Hello Dojo!" then change to "Hello" a few seconds later. This confirms that Dojo is loaded and can locate modules programmatically (in JavaScript). It may not work on the server version of Rpad (if myModule.js is not in the webserver root directory).
There should be a button below with a counter that increments when clicked. This confirms that Dojo widgets can be instantiated declaratively (in markup).
Modified: pkg/Rpad/inst/basehtml/Example1.Rpad =================================================================== --- pkg/Rpad/inst/basehtml/Example1.Rpad 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/inst/basehtml/Example1.Rpad 2014-01-02 15:39:42 UTC (rev 3) @@ -22,8 +22,6 @@ --> - --
+print(sdlog) ++
Deleted: pkg/Rpad/inst/basehtml/LocalDefault.Rpad =================================================================== --- pkg/Rpad/inst/basehtml/LocalDefault.Rpad 2013-12-31 05:19:15 UTC (rev 2) +++ pkg/Rpad/inst/basehtml/LocalDefault.Rpad 2014-01-02 15:39:42 UTC (rev 3) @@ -1,167 +0,0 @@ - - - - - - - - -Rpad Base Page - - - - - - - - - - - - - -
- Rpad/HTML pages in working directory (click on the link to load the file): - - - -
-
-
-
-
-
-
--.threecolumns = function(lst) { - n = length(lst) - if (n <= 3) return(as.matrix(lst)) - ncol = 3 - nrow = ceiling(n / ncol) - lst = as.matrix(append(lst, rep("", ncol * nrow - n))) - dim(lst) = c(nrow, ncol) - lst -} -.rpadfiles = grep('\\.html$|\\.rpad$', dir(), ignore.case = TRUE, value = TRUE) -.rpadfiles = H("a", href = .rpadfiles, collapseContents = FALSE, - .rpadfiles) -.rpadfiles = .threecolumns(.rpadfiles) -HTMLon() -Html(.rpadfiles) -- Objects in user's workspace: -
-
-
--# print(ls.str(), wid = 40, nchar.max = 20, vec.len=2) -ls() -- Enter R code here and press - -or F9 to run it: - -
-
-
-
-
- |
- Help - - -Rpad documentation-Server notes - - - Rpad Demos - - -General Example-Input Examples -Dojo Test Page -Rpad Test Page - - - Links - - -Tom Short's R refcard-Matt Baggot's R refcard v2 -Liu's R refcard -Rpad homepage -R homepage - - - - - |
Rpad has been setup with Linux using the Apache server, with - either Apache 1.3 or Apache 2.0. It may - well work on others, but this was the easiest option. Under - windows, it has also been tested with Apache - (although it doesn't seem as responsive as apache under linux). I have - also had good experiences using Rpad with coLinux (www.colinux.org) under - win2k with R, Apache, and mod_perl. Rpad can be installed using - CGI for the perl portion or with mod_perl. These directions - describe installation with mod_perl:
+This document outlines the setup of the server version of Rpad on Linux using Apache 2.4. + The Perl portion of the Rpad interface can be installed using CGI or mod_perl.
The main steps to installing Rpad on a server are:
@@ -47,49 +40,54 @@cp -r /usr/lib/R/library/Rpad/basehtml /var/www/Rpad-
+LoadModule cgi_module modules/mod_cgi.so <Directory /var/www/Rpad/server*> - <IfModule mod_perl.c> - <Files *.pl> # requires mod_perl - SetHandler perl-script - PerlHandler Apache::Registry - Options +ExecCGI - PerlSendHeader ON - </Files> - </IfModule> Options +ExecCGI AddHandler cgi-script .pl <IfModule mod_expires.c> @@ -97,66 +95,35 @@ ExpiresDefault "now plus 0 seconds" </IfModule> </Directory> -AddType text/x-component .htc AddType text/html .Rpad
+LoadModule perl_module modules/mod_perl.so <Directory /var/www/Rpad/server*> <IfModule mod_perl.c> <Files *.pl> # requires mod_perl SetHandler perl-script - PerlResponseHandler ModPerl::PerlRun + PerlResponseHandler ModPerl::Registry PerlOptions +ParseHeaders - Options -Indexes +ExecCGI + Options +ExecCGI </Files> </IfModule> - Options +ExecCGI - AddHandler cgi-script .pl <IfModule mod_expires.c> ExpiresActive on ExpiresDefault "now plus 0 seconds" </IfModule> </Directory> -AddType text/x-component .htc AddType text/html .Rpad-
This is the main platform that Debian's been tested on, and -www.Rpad.org is a Debian -server. Debian packages for Rpad are available at www.Rpad.org. Installing the Rpad -package does all of the installation steps described above. Under -Debian, Rpad will work with apache or apache2, and it will work with -or without mod_perl on either version of apache.
- -There's also a script that will install the Rpad html files. It is located in the -serverversion directory within the Rpad package directory. It's called -installRpadWWW.sh. This creates another Rpad directory. In -addition to copying the base html files, it sets permissions and configures -apache properly for that directory. Here's an example: -
--/usr/local/lib/R/site-library/Rpad/installRpadWWW.sh /var/www/RpadTesting --
I normally add a cron job to restart the Apache server once a day. This clears out any R processes that didn't get killed for whatever reason. I create the following as the file /etc/cron.daily/Rpad-cleanup:
@@ -166,49 +133,10 @@ rm -rf /var/www/Rpad/server/dd* +Some considerations for Windows:
--# Installing apache_1.3.33-win32-x86-no_src.msi downloaded from -# www.apache.org using CGI -# Windows 2000 -# Perl 5.8.4 installed at C:/apps/perl -# Installed Apache at C:/Program Files/Apache Group/Apache -# WWW root is at C:/Program Files/Apache Group/Apache/htdocs - -# Copied the directory basehtml directory to htdocs\Rpad -xcopy/I/S "C:\Program Files\R\rw2001\library\Rpad\basehtml" "C:\Program Files\Apache Group\Apache\htdocs\Rpad" - -# Added a mime type for .Rpad files in conf\mime.types as follows: -text/html Rpad - -#Installed Statistics-R_perl_interface: -cd C:\Program Files\R\rw2001\library\Rpad\serverversion\Statistics-R_perl_interface -perl Makefile.pl -nmake -nmake install -# you can also just copy the directory -# C:\Program Files\R\rw2001\library\Rpad\serverversion\Statistics-R_perl_interface\lib\Statistics -# to C:\apps\perl\site\lib (or wherever your perl lib's are) - -# Add the following to the conf\httpd.conf file to read .pl files as CGI: -AddHandler cgi-script .pl - -# Changed the following in the conf\httpd.conf file to enable CGI: - Options Indexes FollowSymLinks MultiViews -# to - Options Indexes FollowSymLinks MultiViews ExecCGI - -# Added the following line as the first line to the 3 perl files in -# htdocs\Rpad\server to point to perl -#!c:/apps/perl/bin/perl.exe - -# I also futzed with the permissions on these files, but I don't know -# that it was necessary. - -# Used R's png driver rather than ghostscript: in .RpadStartup.R, +# Used R's png driver rather than ghostscript: in RpadStartup.R, # uncommented the following line: # graphoptions(type="Rpng") @@ -230,78 +158,10 @@ You need to change the user for the apache service and set permissions for that user to prevent access to unwanted parts of your hard drive. Google for "apache localsystem ntfs permissions". --
Installing Rpad on an apache2 installation (cgi mode) on Windows 2000 -worked exactly the same as the Apache 1.3 installation.
- -I briefly tried Rpad with apache2/modperl under windows. In very limited -testing, it worked okay. Modperl under windows can make Apache very slow, at least to start -and stop. A server restart can take over 10 seconds on my win2k -laptop.
- -WARNING: Users (including me) have reported problems installing -Rpad on IIS. I've got a Windows 2000 machine with IIS running fine. In -another installation on XP (also using IIS v5.1), it refuses to start -R (the perl part works, it just won't spawn another process).
- -Installing Rpad on the IIS server that came with Windows 2000 -worked mainly the same as the Apache 1.3 installation. Here are some -further notes:
- --# Copied the directory basehtml directory to wwwroot\Rpad -xcopy/I/S "C:\Program Files\R\rw2001\library\Rpad\basehtml" "C:\Inetpub\wwwroot\Rpad" - -#Installed the Statistics-R_perl_interface as outlined above. - -## NOTE: This step shouldn't be needed anymore! It should figure it out right, -## but I left it in so you can try it if things don't work right. -# In C:\Inetpub\wwwroot\Rpad\server\R_process.pl, change the following -# lines from: -my $R = Statistics::Rpad->new( -# log_dir => '/var/www/Rpad/server/' . $Rpad_ID - log_dir => $dir . $Rpad_ID - ) ; -# to: -my $R = Statistics::Rpad->new( - log_dir => 'c:/Inetpub/wwwroot/Rpad/server/' . $Rpad_ID -# log_dir => $dir . $Rpad_ID - ) ; - -# In the IIS "properties" tab, change the following: -# Under Http Headers|File Types...|New Type..., entered a Content type -# of text/html for an Associated Extension of Rpad -# Under Home Directory|Configuration...|App Mappings, -# added a Extension for pl with an Executable of -# C:\apps\Perl\bin\perl5.8.4.exe %s %s - -# Used R's png driver rather than ghostscript: -# in c:/Inetpub/wwwroot/Rpad/.RpadStartup.R, -# uncommented the following line: -# -graphoptions(type="Rpng") - -# In c:/Inetpub/wwwroot/Rpad/.RpadStartup.R, uncommented -# the following lines to properly specify the location for graphs. -# -## NOTE: This step shouldn't be needed anymore! It should figure it out right, -## but I left it in so you can try it if things don't work right. -assign("RpadDir", envir = Rpad:::.RpadEnv, - gsub("c:/Inetpub/wwwroot","", getwd(), ignore.case = TRUE) ) - -I didn't know how to disable caching on the pages served from Rpad/server*. - -As with apache, you need to lock down the file permissions. Google -for IIS and IUSR. Also look for "IIS Lockdown Tool". --
Look for directories named /var/www/Rpad/server/dd??????????/ @@ -355,13 +215,17 @@
If graphics appear locally but not on remote machines, it indicates a problem with finding the URL for the graphics files. You may have to -modify the Rpad/.RpadStartup.R to explicitly tell R where to find +modify the Rpad/RpadStartup.R to explicitly tell R where to find the graphics files, like:
assign("RpadDir", envir = Rpad:::.RpadEnv, gsub("c:/Inetpub/wwwroot","", getwd(), ignore.case = TRUE) ) -
+ Rpad/HTML pages in working directory (click on the link to load the file): + + + +
+
+
+
+
+
+
++.threecolumns = function(lst) { + n = length(lst) + if (n <= 3) return(as.matrix(lst)) + ncol = 3 + nrow = ceiling(n / ncol) + lst = as.matrix(append(lst, rep("", ncol * nrow - n))) + dim(lst) = c(nrow, ncol) + lst +} +.rpadfiles = grep('\\.html$|\\.rpad$', dir(), ignore.case = TRUE, value = TRUE) +.rpadfiles = H("a", href = .rpadfiles, collapseContents = FALSE, + .rpadfiles) +.rpadfiles = .threecolumns(.rpadfiles) +HTMLon() +Html(.rpadfiles) ++ Objects in user's workspace: +
+
+
++# print(ls.str(), wid = 40, nchar.max = 20, vec.len=2) +ls() ++ Enter R code here and press + +or F9 to run it: + +
+
+
+
+The date and time: +
+
+
+
++date() ++ |
+ Help + + +Rpad documentation+Server notes + + + Rpad Demos + + +General Example+Input Examples +Dojo Test Page +Rpad Test Page + + + Links + + +Tom Short's R refcard+Matt Baggot's R refcard v2 +Liu's R refcard +Rpad homepage +R homepage + + + + + |
The date and time:
--date() --
Help
Modified: pkg/Rpad/inst/basehtml/server/R_process.pl =================================================================== --- pkg/Rpad/inst/basehtml/server/R_process.pl 2014-01-02 15:39:42 UTC (rev 3) +++ pkg/Rpad/inst/basehtml/server/R_process.pl 2014-01-04 10:15:39 UTC (rev 4) @@ -1,176 +1,198 @@ -#!/usr/bin/perl -w -#!c:/apps/perl/bin/perl.exe - -# The following line is a test script to see if it works. -# http://localhost/Rpad/server/R_process.pl?&ID=/tmp/ddNTlmHSvWZF&command=R_commands&R_commands=print('hello') - -use strict; -use warnings; - -use Statistics::R; -use Linux::Inotify2; -use File::Path qw(remove_tree); -use Time::Out qw(timeout); -use CGI qw/:standard send_http_header/; - -# chdir to temporary directory -#my $Rpad_ID = '/home/jedick/tmp/rtmp'; ## testing -my $Rpad_ID = param('ID'); -chomp($Rpad_ID); -chdir $Rpad_ID; - -#my $p_command = 'login'; ## testing -#my $p_command = 'R_commands'; ## testing -my $p_command = param('command'); -chomp $p_command ; - -my @output_value = ""; - -if ($p_command eq 'login') { - - # fork this process - my $pid = fork(); - die "Fork failed: $!" if !defined $pid; - - if ($pid == 0) { - - # do this in the child - open STDOUT, ">/dev/null"; - open STDERR, ">/dev/null"; - - # start R and load Rpad - my $R = ""; - sub startR{ - $R = Statistics::R->new( shared => 1 ); - $R->start(); - $R->run(q`require(Rpad)`); - # from ?stop: "don't stop on stop(.)" - # this way the R process behaves more like the interactive session - it isn't halted when an error occurs - # but errors still hang up the perl so we can't use it... - #$R->run(q`options(error = expression(NULL))`); - } - &startR(); - - # subroutine to clean up temporary directory - sub cleanup{ - chdir ".." or die "Failed to go to parent directory: $!"; - remove_tree($Rpad_ID); - } - - # set up inotify watch on temporary directory - my $inotify = new Linux::Inotify2 - or die "Unable to create new inotify object: $!"; - $inotify->watch("$Rpad_ID", IN_CLOSE_WRITE, sub { - my $event = shift; - my $name = $event->name; - # run the input.R when it appears - if ( $name eq "input.R" ) { - # read R command from the input file - # $R->run_from_file would be cleaner, but it's a source(), so doesn't echo like the interactive session - #my $output_value = eval { $R->run_from_file($name); }; - open(my $fh, '<', $name) or die "Could not open file '$name' $!"; - # Slurp into a scalar - my $R_commands; - { local $/ = undef; $R_commands = <$fh>; } - close $fh; - my $output_value = eval { $R->run($R_commands); }; - - # convert any errors from R into the output text - if ( $@ ) { - $output_value = "$@"; - # remove first 3 lines for a cleaner error message - $output_value =~ s/^(?:.*\n){1,3}//; - # restart R (probably should test if really did stop) - &startR(); - } - # save output to file - my $filename = "output"; - open($fh, '>', $filename) or die "Could not open file '$filename' $!"; - print $fh "$output_value\n"; - close $fh; - } - elsif ( $name eq "theend" ) { - &cleanup(); - die "watch process terminated by request"; - } - }) or die "watch creation failed: $!"; - - # put a limit of 10 minutes on our process - timeout 600 => sub { - 1 while $inotify->poll; - } ; - if ($@){ - &cleanup(); - # operation timed-out - die "watch process reached timeout limit"; - } - } - - # wait a second for R to start and to begin watch of - # input file before any R commands are sent - sleep 1; - -} - -elsif ($p_command eq 'logout') { - - # this creates a file signalling the end of Perl child process - my $filename = "theend"; - open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; - print $fh "\n"; - close $fh; - -} - -elsif ($p_command eq 'R_commands') { - - # process R commands - #my $R_commands = "print('abcxyz') \n\ndate()\n\n \n Sys.sleep(10)"; ## testing - my $R_commands = param('R_commands'); - # replace non-breaking spaces with regular spaces - $R_commands =~ s/\xA0/ /g; - - # save commands to the input file that is being watched by the child process - my $filename = "input.R"; - open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; - # split the string of commands on newlines - my @lines = split /\n/, $R_commands; - foreach my $line (@lines) { - # remove the trailing space(s), which seem to cause problems - $line =~ s/\ *$//g; - # blank lines also cause problems; remove them too - if ( $line ne "" ) { - print $fh "$line\n"; - } - } - close $fh; - - # set up inotify watch to grab output file - my $inotify = new Linux::Inotify2 - or die "Unable to create new inotify object: $!"; - $inotify->watch("$Rpad_ID", IN_CLOSE_WRITE, sub { - my $event = shift; - my $name = $event->name; - if ( $name eq "output" ) { - # read contents of output file into output_value - my $filename = "output"; - open(my $fh, '<', $filename) or die "Could not open file '$filename' $!"; - @output_value=<$fh>; - close $fh; - } - }) or die "watch creation failed: $!"; - - # interrupt the watch if it runs for more than 10 seconds. - timeout 10 => sub { - $inotify->poll; - } ; - if ($@){ - # operation timed-out - @output_value = "10 seconds passed with no output from R ... back to you!\n"; - } - -} - -CGI::initialize_globals(); -print header; -print @output_value; +#!/usr/bin/perl +#!c:/apps/perl/bin/perl.exe + +# The following line is a test script to see if it works. +# http://localhost/Rpad/server/R_process.pl?&ID=/tmp/ddNTlmHSvWZF&command=R_commands&R_commands=print('hello') + +use strict; +use warnings; + +use Statistics::R; +use Linux::Inotify2; +use File::Path qw(remove_tree); +use CGI qw/:standard send_http_header/; +use Time::HiRes qw(time sleep); + +CGI::initialize_globals(); + +# get name of temporary directory +#my $Rpad_ID = '/home/jedick/tmp/rtmp'; ## testing +my $Rpad_ID = param('ID'); +chomp($Rpad_ID); + +#my $p_command = 'login'; ## testing +#my $p_command = 'R_commands'; ## testing +my $p_command = param('command'); +chomp $p_command ; + +my @output_value = ""; + +if ($p_command eq 'login') { + + # fork this process + my $pid = fork(); + die "Fork failed: $!" if !defined $pid; + + if ($pid == 0) { + + # do this in the child + open STDOUT, ">/dev/null"; + open STDERR, ">/dev/null"; + + # start R and load Rpad + my $R = ""; + sub startR{ + chdir $Rpad_ID; + $R = Statistics::R->new( shared => 1 ); + $R->start(); + $R->run(q`require(Rpad)`); + # from ?stop: "don't stop on stop(.)" + # this way the R process behaves more like the interactive session - it isn't halted when an error occurs + # but errors still hang up the perl so we can't use it... + #$R->run(q`options(error = expression(NULL))`); + chdir ".." or die "Failed to go to parent directory: $!"; + } + &startR(); + + # subroutine to clean up temporary directory + sub cleanup{ + remove_tree($Rpad_ID); + } + + # set up inotify watch on temporary directory + my $inotify = new Linux::Inotify2 + or die "Unable to create new inotify object: $!"; + $inotify->watch($Rpad_ID, IN_CLOSE_WRITE, sub { + my $event = shift; + my $name = $event->name; + my $fullname = $event->fullname; + # run the input.R when it appears + if ( $name eq "input.R" ) { + # read R command from the input file + # $R->run_from_file would be cleaner, but it's a source(), so doesn't echo like the interactive session + #my $output_value = eval { $R->run_from_file($name); }; + open(my $fh, '<', $fullname) or die "Could not open file '$fullname' $!"; + # Slurp into a scalar + my $R_commands; + { local $/ = undef; $R_commands = <$fh>; } + close $fh; + my $output_value = eval { $R->run($R_commands); }; + + # convert any errors from R into the output text + if ( $@ ) { + $output_value = "$@"; + # remove first 3 lines for a cleaner error message + $output_value =~ s/^(?:.*\n){1,3}//; + # restart R (probably should test if really did stop) + &startR(); + } + # save output to file + my $filename = $Rpad_ID . "/output"; + open($fh, '>', $filename) or die "Could not open file '$filename' $!"; + print $fh "$output_value\n"; + close $fh; + } + elsif ( $name eq "theend" ) { + &cleanup(); + die "watch process terminated by request"; + } + }) or die "watch creation failed: $!"; + + # time out after 5 minutes + # Sys::SigAction or Time::Out work when script is run from commandline, but don't timeout under CGI + # instead, turn off blocking on inotify and use Time::HiRes + # http://www.perlmonks.org/?node_id=859287 + $inotify->blocking(0); + my $timelimit = 20; + my $end = time() + $timelimit; + while( time() < $end ) { + $inotify->poll; + sleep 0.1; + } + &cleanup(); + die "watch process reached timeout limit"; + + } + + # wait a second for R to start and to begin watch of + # input file before any R commands are sent + sleep 1; + +} + +elsif ($p_command eq 'logout') { + + # this creates a file signalling the end of Perl child process + my $filename = "theend"; + open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; + print $fh "\n"; + close $fh; + +} + +elsif ($p_command eq 'R_commands') { + + # process R commands + #my $R_commands = "print('abcxyz') \n\ndate()\n\n \n Sys.sleep(10)"; ## testing + my $R_commands = param('R_commands'); + # replace non-breaking spaces with regular spaces + $R_commands =~ s/\xA0/ /g; + + # save commands to the input file that is being watched by the child process + my $filename = $Rpad_ID . "/input.R"; + sub not_writable{ + @output_value="Input file not writable; timeout may have occurred.\nTry starting a new session by reloading the page.\n"; + print header; + print @output_value; + exit 1; + } + open(my $fh, '>', $filename) or ¬_writable(); + # split the string of commands on newlines + my @lines = split /\n/, $R_commands; + foreach my $line (@lines) { + # remove the trailing space(s), which seem to cause problems + $line =~ s/\ *$//g; + # blank lines also cause problems; remove them too + if ( $line ne "" ) { + print $fh "$line\n"; + } + } + close $fh; + + # set up inotify watch to grab output file or create message if tmpdir (Rpad_ID) was deleted while running R command + my $inotify = new Linux::Inotify2 + or die "Unable to create new inotify object: $!"; + # set up a watcher on an output file + $inotify->watch($Rpad_ID, IN_DELETE_SELF | IN_CLOSE_WRITE, sub { + my $event = shift; + my $name = $event->name; + my $fullname = $event->fullname; + if ( $event->IN_DELETE_SELF ) { + # TODO: test this, do we ever get here? + @output_value="Temporary directory was deleted while running R command; timeout may have occurred.\nTry starting a new session by reloading the page.\n"; + } + elsif ( $name eq "output" ) { + # read contents of output file into output_value + open(my $fh, '<', $fullname) or die "Could not open file '$fullname' $!"; + @output_value=<$fh>; + close $fh; + } + }) or die "watch creation failed: $!"; + + $inotify->poll; + +# this slows down response time considerably, so for now running of R commands is blocking +# # return a default message if the R process doesn't finish within 10 seconds +# @output_value = "10 seconds passed with no output from R ... back to you!\n"; +# $inotify->blocking(0); +# my $timelimit = 10; +# my $end = time() + $timelimit; +# while( time() < $end ) { +# $inotify->poll; +# sleep 0.01; +# } + +} + +print header; +print @output_value; Modified: pkg/Rpad/man/Rpad-package.Rd =================================================================== --- pkg/Rpad/man/Rpad-package.Rd 2014-01-02 15:39:42 UTC (rev 3) +++ pkg/Rpad/man/Rpad-package.Rd 2014-01-04 10:15:39 UTC (rev 4) @@ -1,6 +1,5 @@ \docType{package} \name{Rpad-package} -\alias{Rpad} \alias{Rpad-package} \title{Rpad} \description{ @@ -9,8 +8,8 @@ \details{ This manual describes the R functions that support the web interface. Other documentation is in the \dQuote{basehtml} directory. -The example below will launch a local web browser where you can read the documentation and view the demos. -You can continue to interact with the R console when the local HTTP server starts. +The example below will launch a browser where you can read that documentation and view the demos. +You can continue to use the R console after the local HTTP server starts. } \examples{ \dontrun{ From noreply at r-forge.r-project.org Sun Jan 5 15:58:57 2014 From: noreply at r-forge.r-project.org (noreply at r-forge.r-project.org) Date: Sun, 5 Jan 2014 15:58:57 +0100 (CET) Subject: [Rpad-commits] r5 - in pkg/Rpad: . R inst inst/basehtml inst/basehtml/server man Message-ID: <20140105145857.EE124186B07@r-forge.r-project.org> Author: jedick Date: 2014-01-05 15:58:57 +0100 (Sun, 05 Jan 2014) New Revision: 5 Added: pkg/Rpad/inst/basehtml/DojoEvents.Rpad pkg/Rpad/inst/basehtml/RpadWidgets.Rpad Removed: pkg/Rpad/inst/basehtml/RpadTest.Rpad Modified: pkg/Rpad/DESCRIPTION pkg/Rpad/NAMESPACE pkg/Rpad/R/Graphing.R pkg/Rpad/R/HtmlTree.R pkg/Rpad/R/LocalVersion.R pkg/Rpad/R/Rpad-internal.R pkg/Rpad/R/Util.R pkg/Rpad/inst/NEWS pkg/Rpad/inst/basehtml/BasicDocumentation.html pkg/Rpad/inst/basehtml/DojoTest.html pkg/Rpad/inst/basehtml/Example1.Rpad pkg/Rpad/inst/basehtml/InputExamples.Rpad pkg/Rpad/inst/basehtml/Rpad_body.js pkg/Rpad/inst/basehtml/index.html pkg/Rpad/inst/basehtml/server/R_process.pl pkg/Rpad/man/Rpad-internal.Rd pkg/Rpad/man/RpadGraphing.Rd pkg/Rpad/man/RpadHTML.Rd pkg/Rpad/man/RpadLocalServer.Rd pkg/Rpad/man/RpadUtil.Rd Log: consolidate graphing functions; add Dojo events demo Modified: pkg/Rpad/DESCRIPTION =================================================================== --- pkg/Rpad/DESCRIPTION 2014-01-04 10:15:39 UTC (rev 4) +++ pkg/Rpad/DESCRIPTION 2014-01-05 14:58:57 UTC (rev 5) @@ -1,6 +1,6 @@ Package: Rpad Title: Workbook-style, web-based interface to R -Version: 1.3.99.2 +Version: 1.3.99.3 Author: Tom Short (EPRI), Philippe Grosjean (UMH EcoNum), Jeffrey Dick Description: A workbook-style user interface to R through a web browser. Provides convenient interaction with an R process Modified: pkg/Rpad/NAMESPACE =================================================================== --- pkg/Rpad/NAMESPACE 2014-01-04 10:15:39 UTC (rev 4) +++ pkg/Rpad/NAMESPACE 2014-01-05 14:58:57 UTC (rev 5) @@ -5,7 +5,6 @@ Rpad, startRpadServer, stopRpadServer, - ROutputFormat, Html, H, HtmlTree, @@ -13,11 +12,6 @@ BR, HTMLon, HTMLoff, - HTMLh1, - HTMLh2, - HTMLh3, - HTMLh4, - HTMLh5, HTMLargs, HTMLtag, HTMLetag, @@ -31,12 +25,12 @@ graphoptions, newgraph, showgraph, - RpadPlotName, RpadURL, RpadBaseURL, RpadBaseFile, RpadIsLocal, - json + json, + RpadEnv ) S3method(json, default) Modified: pkg/Rpad/R/Graphing.R =================================================================== --- pkg/Rpad/R/Graphing.R 2014-01-04 10:15:39 UTC (rev 4) +++ pkg/Rpad/R/Graphing.R 2014-01-05 14:58:57 UTC (rev 5) @@ -1,198 +1,121 @@ # Rpad graphing functions -"graphoptions" <- function (..., reset = FALSE, override.check = TRUE) { - # set various Rpad graph options - # modified based on code from ps.options - l... <- length(new <- list(...)) - old <- check.options(new = new, envir = .RpadEnv, name.opt = ".RpadGraphOptions", - reset = as.logical(reset), assign.opt = l... > 0, override.check = override.check) - if (reset || l... > 0) - invisible(old) - else old -} +###################### +# internal functions # +###################### "newRpadPlotName" <- function(name = "") { # Create a new Rpad plot name # Updates the plot counter and name if (name == "") { - Counter <- get("Rpad.plot.counter", envir = .RpadEnv) - assign("Rpad.plot.counter", Counter + 1, envir = .RpadEnv) - name <- paste("Rpad_plot", Counter, sep="") + Counter <- get("plot.counter", envir = .RpadEnv) + assign("plot.counter", Counter + 1, envir = .RpadEnv) + name <- sprintf("Rpad_plot%03d", Counter) } - assign("Rpad.plot.name", name, envir = .RpadEnv) + assign("plot.name", name, envir = .RpadEnv) name } -"RpadPlotName" <- function() - get("Rpad.plot.name", envir = .RpadEnv) +GScmd <- function(name, invisible=FALSE, infile=paste(name, ".eps", sep = "")) { + # generate a ghostscript command + # set invisible=TRUE for windows + # set infile="" for output piped to command (see ?postscript) + GO <- graphoptions() + gsexe <- Sys.getenv("R_GSCMD") + if (is.null(gsexe) || nchar(gsexe) == 0) + gsexe <- ifelse(.Platform$OS.type == "windows", "gswin32c.exe", "gs") + if(invisible) gshelp <- system(paste(gsexe, "-help"), intern = TRUE, invisible = TRUE) + else gshelp <- system(paste(gsexe, "-help"), intern = TRUE) + st <- grep("^Available", gshelp) + en <- grep("^Search", gshelp) + gsdevs <- gshelp[(st + 1):(en - 1)] + devs <- c(strsplit(gsdevs, " "), recursive = TRUE) + if (match(GO$type, devs, 0) == 0) + stop(paste(paste("Device ", GO$type, "is not available"), + "Available devices are", paste(gsdevs, collapse = "\n"), + sep = "\n")) + cmd <- paste(gsexe, " -dNOPAUSE -dBATCH -q -sDEVICE=", GO$type, + " -r", GO$res, " -g", ceiling(GO$res * GO$width), "x", + ceiling(GO$res * GO$height), " -sOutputFile=", name, + ".", GO$extension, " ", infile, sep = "") +} - +"newDevice" <- function(name) { + # Open a new device. + # If it's an R graphics device, initiate it. + # If it's a ghostscript-based device, set up the ghostscript handling. + name <- newRpadPlotName(name) + GO <- graphoptions() + if (GO$type == "Rpng") { + # for builtin png support + png(filename = paste(name, ".png", sep=""), width = GO$width*GO$res, height = GO$height*GO$res) + } else if (GO$type == "pngalpha") { + # for a ghostscript device using bitmap + if (.Platform$OS.type == "windows") { + cmd <- NULL + } else { + cmd <- GScmd(name, infile="") + } + postscript(file = paste(name, ".eps", sep=""), width = GO$width, height = GO$height, + pointsize = GO$pointsize, + paper = "special", horizontal = FALSE, print.it = !is.null(cmd), + command = cmd) + } +} "closeCurrentDevice" <- function() { # Closes the current device and if the current device is postscript, # process the output with ghostscript to generate the desired output. - if (exists("RpadPlotParams", envir = .RpadEnv)) - p <- get("RpadPlotParams", envir = .RpadEnv) - else - return() - dev.set(p$dev) if (.Device == "postscript") { dev.off() if (.Platform$OS.type == "windows") { - gsexe <- Sys.getenv("R_GSCMD") - if (is.null(gsexe) || nchar(gsexe) == 0) - gsexe <- ifelse(.Platform$OS.type == "windows", "gswin32c.exe", "gs") - - gshelp <- system(paste(gsexe, "-help"), intern = TRUE, invisible = TRUE) - st <- grep("^Available", gshelp) - en <- grep("^Search", gshelp) - gsdevs <- gshelp[(st + 1):(en - 1)] - devs <- c(strsplit(gsdevs, " "), recursive = TRUE) - if (match(p$type, devs, 0) == 0) - stop(paste(paste("Device ", p$type, "is not available"), - "Available devices are", paste(gsdevs, collapse = "\n"), - sep = "\n")) - cmd <- paste(gsexe, " -dNOPAUSE -dBATCH -q -sDEVICE=", p$type, - " -r", p$res, " -g", ceiling(p$res * p$width), "x", - ceiling(p$res * p$height), " -sOutputFile=", p$name, - "-%03d.", p$extension, " ", p$name, ".eps", sep = "") + cmd <- GScmd(get("plot.name", envir = .RpadEnv), invisible=TRUE) system(cmd, intern = TRUE, invisible = TRUE) } - for (fun in getHook("closeRpadDevice")) try(fun()) } else if (.Device != "null device") { dev.off() - for (fun in getHook("closeRpadDevice")) try(fun()) } - assign("RpadPlotParams", NULL, envir = .RpadEnv) } -"newDevice" <- function(name, extension, type, res, width, height, deviceUsesPixels, pointsize, ...) { - # Open a new device. If it's a ghostscript-based device, set up the - # ghostscript handling. - # If it's an R graphics device, initiate it. - name <- newRpadPlotName(name) - assign("Rpad.plot.type", type, envir = .RpadEnv) - if (is.character(type) && type == "Rpng") { # for builtin png support - unlink(grep(paste(name,".*\\.png",sep=""), dir(), value=T)) - png(filename = paste(name,"-%03d.png",sep=""), width = width*res, height = height*res) - assign("RpadPlotParams", list(dev=dev.cur(), extension="png"), envir = .RpadEnv) - } else if (is.function(type)) { - # for an arbitrary R graphics device - unlink(grep(paste(name,".*\\.", extension, sep=""), dir(), value=T)) - funargs <- formals(type) - callargs <- list(file = paste(name, "-%03d.", extension, sep="")) - if (deviceUsesPixels) { - height <- height * res - width <- width * res - } - extraargs <- c(list(res = res, width = width, height = height, pointsize = pointsize), - list(...)) - if ("..." %in% names(funargs)) { - # the device function has a ..., so we (probably) can pass everything - callargs <- c(callargs, extraargs) - } else { - # remove arguments not used by this device function - callargs <- c(callargs, extraargs[intersect(names(extraargs), names(funargs))]) - } - do.call("type", callargs) - assign("RpadPlotParams", list(dev=dev.cur(), extension=extension), envir = .RpadEnv) - } else { - # for a ghostscript device using bitmap - unlink(grep(paste(name,".*\\.", extension,sep=""), dir(), value=T)) - if (.Platform$OS.type == "windows") { - cmd <- NULL - } else { - gsexe <- Sys.getenv("R_GSCMD") - if (is.null(gsexe) || nchar(gsexe) == 0) - gsexe <- ifelse(.Platform$OS.type == "windows", "gswin32c.exe", "gs") - gshelp <- system(paste(gsexe, "-help"), intern = TRUE) - st <- grep("^Available", gshelp) - en <- grep("^Search", gshelp) - gsdevs <- gshelp[(st + 1):(en - 1)] - devs <- c(strsplit(gsdevs, " "), recursive = TRUE) - if (match(type, devs, 0) == 0) - stop(paste(paste("Device ", type, "is not available"), - "Available devices are", paste(gsdevs, collapse = "\n"), - sep = "\n")) - cmd <- paste(gsexe, " -dNOPAUSE -dBATCH -q -sDEVICE=", type, - " -r", res, " -g", ceiling(res * width), "x", ceiling(res * - height), " -sOutputFile=", name, "-%03d.", extension, " ", sep = "") - } - postscript(file = paste(name,".eps",sep=""), width = width, height = height, - pointsize = pointsize, - paper = "special", horizontal = FALSE, print.it = !is.null(cmd), - command = cmd, ...) - assign("RpadPlotParams", - list(dev=dev.cur(), name=name, type=type, width=width, - height=height, res=res, extension=extension), envir = .RpadEnv) - } -} -"newgraph" <- function(name = "", extension = graphoptions()$extension, - type = graphoptions()$type, res = graphoptions()$res, - width = graphoptions()$width, height = graphoptions()$height, - deviceUsesPixels = graphoptions()$deviceUsesPixels, - pointsize = graphoptions()$pointsize, sublines = graphoptions()$sublines, - toplines = graphoptions()$toplines, ratio = graphoptions()$ratio, - leftlines = graphoptions()$leftlines, lwd = graphoptions()$lwd, ...) { -# Start a new Rpad graph. -# uses code from bitmap and from Frank Harrell's Hmisc routine setps - - if (width == 0 & height == 0) - width <- 3.5 - if (width > 0 & height == 0) - height <- width/ratio - if (width == 0 & height > 0) - width <- height * ratio - closeCurrentDevice() - newDevice(name, extension, type, res, width, height, deviceUsesPixels, pointsize, ...) +########################## +# user-visible functions # +########################## - par(lwd = lwd, mgp = c(2.5, 0.6, 0), - mar = c(3 + sublines + 0.25 * (sublines > 0) + - 0.5, 3 + leftlines + 0.5, toplines+.4, 1) + 0.1, - cex.main=1,font.main=1,las=1) - #require(lattice) +"graphoptions" <- function (..., reset = FALSE, override.check = TRUE) { + # set various Rpad graph options + # modified based on code from ps.options + l... <- length(new <- list(...)) + old <- check.options(new = new, envir = .RpadEnv, name.opt = "GraphOptions", + reset = as.logical(reset), assign.opt = l... > 0, override.check = override.check) + if (reset || l... > 0) + invisible(old) + else old +} -# lattice::lset(lattice::canonical.theme("postscript", color = TRUE)) - -# if (exists('xyplot')) { -# trellis.device(col=T) -# lset(list(axis.line=list(col="gray50"),axis.text=list(col="black"), -# strip.background=list(col="white"),strip.shingle=list(col="gray70"))) -# } - for (fun in getHook("newgraph")) try(fun()) +"newgraph" <- function(name = "") { + # Start a new Rpad graph. + closeCurrentDevice() + newDevice(name) + GO <- graphoptions() + par(lwd = GO$lwd, mgp = c(2.5, 0.6, 0), + mar = c(3 + GO$sublines + 0.25 * (GO$sublines > 0) + + 0.5, 3 + GO$leftlines + 0.5, GO$toplines+.4, 1) + 0.1, + cex.main=1, font.main=1, las=1) invisible() } # Start a new Rpad graph, and show the existing graph(s). -"showgraph" <- function(name = RpadPlotName(), link = FALSE, ...) { +"showgraph" <- function(name = get("plot.name", envir = .RpadEnv), link = FALSE, ...) { name newgraph() - for (n in dir(pattern = paste(name, ".*", get("RpadPlotParams", envir = .RpadEnv)$extension, sep=""))) + for (n in dir(pattern = paste(name, graphoptions()$extension, sep="."))) print(HTMLimg(n)) - if (link && # show a link to an EPS file if specified and if using the ghostscript graphics - get("Rpad.plot.type", envir = .RpadEnv) != "Rpng" && - !is.function(get("Rpad.plot.type", envir = .RpadEnv))) + # show a link to an EPS file if specified and if using the ghostscript graphics + if (link && graphoptions()$type == "pngalpha") cat("", "[EPS]", "\n", sep="") invisible() } - - -# Here's an example hook that you could use to add an EPS preview to eps files (requires epstool) - -#eps.add.preview <- function(fname) system(paste("epstool -n1 -b -t6p -zbmp256 -r200 -g\"gswin32c\" -o",fname,".eps ",fname,".eps",sep=""),show.output.on.console = TRUE) -# -#setHook("closeRpadDevice", function() { # add a tiff preview to an eps file -# name = RpadPlotName() -# if (length(dir(pattern=paste(name,".eps",sep=""))) == 1) -# eps.add.preview(name) -#}) - -### This will set the default graphics option to the GDD device: -# library(GDD) -# graphoptions(type = GDD) -### This is how you could change the pointsize on a GDD device: -# newgraph(ps = 10) # the default is 12 Modified: pkg/Rpad/R/HtmlTree.R =================================================================== --- pkg/Rpad/R/HtmlTree.R 2014-01-04 10:15:39 UTC (rev 4) +++ pkg/Rpad/R/HtmlTree.R 2014-01-05 14:58:57 UTC (rev 5) @@ -1,10 +1,3 @@ -# -# -# -# -# -# - "Html" <- function(x,...) { UseMethod("Html") } @@ -118,23 +111,6 @@ } -# broken: -#"HtmlTree.list" <- "Html.list" <- function (x, first = TRUE, ...) { -# res = rep(H("dum"), length = 2*length(x)) -# res[seq(1, 2*length(x), by = 2)] = H(NULL, names(x), collapseContents = FALSE) -# res[seq(2, 2*length(x), by = 2)] = sapply(x, FUN = function(x) -# H("ul", -# Html(x, first = FALSE))) -# if (first) # IE needs contenteditable off -# H("div", contentEditable='false', -# H("ul", -# H("li", -# H(NULL, res)))) -# else -# H("li", -# H(NULL, res)) -#} - "HTMLbutton" <- function(label = "Calculate", js = "rpad.calculatePage()", ...) # Other useful js parameters: # js = "rpad.calculateNext(this)" # calculate the next Rpad block @@ -193,7 +169,7 @@ H("a", href = url, ..., text)) -"HTMLimg" <- function(filename = RpadPlotName(), ...) +"HTMLimg" <- function(filename = get("plot.name", envir = .RpadEnv), ...) H("img", src = RpadURL(filename), ...) "HTMLembed" <- function(filename, width = 600, height = 600, ...) @@ -223,31 +199,12 @@ "BR" = function() H("br", standaloneTag = TRUE) #Debugging hint: the dojo.js that is packaged with Rpad is an optimized (compressed) +version. To debug errors in the Javascript code using e.g. Firebug, it is easier +to use a non-compressed dojo.js. This can be built by setting layerOptimize: false +in app.profile.js and then building Dojo as outlined in the README (you will need +the complete Dojo source distribution). Then, place the un-optimized dojo.js +in your working directory and start Rpad; this new dojo.js will take precedence +over the one installed with the package.
+Here is an example of a complete Rpad HTML file:
Added: pkg/Rpad/inst/basehtml/DojoEvents.Rpad =================================================================== --- pkg/Rpad/inst/basehtml/DojoEvents.Rpad (rev 0) +++ pkg/Rpad/inst/basehtml/DojoEvents.Rpad 2014-01-05 14:58:57 UTC (rev 5) @@ -0,0 +1,115 @@ + + + + + +(Modified from testDojoEvents.Rpad of Rpad 1.3.0)
+ +Normally, Rpad runs calculations on a page from top to bottom. With +Dojo's event system, you can change that and run things in different orders +or with different dependencies or to make interactions more dynamic. +The following example updates the top Rpad input block whenever you change the select +box created by the third Rpad input block.
+ + ++# this block (id=rpad3) runs after the Rpad section below is finished +p = state.x77[sname, "Population"] +a = state.area[state.name==sname] +cat("population density of", sname, "is", 1000*p/a, "persons/sq.mile") ++
+# this block (id=rpad2) runs when the select box is updated +HTMLon() +H("h3", sname) +Html(state.x77[sname, , drop=FALSE]) +n <- n + 1 +pop <- pop + state.x77[sname, "Population"] +BR() +cat("in the", n, "states selected so far, the total population is", pop, "thousand people") ++
+# this block (id=rpad1) runs initially +pop <- n <- 0 +data(state) +cat("Pick a state:") +HTMLon() +HTMLselect("sname", state.name, id="sNameSelect") ++
Dojo Javascript code to tie the GUI together (normally, you'd hide this code):
+ + ++require(["dojo/parser", "dojo/on", "dojo/dom", "dijit/registry", "dojo/aspect", "dojo/domReady!"], +function(parser, on, dom, registry, aspect){ + + // parsing the nodes is needed when using declarative syntax + // http://dojotoolkit.org/documentation/tutorials/1.8/declarative/ + parser.parse(); + + // to make the select box automatically update the R variable + // we watch for a change in the widget holding the select box + var myWidget1 = registry.byId("rpad1"); + on(myWidget1, "change", function(evt){ + + var mySelect = dom.byId("sNameSelect"); + // here, set 'doit' (second argument) to true to force calculation of + // a node with rpadRun="init" (which otherwise is calculated only on page load). + rpad.calculateNode(mySelect, true) + + // when the select is done updating (has a response from R), calculate "rpad2" + var handle = aspect.after(mySelect, "onReceive", function(response){ + // to run just once, we remove this handle, otherwise the 'n' increments indefinitely + handle.remove(); + //rpad.calculateNode("rpad2", true) + var myWidget2 = registry.byId("rpad2"); + myWidget2.calculate(); + }); + + // when "rpad2" is done, calculate "rpad3" + var myWidget2 = registry.byId("rpad2"); + on(myWidget2, "receive", function(evt) { + var myWidget3 = registry.byId("rpad3"); + // set a 0.5s timeout to visually demonstrate the order of calculation + setTimeout(function() { + myWidget3.calculate(); + }, 500); + }); + + }); + +}); ++