Skip to content

Commit 7bbd2b9

Browse files
committed
Merge branch 'master' of github.com:fhinkel/InteractiveShell
2 parents 5fbd629 + 0a30f13 commit 7bbd2b9

7 files changed

Lines changed: 122 additions & 95 deletions

File tree

Readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
# Interactive Shell - a Web App for Macaulay2
44

5+
## Quickstart
6+
7+
Run the following commands in a terminal (`vagrant` might take a while):
8+
```bash
9+
git clone https://github.com/fhinkel/InteractiveShell.git
10+
cd InteractiveShell/setups/basic
11+
vagrant up
12+
```
13+
Point your broser to [localhost:8002](http://localhost:8002).
14+
515
## Purpose
616

717
With Interactive Shell you can build a web app for interactive command-line tools.

manuscript/jsag.tex

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ \section{Introduction}
127127

128128
We considered off the shelf solutions, such as the Sage
129129
notebook~\cite{sagenotebook}, but we wanted a more
130-
lightweight solution: one that does not require users to create
130+
lightweight solution, in particular one that does not require users to create
131131
new accounts at a web site.
132132

133133
\trym2 runs in modern browsers, including Chrome, Firefox, Safari, and Edge, both on mobile devices and desktop
@@ -238,35 +238,86 @@ \subsection{Features}
238238

239239
\section{Tutorials}
240240

241-
You can create your own tutorials for the web version. If you teach a course,
242-
email your tutorial to your students. They can include your tutorial in their web app by clicking
243-
{\it Load Tutorial} on the website.
244-
If you want to share a tutorial with the community, we would
245-
be happy to include them on the website!
246-
247-
You can use the \M2 package {\it DocConverter}.
248-
It converts a file from {\it SimpleDoc} to the tutorial specific HTML. Please see the
249-
{\it DocConverter} package for instructions and examples.
250-
251-
241+
The purpose of the mathematical tutorials in \trym2 is to make abstract
242+
mathematical concepts more concrete as well as to provide a playground for users
243+
and students to experiment and explore the mathematics.
244+
245+
The tutorials are interactive, \M2 examples in a tutorial can be run
246+
by clicking or pressing on the highlighted code. The text of the
247+
tutorial includes mathematics, using the mathjax tex library for
248+
browsers. Users can easily modify this \M2 code in the Editor, in
249+
order to work examples and exercises, or to investigate further the
250+
mathematical concepts taught in the tutorial.
251+
252+
\trym2 includes several tutorials describing basic \M2 usage and
253+
mathematics around Gr\"obner bases and polynomial algebra. These
254+
tutorials include content written by the authors and by David
255+
Eisenbud.
256+
257+
Additional tutorials can be used in \trym2 by simply uploading them in the
258+
{\it Load your own tutorial} section.
259+
260+
\subsection{Authoring a tutorial}
261+
262+
The format of tutorials for \trym2 is the simple markdown format, used
263+
on many websites, such as github. The title line begins with a ``\#''
264+
and contains the title (and possibly author) of the tutorial. Each lesson
265+
in the tutorial is marked by two ``\#''s, and each piece of \M2 code is enclosed in triple
266+
backticks ``` (these should be on their own line). The text itself
267+
can contain latex math, as well as html markup. Blank lines separate
268+
paragraphs. A tutorial template file is available for download in the
269+
{\it Load your own tutorial} section of \trym2, see
270+
Figure~\ref{fig:markdown}.
271+
272+
Instructors or users who wish to share their tutorials with their
273+
students or others should distribute their tutorials to them, e.g. via
274+
email, a course website, dropbox, google drive, etc. Each
275+
user then uploads the tutorial in their own \trym2. Note that an
276+
uploaded tuorial is only available to that user, it is not made
277+
publically available. We encourage interested authors to share their
278+
tutorials at the \trym2 google group (\cite{trym2:googlegroup}). This
279+
is also an excellent place to ask questions and get help about writing
280+
tutorials.
281+
282+
Existing \M2 documentation in simpledoc format can be converted into
283+
tutorials via the \M2 package {\tt TryM2Tutorials}. This is how several of
284+
the distributed tutorials were generated.
285+
286+
We are collaborating with several mathematicians to develop more
287+
tutorials. We will keep a curated collection of tutorials on various
288+
mathematical topics at the \trym2 google group (\cite{trym2:googlegroup}).
289+
252290
\section{Internal structure}
253291
254-
We choose to implement the server in Node.js
255-
because of Node.js's event-driven, non-blocking I/O model~\cite{nodejs}.
256-
The Node.js server functions as a bridge between \M2 instances and end users.
257-
258-
For every user we start a new \M2 process and
259-
provide them with the underlying Linux system in a separate virtual environment.
260-
This allows advanced users to
261-
interact with the file system or run shell commands by using \M2's {\tt get}
292+
The front end of \trym2 is written in TypeScript, and uses Material Design Lite
293+
\cite{MDL} for user interface elements. The server back end is
294+
implemented in Node.js. The Node.js server functions as a bridge
295+
between \M2 instances and users. For every user, the server starts
296+
a new \M2 process in a separate and sandboxed linux virtual environment.
297+
298+
Technically, this is achieved by using Docker
299+
containers~\cite{docker}. Docker implements a high-level API to
300+
provide lightweight containers that run processes in isolation. The
301+
server starts a new Docker container running \M2 for every user. The
302+
Node.js server communicates with Docker containers via {\it ssh}. This
303+
allows containers to run on independent machines, so in the future
304+
this will allow the configuration of systems which can scale with
305+
demand.
306+
307+
This architecture provides a sandboxed and secure linux environment
308+
for every \trym2 user. For instance, users can interact with the
309+
sandboxed file system and run shell commands via \M2's {\tt get}
262310
command:
263311
264-
\begin{verbatim}
312+
{\tiny\begin{verbatim}
265313
i1 : -- get information on the underlying
266314
-- operating system
267315
get "!uname -mrs"
268-
o1 = Linux 3.13.0-49-generic x86_64
316+
o1 = Linux 4.4.0-81-generic x86_64
317+
\end{verbatim}
318+
}
269319
320+
{\tiny\begin{verbatim}
270321
i2 : -- write to a file
271322
"results.txt" << "Hello!" << close
272323
o2 = results.txt
@@ -280,39 +331,28 @@ \section{Internal structure}
280331
i4 : -- obtain the file
281332
get "!open results.txt"
282333
\end{verbatim}
334+
}
283335
284-
Technically, this is achieved by using Docker containers~\cite{docker}. Docker implements
285-
a high-level API to provide lightweight containers that run processes in isolation.
286-
We start a new Docker container running \M2 for every user. The Node.js
287-
server communicates with Docker containers via {\it ssh}. This allows us to easily
288-
scale the application as demand grows.
289336
290337
To ease the setup process we provide a virtual machine that contains both the Node.js server
291338
and Docker. This virtual machine is configured using {\tt vagrant}, a tool to create and
292339
configure reproducible and portable development environments~\cite{vagrant}.
293340
294341
\section{Conclusion}
295342
296-
By providing \M2 as a web application, we hope to lower the
297-
entry barrier for new users, therefore increasing the number
343+
\trym2 lowers the entry barrier for new users of \M2, therefore increasing the number
298344
of users and fostering research in computational algebraic geometry and commutative algebra.
299345
300-
301-
We are collaborating with several mathematicians to develop more tutorials.
302-
We plan to substantially increase the number of tutorials in the tutorial database over the next semester.
303-
304-
305-
We envision some form of session sharing which allows to use the web app as a tool for collaborative research.
306-
307-
308-
The application was designed with \M2 in mind, but
309-
the entire structure will work for other command line programs such as Singular~\cite{singular},
310-
and GAP~\cite{GAP4}. A similar web application for Singular is work in progress.
346+
For all users, \trym2 is a useful way to use \M2 on shared or mobile
347+
devices where it is difficult or impossible to install software. For
348+
some, the user interface of \trym2 is a more natural way to interact with \M2.
311349
312350
\section{Acknowledgments}
313351
314-
We would like to thank Charles Boyd, Dan Grayson, Greg Smith, and Benjamin Lorenz for
352+
We would like to thank Dan Grayson, Greg Smith, and Benjamin Lorenz for
315353
fruitful discussions on system security and on user interface design.
354+
We would like to thank David Eisenbud for writing his \M2 tutorials.
355+
316356
317357
\bibliographystyle{plain}
318358
\bibliography{references}

package.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,26 @@
2020
"node": ">=8.0.0"
2121
},
2222
"dependencies": {
23-
"@types/express": "^4.0.36",
23+
"@types/express": "4.0.36",
2424
"@types/jquery": "3.2.4",
2525
"@types/mathjax": "0.0.31",
2626
"@types/mocha": "2.2.41",
2727
"@types/node": "8.0.0",
2828
"@types/socket.io": "1.4.29",
2929
"@types/socket.io-client": "1.4.29",
3030
"@types/ssh2": "0.5.35",
31-
"D": "0.0.1",
32-
"async": "2.4.1",
3331
"chai": "2.2.0",
34-
"cookie": "^0.3.1",
32+
"cookie": "0.3.1",
3533
"create-download-link": "1.1.0",
3634
"dialog-polyfill": "0.4.3",
3735
"eslint": "4.0.0",
3836
"eslint-config-google": "0.5.0",
39-
"exports-loader": "0.6.3",
4037
"express": "4.13.4",
4138
"express-winston": "0.2.9",
4239
"forever": "0.14.1",
4340
"get-selected-text": "1.0.2",
4441
"http-auth": "2.3.1",
45-
"imports-loader": "0.6.5",
4642
"jquery": "2.2.3",
47-
"jsdom": "4.3.0",
4843
"mocha": "2.1.0",
4944
"rewire": "2.5.1",
5045
"scroll-down": "2.0.0",
@@ -56,7 +51,6 @@
5651
"socket.io-client": "2.0.3",
5752
"socketio-file-upload": "0.4.6",
5853
"ssh2": "0.5.5",
59-
"supertest": "0.15.0",
6054
"ts-node": "3.0.6",
6155
"tslint": "5.4.3",
6256
"typescript": "2.3.4",

src/lib/tutorialReader.ts

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,57 +18,41 @@ function moveWelcomeTutorialToBeginning(
1818
type GetListFunction = (request: any, response: { writeHead: any; end: any; }) => void;
1919

2020
function tutorialReader(prefix: string, fs): GetListFunction {
21-
const async = require("async");
22-
23-
const prefixedFsReaddir = function(path: string, next): void {
24-
const totalPath: string = prefix + path;
25-
fs.readdir(totalPath, function(err, files) {
26-
const tutorials: Tutorials = files.map(function(filename): Tutorial {
27-
return path + filename;
28-
});
29-
next(err, tutorials);
30-
});
31-
};
32-
33-
const prefixedFsExists = function(path: string, next): void {
34-
const totalPath: string = prefix + path;
35-
fs.access(totalPath, fs.constants.R_OK, function(error) {
36-
next(null, !error);
37-
});
38-
};
39-
4021
const getListOfTutorials = function(request, response: {writeHead, end})
4122
: void {
4223
const pathForTutorials: string = "tutorials/";
43-
const pathForUserTutorials: string = "shared-tutorials/";
44-
const folderList: string[] = [pathForTutorials, pathForUserTutorials];
45-
async.filter(folderList, prefixedFsExists, function(err, existingFolders) {
46-
if (err) {
47-
console.log("Something went wrong when getting the list of tutorials.");
24+
25+
const totalPath: string = prefix + pathForTutorials;
26+
fs.access(totalPath, fs.constants.R_OK, function(error) {
27+
if (error) {
28+
console.log("Tutorial directory does not exists.");
4829
response.writeHead(500, {"Content-Type": "text/plain"});
49-
response.end("Something went wrong when getting the list of tutorials.");
30+
response.end("Tutorial directory does not exists.");
5031
return;
5132
}
52-
async.concat(
53-
existingFolders,
54-
prefixedFsReaddir,
55-
function(error, files: string[],
56-
) {
57-
if (error) {
58-
throw new Error("async.concat() failed: " + error);
59-
}
60-
let tutorials: Tutorials = files.filter(
61-
function(filename: Tutorial): Tutorials {
62-
return filename.match(/\.html$/);
63-
});
64-
response.writeHead(200, {
65-
"Content-Type": "text/html",
66-
});
67-
tutorials = moveWelcomeTutorialToBeginning(tutorials,
68-
"tutorials/welcome2.html");
69-
response.end(JSON.stringify(tutorials));
70-
});
33+
fs.readdir(totalPath, function(err, files) {
34+
if (err) {
35+
console.log("Reading directory of tutorials failed.");
36+
response.writeHead(500, {"Content-Type": "text/plain"});
37+
response.end("Reading directory of tutorials failed.");
38+
return;
39+
}
40+
let tutorials: Tutorials = files.map(function(filename): Tutorial {
41+
return pathForTutorials + filename;
42+
});
43+
tutorials = tutorials.filter(
44+
function(filename: Tutorial): Tutorials {
45+
return filename.match(/\.html$/);
46+
});
47+
tutorials = moveWelcomeTutorialToBeginning(tutorials,
48+
"tutorials/welcome2.html");
49+
50+
response.writeHead(200, {
51+
"Content-Type": "text/html",
52+
});
53+
response.end(JSON.stringify(tutorials));
7154
});
55+
});
7256
};
7357

7458
return getListOfTutorials;

src/tests/tutorialReader.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ describe("GetListOfTutorials Module:", function() {
5151
},
5252
end() {
5353
const expected = JSON.stringify([
54-
"tutorials/mock.html",
55-
"shared-tutorials/mock.html",
54+
"tutorials/mock.html"
5655
]);
5756
assert.equal(spy.args, expected);
5857
assert(spy.calledOnce);
File renamed without changes.

0 commit comments

Comments
 (0)