4 |
5 |
6 |
7 |
8 | SageMathCell Help Resources
9 |
10 |
11 | {% include info.html %}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/timing/config.cfg:
--------------------------------------------------------------------------------
1 | [global]
2 | run_time: 100
3 | rampup: 10
4 | console_logging: off
5 | results_ts_interval: 5
6 |
7 | project_config_script: curl --silent http://boxen.math.washington.edu:5467/config
8 |
9 | [user_group-1]
10 | threads: 50
11 | script: simple_computation.py
12 | script_options: poll_interval=0.1, base_url="http://boxen.math.washington.edu:5467"
13 |
14 |
15 | #[user_group-2]
16 | #threads: 100
17 | #script: simple_computation.py
18 |
--------------------------------------------------------------------------------
/static/main.css:
--------------------------------------------------------------------------------
1 | @import "../build/vendor/components/codemirror/lib/codemirror.css";
2 | @import "../build/vendor/components/codemirror/addon/display/fullscreen.css";
3 | @import "../build/vendor/components/codemirror/addon/fold/foldgutter.css";
4 | @import "../build/vendor/components/codemirror/addon/hint/show-hint.css";
5 |
6 | @import "jquery-ui.min.css";
7 | @import "colorpicker/css/colorpicker.css";
8 | @import "fontawesome.css";
9 |
10 | @import "sagecell.css";
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *~
3 |
4 | /build*/
5 | /doc/_build/*
6 | /static/SageMenu.mnu
7 | /static/all.min.css
8 | /static/embedded_sagecell.js
9 | /static/embedded_sagecell.js.map
10 | /static/embedded_sagecell.js.LICENSE.txt
11 | /static/images/
12 | /static/jquery.min.js
13 | /static/jquery-ui.min.css
14 | /static/jsmol
15 | /static/sagecell_embed.css
16 | /static/tos.html
17 | /templates/tos.html
18 | /tests/multimechanize/results/
19 | /config.py
20 | /sqlite.db
21 | node_modules
22 |
--------------------------------------------------------------------------------
/contrib/vm/compute_node/etc/nginx/conf.d/sagecell.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8889;
3 | gzip on;
4 | gzip_types *;
5 | root /home/{server}/sagecell;
6 | location /static/ {
7 | add_header Access-Control-Allow-Origin $http_origin;
8 | }
9 | location = /static/jsmol/php/jsmol.php {
10 | # Script adds Access-Control-Allow-Origin *
11 | include snippets/fastcgi-php.conf;
12 | fastcgi_pass unix:/run/php/php7.2-fpm.sock;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/contrib/vm/compute_node/root/check_sagecell:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | systemctl --quiet is-active sagecell
4 | if [ $? -ne 0 ]
5 | then
6 | echo "`date` Service is not active, skipping check"
7 | exit 0
8 | fi
9 |
10 | /home/{server}/sagecell/contrib/sagecell-client/sagecell-service.py $1
11 | if [ $? -ne 0 ]
12 | then
13 | echo "`date` Error in server. Restarting..."
14 | systemctl restart sagecell
15 | echo "`date` Restarted."
16 | echo "************"
17 | exit 1
18 | fi
19 |
--------------------------------------------------------------------------------
/contrib/vm/compute_node/config.py:
--------------------------------------------------------------------------------
1 | import config_default
2 |
3 |
4 | # Global database running on Google Compute Engine with a static IP
5 | db = "web"
6 | db_config = {"uri": "http://130.211.113.153"}
7 |
8 | requires_tos = False
9 |
10 | pid_file = '/home/{server}/sagecell.pid'
11 |
12 | config_default.provider_settings.update({
13 | "max_kernels": 80,
14 | "max_preforked": 10,
15 | })
16 |
17 | config_default.provider_info.update({
18 | "username": "{worker}",
19 | })
20 |
--------------------------------------------------------------------------------
/timing/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | The timing tests use a heavily-modified version of MultiMechanize, which is a framework for running stress tests of web applications. To test:
3 |
4 | #. Download the `custom version of MultiMechanize `_
5 | #. Copy (or symbolic link) the ``timing`` directory into the ``projects`` directory of multi-mechanize
6 | #. Get the web server running
7 | #. Run ``python multi-mechanize.py timing`` from the multi-mechanize root directory
8 |
9 | """
10 |
11 |
--------------------------------------------------------------------------------
/contrib/dokuwiki/conf/default.php:
--------------------------------------------------------------------------------
1 |
6 | */
7 |
8 | $conf['url'] = 'https://sagecell.sagemath.org';
9 | $conf['style'] = '.sagecell .CodeMirror pre {
10 | padding: 0 4px !important;
11 | border: 0px !important;
12 | margin: 0 !important;}
13 | .sagecell .CodeMirror {
14 | height: auto;
15 | }
16 | .sagecell .CodeMirror-scroll {
17 | overflow-y: auto;
18 | overflow-x: auto;
19 | max-height: 200px;
20 | }
21 | ';
22 |
--------------------------------------------------------------------------------
/contrib/sphinx2/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "!layout.html" %}
2 | {% block linktags %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
18 |
19 | {{ super() }}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/contrib/vm/permalink_database/etc/systemd/system/permalink_database.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=SageMathCell Permalink Server
3 |
4 |
5 | [Service]
6 | Type=notify
7 | NotifyAccess=all
8 | Restart=always
9 | SyslogIdentifier=SageMathCell
10 |
11 | ExecStartPre=\
12 | /sbin/iptables -t nat --flush PREROUTING ;\
13 | /sbin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
14 |
15 |
16 | PermissionsStartOnly=true
17 | WorkingDirectory=/home/sc_data
18 | User=sc_data
19 | ExecStart=/usr/bin/python3 sagecell/permalink_server.py
20 |
21 |
22 | [Install]
23 | WantedBy=multi-user.target
24 |
--------------------------------------------------------------------------------
/static/test/linked.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sage Cell Server
7 |
8 |
11 |
12 |
13 | Type your own Sage computation below and click “Evaluate”.
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/static/fontawesome-webfont.afm:
--------------------------------------------------------------------------------
1 | StartFontMetrics 2.0
2 | Comment Generated by FontForge 20120731
3 | Comment Creation Date: Wed Nov 13 01:22:55 2013
4 | FontName fontawesome
5 | FullName fontawesome
6 | FamilyName fontawesome
7 | Weight Book
8 | Notice (Created by root with FontForge 2.0 (http://fontforge.sf.net))
9 | ItalicAngle 0
10 | IsFixedPitch true
11 | UnderlinePosition -170.667
12 | UnderlineThickness 85.3333
13 | Version 001.000
14 | EncodingScheme ISO10646-1
15 | FontBBox 0 -75 900 825
16 | StartCharMetrics 2
17 | C -1 ; WX 899 ; N resize-full ; B 0 -75 900 825 ;
18 | C -1 ; WX 899 ; N resize-small ; B 7 -68 893 818 ;
19 | EndCharMetrics
20 | EndFontMetrics
21 |
--------------------------------------------------------------------------------
/contrib/vm/compute_node/etc/systemd/system/sagecell.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=SageMathCell computation server
3 |
4 |
5 | [Service]
6 | Type=notify
7 | NotifyAccess=all
8 | Restart=always
9 | SyslogIdentifier=SageMathCell
10 |
11 | ExecStartPre=/root/firewall
12 | ExecStartPre=\
13 | -/usr/bin/pkill -u {worker} ;\
14 | /bin/rm -rf /tmp/sagecell ;\
15 | /bin/mkdir /tmp/sagecell ;\
16 | /bin/chown {server}:{group} /tmp/sagecell ;\
17 | /bin/chmod g=wxs,o= /tmp/sagecell
18 |
19 | PermissionsStartOnly=true
20 | WorkingDirectory=/home/{server}/sagecell
21 | User={server}
22 | ExecStart=/home/{server}/sage/sage web_server.py
23 |
24 |
25 | [Install]
26 | WantedBy=multi-user.target
27 |
--------------------------------------------------------------------------------
/contrib/sphinx2/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from setuptools import setup, find_packages
4 |
5 | long_desc = '''
6 | This package contains the sage cell server Sphinx extension.
7 |
8 | The extension defines a directive, "sagecellserver", for embedding sage cell.
9 | '''
10 |
11 | requires = ['Sphinx>=0.6', 'setuptools']
12 |
13 |
14 | setup(name='icsecontrib-sagecellserver',
15 | version='1.1',
16 | description='Sphinx sagecellserver extension',
17 | author='Krzysztof Kajda',
18 | author_email='kajda.krzysztof@gmail.com',
19 | packages=find_packages(),
20 | include_package_data=True,
21 | install_requires=requires,
22 | namespace_packages=['icsecontrib'],
23 | )
24 |
--------------------------------------------------------------------------------
/static/colorpicker/js/eye.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Zoomimage
4 | * Author: Stefan Petre www.eyecon.ro
5 | *
6 | */
7 | (function($){
8 | var EYE = window.EYE = function() {
9 | var _registered = {
10 | init: []
11 | };
12 | return {
13 | init: function() {
14 | $.each(_registered.init, function(nr, fn){
15 | fn.call();
16 | });
17 | },
18 | extend: function(prop) {
19 | for (var i in prop) {
20 | if (prop[i] != undefined) {
21 | this[i] = prop[i];
22 | }
23 | }
24 | },
25 | register: function(fn, type) {
26 | if (!_registered[type]) {
27 | _registered[type] = [];
28 | }
29 | _registered[type].push(fn);
30 | }
31 | };
32 | }();
33 | $(EYE.init);
34 | })(jQuery);
35 |
--------------------------------------------------------------------------------
/js/css.js:
--------------------------------------------------------------------------------
1 | /** Statically import CSS files and re-export them as a string */
2 |
3 | import codemirror from "codemirror/lib/codemirror.css";
4 | import fullscreen from "codemirror/addon/display/fullscreen.css";
5 | import foldgutter from "codemirror/addon/fold/foldgutter.css";
6 | import show_hint from "codemirror/addon/hint/show-hint.css";
7 | import jquery from "jquery-ui-themes/themes/smoothness/jquery-ui.min.css";
8 |
9 | import _colorpicker from "colorpicker.css";
10 | // Fix colorpicker's relative paths
11 | const colorpicker = _colorpicker.replace(/url\(\.\./g, "url(colorpicker");
12 | import fontawesome from "fontawesome.css";
13 | import sagecell_css from "sagecell.css";
14 |
15 | const css = `${codemirror}\n\n${fullscreen}\n\n${foldgutter}\n\n${show_hint}\n\n${jquery}\n\n${colorpicker}\n\n${fontawesome}\n\n${sagecell_css}`;
16 |
17 | export { css };
18 |
--------------------------------------------------------------------------------
/js/console.js:
--------------------------------------------------------------------------------
1 | import sagecell from "./sagecell";
2 |
3 | export const origConsole = window.console;
4 |
5 | /**
6 | * A replacement for window.console that suppresses logging based on `sagecell.quietMode`
7 | */
8 | export const console = {
9 | log(...args) {
10 | if (sagecell.quietMode) {
11 | return;
12 | }
13 | origConsole.log(...args);
14 | },
15 | info(...args) {
16 | if (sagecell.quietMode) {
17 | return;
18 | }
19 | origConsole.info(...args);
20 | },
21 | debug(...args) {
22 | if (sagecell.quietMode) {
23 | return;
24 | }
25 | origConsole.debug(...args);
26 | },
27 | error(...args) {
28 | origConsole.error(...args);
29 | },
30 | warn(...args) {
31 | origConsole.warn(...args);
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/static/root.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 20px;
3 | font-family: sans-serif;
4 | background-color: white;
5 | }
6 |
7 | #sagecell_main {
8 | /* This is so that an interact that changes size
9 | doesn't cause the browser to scroll everything up and down */
10 | margin-bottom: 80%;
11 | }
12 |
13 | a {
14 | text-decoration: none;
15 | color: mediumblue;
16 | }
17 |
18 | a:hover {
19 | text-decoration: underline;
20 | }
21 |
22 | .sagecell button.sagecell_evalButton {
23 | font-size: 120%;
24 | }
25 |
26 | #sagecell_about {
27 | position: absolute;
28 | top: 5px;
29 | right: 5px;
30 | font-size: 80%;
31 | }
32 |
33 | ol.sagecell_toc,
34 | ol.sagecell_toc ol {
35 | list-style: none;
36 | }
37 |
38 | .sagecell_disclaimer {
39 | font-size: 80%;
40 | }
41 |
42 | .sagecell .CodeMirror-scroll {
43 | min-height: 14em;
44 | }
45 |
--------------------------------------------------------------------------------
/contrib/drupalmodule/sagecell_makesagecell.inc:
--------------------------------------------------------------------------------
1 | 'header', 'every_page' => TRUE));
4 | drupal_add_js('http://aleph.sagemath.org/embedded_sagecell.js', array('scope' => 'header', 'every_page' => TRUE));
5 |
6 | // Add the inline JS to create the cell, performed after the page is loaded.
7 | // The long callback function changes the sagecell's buttons "type's" to "button" so they don't default to "submit" and submit the page when pressed
8 | drupal_add_js("sagecell.jQuery(function () { sagecell.makeSagecell({inputLocation: '#editcelltextarea', hide: ['files', 'sageMode'], evalButtonText: 'Evaluate', callback: function () {sagecell.jQuery('.sagecell button').each(function (i) {this.setAttribute('type', 'button');});}});});", array('type' => 'inline', 'defer' => TRUE, 'every_page' => TRUE));
9 |
10 |
--------------------------------------------------------------------------------
/static/logo_sagemath_cell.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/contrib/drupalmodule/sagecell.install:
--------------------------------------------------------------------------------
1 | 'text', // $schema['columns']['code$
11 | 'size' => 'medium',
12 | 'not null' => TRUE,
13 | //'length' => 100000,
14 | );
15 | //$schema['indexes'] = array(
16 | // 'code' => array(array('code',30)), // $schema['indexes']['code'] = ('c$
17 | // );
18 |
19 | }
20 | return $schema;
21 | }
22 |
--------------------------------------------------------------------------------
/contrib/vm/compute_node/etc/rsyslog.d/sagecell.conf:
--------------------------------------------------------------------------------
1 | global(maxMessageSize="64k")
2 |
3 | module(load="omrelp")
4 |
5 | template(name="sagecell_local" type="list") {
6 | property(name="syslogtag")
7 | property(name="msg" spifno1stsp="on")
8 | property(name="msg" droplastlf="on")
9 | constant(value=" #")
10 | property(name="syslogseverity-text" caseconversion="upper")
11 | constant(value="\n")
12 | }
13 |
14 | if $syslogfacility-text == "local3" then
15 | {
16 | action(type="omfile"
17 | file="/var/log/sagecell.log"
18 | template="sagecell_local")
19 | if $syslogseverity-text != "debug" and $msg contains " sagecell.stats " then
20 | action(type="omrelp"
21 | target="10.0.3.1"
22 | port="12514"
23 | action.resumeRetryCount="-1"
24 | queue.type="linkedList"
25 | queue.filename="sagecell"
26 | queue.maxDiskSpace="1g"
27 | queue.saveOnShutdown="on")
28 | stop
29 | }
30 |
--------------------------------------------------------------------------------
/contrib/dokuwiki/README:
--------------------------------------------------------------------------------
1 | sagecell Plugin for DokuWiki
2 |
3 | Embed a Sage Cell into your page
4 |
5 | All documentation for this plugin can be found at
6 | https://github.com/sagemath/sagecell
7 |
8 | If you install this plugin manually, make sure it is installed in
9 | lib/plugins/sagecell/ - if the folder is called different it
10 | will not work!
11 |
12 | Please refer to http://www.dokuwiki.org/plugins for additional info
13 | on how to install plugins in DokuWiki.
14 |
15 | ----
16 | Copyright (C) Jason Grout
17 |
18 | This program is free software; you can redistribute it and/or modify
19 | it under the terms of the GNU General Public License as published by
20 | the Free Software Foundation; version 2 of the License
21 |
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
26 |
27 | See the COPYING file in your DokuWiki folder for details
28 |
--------------------------------------------------------------------------------
/db.py:
--------------------------------------------------------------------------------
1 | """
2 | Generic Database Adapter
3 |
4 | The database is used for storing execute requests and
5 | permalinks, as well as any extra logging required by
6 | the web server and/or backend.
7 | """
8 |
9 |
10 | class DB(object):
11 | """
12 | Abstract base class for database adaptors.
13 | """
14 |
15 | async def add(self, code, language, interacts):
16 | """
17 | Add an entry to the database.
18 |
19 | INPUT:
20 |
21 | - ``code`` -- a string
22 |
23 | - ``language`` -- a string
24 |
25 | - ``interacts`` -- a string
26 |
27 | OUTPUT:
28 |
29 | - a string -- the identifier key for the entry
30 | """
31 | raise NotImplementedError
32 |
33 | async def get(self, key):
34 | """
35 | Retrieve the entry from the database matching ``key``.
36 |
37 | INPUT:
38 |
39 | - ``key`` -- a string
40 |
41 | OUTPUT:
42 |
43 | - a tuple of three strings: the code, the language, the interact state.
44 | """
45 | raise NotImplementedError
46 |
--------------------------------------------------------------------------------
/templates/tos_default.html:
--------------------------------------------------------------------------------
1 |
The Sage Cell Server is a non-commercial service that may change or be shut down
2 | at any time. You agree to not post malware, viruses, spam, etc. You will not use
3 | the Sage Cell Server to send spam or attack other computers or people in any way.
4 | You will not attempt to bring harm to the system or hack into it. You also agree
5 | that all content that you compute with this site is by default visible to anybody
6 | else on the Internet. The resources available to you through this service, and
7 | these Terms of Usage, may change at any time without warning. This service is not
8 | guaranteed to have any uptime or backups.
9 |
THE SERVICE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
10 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
11 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
12 | HOLDERS OR SERVICE PROVIDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
13 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
--------------------------------------------------------------------------------
/db_web.py:
--------------------------------------------------------------------------------
1 | """
2 | Web Database Adapter
3 | """
4 |
5 | import json
6 | import urllib
7 |
8 |
9 | import tornado.httpclient
10 |
11 |
12 | import db
13 |
14 |
15 | class DB(db.DB):
16 | """
17 | :arg URL str: the URL for the key-value store
18 | """
19 |
20 | def __init__(self, url):
21 | self.url = url
22 |
23 | async def add(self, code, language, interacts):
24 | """
25 | See :meth:`db.DB.add`
26 | """
27 | body = urllib.parse.urlencode({
28 | "code": code.encode("utf8"),
29 | "language": language.encode("utf8"),
30 | "interacts": interacts.encode("utf8")})
31 | http_client = tornado.httpclient.AsyncHTTPClient()
32 | response = await http_client.fetch(
33 | self.url, method="POST", body=body,
34 | headers={"Accept": "application/json"})
35 | return json.loads(response.body)["query"]
36 |
37 | async def get(self, key):
38 | """
39 | See :meth:`db.DB.get`
40 | """
41 | http_client = tornado.httpclient.AsyncHTTPClient()
42 | response = await http_client.fetch(
43 | "{}?q={}".format(self.url, key), method="GET",
44 | headers={"Accept": "application/json"})
45 | return json.loads(response.body)
46 |
--------------------------------------------------------------------------------
/doc/timing.rst:
--------------------------------------------------------------------------------
1 | Timing
2 | =======
3 |
4 | .. automodule:: timing
5 |
6 |
7 | Test Scripts
8 | ------------
9 |
10 | Timing Utilities
11 | ^^^^^^^^^^^^^^^^
12 |
13 | .. automodule:: timing.test_scripts.timing_util
14 |
15 | Timing Tests
16 | ^^^^^^^^^^^^
17 |
18 | .. automodule:: timing.test_scripts.simple_computation
19 |
20 | Testing
21 | -------
22 |
23 | Here are some tests that should be written:
24 |
25 | * an interact (maybe where the user waits a small random amount of time, then "moves the slider", another small random amount of time and "changes an input", etc.
26 |
27 | * upload a file, do some operation on the file, and then get the result (and the resulting file)
28 |
29 | * a longer computation than just summing two numbers. Maybe a for loop that calculates a factorial of a big number or something.
30 |
31 | * generate a file in code (maybe a matplotlib plot) and download the resulting image
32 |
33 | * Exercise the "Sage Mode" --- that should also be an option for all of the above
34 |
35 | * Sage-specific preparser tests.
36 |
37 | * tests exercising memory and cputime limits::
38 |
39 | import time
40 | a = []
41 | for i in range(20):
42 | a.append([0] * 50000000)
43 | time.sleep(1)
44 | print(get_memory_usage())
45 |
46 | or for time limits::
47 |
48 | factor(2^4994-3^344)
49 |
--------------------------------------------------------------------------------
/namespace.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 |
3 |
4 | class InstrumentedNamespace(dict):
5 | def __init__(self, *args, **kwargs):
6 | """
7 | Set up a namespace id
8 | """
9 | dict.__init__(self,*args,**kwargs)
10 | self.events = defaultdict(lambda: defaultdict(list))
11 |
12 | def on(self, key, event, f):
13 | self.events[key][event].append(f)
14 |
15 | def off(self, key, event=None, f=None):
16 | if event is None:
17 | self.events.pop(key, None)
18 | elif f is None:
19 | self.events[key].pop(event, None)
20 | else:
21 | self.events[key][event].remove(f)
22 |
23 | def trigger(self, key, event, *args, **kwargs):
24 | if key in self.events and event in self.events[key]:
25 | for f in self.events[key][event]:
26 | f(key, *args, **kwargs)
27 |
28 | def __setitem__(self, key, value):
29 | """
30 | Set a value in the dictionary and run attached notification functions.
31 | """
32 | if key not in self:
33 | self.trigger(key, 'initialize', value)
34 | dict.__setitem__(self, key, value)
35 | self.trigger(key, 'change', value)
36 |
37 | def __delitem__(self, key):
38 | dict.__delitem__(self, key)
39 | self.off(key)
40 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | sage-root := $(shell [ -n "$$SAGE_ROOT" ] && echo "$$SAGE_ROOT" || sage --root || echo "\$$SAGE_ROOT")
2 | all-min-js = static/embedded_sagecell.js
3 | all-min-js-map = static/embedded_sagecell.js.map
4 | all-min-js-license = static/embedded_sagecell.js.LICENSE.txt
5 |
6 | sagecell-css = static/sagecell.css
7 | embed-css = static/sagecell_embed.css
8 |
9 | tos-default = templates/tos_default.html
10 | tos = templates/tos.html
11 | tos-static = static/tos.html
12 |
13 | all: $(all-min-js) $(embed-css) $(tos-static)
14 |
15 | .PHONY: $(tos-static)
16 |
17 | build:
18 | npm install
19 | -rm -r build
20 | npm run build:deps
21 | ln -sfn $(SAGE_VENV)/share/jupyter/nbextensions/jupyter-jsmol/jsmol static/jsmol
22 | ln -sfn $(sage-root)/local/share/threejs-sage/r122 static/threejs
23 | ln -sf $(sage-root)/local/share/jmol/appletweb/SageMenu.mnu static/SageMenu.mnu
24 | cp static/jsmol/JSmol.min.nojq.js build/vendor/JSmol.js
25 |
26 | $(all-min-js): build js/*
27 | npm run build
28 | cp build/embedded_sagecell.js $(all-min-js)
29 | cp build/embedded_sagecell.js.map $(all-min-js-map)
30 | cp build/embedded_sagecell.js.LICENSE.txt $(all-min-js-license)
31 | # Host standalone jquery for compatibility with old instructions
32 | cp build/vendor/jquery*.min.js static/jquery.min.js
33 |
34 | $(embed-css): $(sagecell-css)
35 | sed -e 's/;/ !important;/g' < $(sagecell-css) > $(embed-css)
36 |
37 | $(tos-static): $(tos-default)
38 | @[ -e $(tos) ] && cp $(tos) $(tos-static) || cp $(tos-default) $(tos-static)
39 |
--------------------------------------------------------------------------------
/contrib/dokuwiki/syntax.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 |
9 | // must be run within Dokuwiki
10 | if (!defined('DOKU_INC')) die();
11 |
12 | if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
13 | if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14 | if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15 |
16 | require_once DOKU_PLUGIN.'syntax.php';
17 |
18 | class syntax_plugin_sagecell extends DokuWiki_Syntax_Plugin {
19 | public function getType() {
20 | return 'protected';
21 | }
22 |
23 | public function getPType() {
24 | return 'normal';
25 | }
26 |
27 | public function getSort() {
28 | return 65;
29 | }
30 |
31 |
32 | public function connectTo($mode) {
33 | $this->Lexer->addSpecialPattern('.*?', $mode, 'plugin_sagecell');
34 | }
35 |
36 | public function handle($match, $state, $pos, &$handler){
37 | $data = array("code" => str_replace('', '<\/script>', substr($match,10,-11)));
38 | return $data;
39 | }
40 |
41 | public function render($mode, &$renderer, $data) {
42 | if($mode != 'xhtml') return false;
43 | $renderer->doc .= "";
44 | return true;
45 | }
46 | }
47 |
48 | // vim:ts=4:sw=4:et:
49 |
--------------------------------------------------------------------------------
/tests/multimechanize/test_scripts/simple_session.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | import client
4 | import time
5 | import random
6 |
7 | class Transaction(object):
8 | """
9 | A transaction that simulates loading the page
10 | and performing a simple addition
11 | """
12 |
13 | def __init__(self):
14 | self.custom_timers = {}
15 |
16 | def run(self):
17 | t = time.time()
18 | client.load_root()
19 | self.custom_timers["root load"] = time.time() - t
20 | time.sleep(5)
21 | t = time.time()
22 | with client.SageCellSession() as s:
23 | self.custom_timers["initial connection"] = time.time() - t
24 | t = time.time()
25 | num1 = random.randint(1, 10 ** 20)
26 | num2 = random.randint(1, 10 ** 20)
27 | s.execute("print %d + %d" % (num1, num2))
28 | output = ""
29 | while True:
30 | msg = s.iopub_recv()
31 | if msg["header"]["msg_type"] == "status" and msg["content"]["execution_state"] == "idle":
32 | break
33 | elif msg["header"]["msg_type"] == "stream" and msg["content"]["name"] == "stdout":
34 | output += msg["content"]["data"]
35 | assert int(output.strip()) == num1 + num2, "Incorrect output: %r" % (output,)
36 | self.custom_timers["computation"] = time.time() - t
37 |
38 | if __name__ == "__main__":
39 | t = Transaction()
40 | t.run()
41 | print t.custom_timers
42 |
--------------------------------------------------------------------------------
/templates/root.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sage Cell Server
8 |
9 |
10 |
11 |
12 |
13 |
14 | Type some Sage code below and press Evaluate.
15 |
16 | About SageMathCell
17 |
35 | {% include info.html %}
36 |
37 |
38 |
--------------------------------------------------------------------------------
/contrib/moinmoin/sagecell.py:
--------------------------------------------------------------------------------
1 | """
2 | MoinMoin - Sage Cell Parser
3 |
4 | @copyright: 2012 Jason Grout
5 | @license: Modified BSD
6 |
7 | Usage::
8 |
9 | {{{#!sagecell
10 | 1+1
11 | }}}
12 |
13 | Installation
14 |
15 | Put this file in ``data/plugin/parser/``.
16 |
17 | You must also something like these lines in your wikiconfig::
18 |
19 | html_head = ''
20 | html_head += ''
21 |
22 |
23 | """
24 | from MoinMoin.parser._ParserBase import ParserBase
25 | from uuid import uuid4
26 |
27 | Dependencies = ['user']
28 |
29 | template="""
30 |
31 |
34 | """
35 |
36 | class Parser(ParserBase):
37 |
38 | parsername = "sagecell"
39 | Dependencies = []
40 |
41 | def __init__(self, code, request, **kw):
42 | self.code = self.sanitize(code)
43 | self.request = request
44 |
45 | def sanitize(self, code):
46 | """
47 | Sanitize the code, for example, escape any instances of
48 | """
49 | sanitized=code.replace("", "<\/script>")
50 | return sanitized
51 |
52 | def format(self, formatter):
53 | self.request.write(formatter.rawHTML(template%{'random': uuid4(), 'code': self.code}))
54 |
--------------------------------------------------------------------------------
/timing/test_scripts/timing_util.py:
--------------------------------------------------------------------------------
1 | """
2 | Provide a timing utility context manager
3 | """
4 | import contextlib
5 | @contextlib.contextmanager
6 | def timing(results=None):
7 | """
8 | Time the execution of the block of code. If a results list is
9 | passed in, the time is appended to the list. Also returns a list
10 | of one element containing the time the execution took.
11 |
12 | To use, do something like::
13 |
14 | from time import sleep
15 | results_list=[]
16 | with timing(results_list) as t:
17 | sleep(1)
18 | print results_list, t
19 |
20 | Exceptions in the code should be re-raised and the timing should
21 | correctly be set regardless of the exceptions.
22 | """
23 | from time import time
24 | try:
25 | # code in the context is executed when we yield
26 | start=[time()]
27 | yield start
28 | except:
29 | # any exceptions in the code should get propogated
30 | raise
31 | finally:
32 | start.append(time()-start[0])
33 | if results is not None:
34 | results.append(start)
35 |
36 | import urllib
37 | import urllib2
38 |
39 | try: import simplejson as json
40 | except ImportError: import json
41 |
42 | def json_request(url, data=None):
43 | """
44 | Send a JSON message to the URL and return the result as a
45 | dictionary.
46 |
47 | :param data: a JSON-stringifiable object, passed in the POST
48 | variable ``message``
49 | :returns: a JSON-parsed dict/list/whatever from the server reply
50 | """
51 | if data is not None:
52 | data = urllib.urlencode(data)
53 | response = urllib2.urlopen(url, data)
54 | return json.loads(response.read())
55 |
56 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "embedded_sagecell.js",
3 | "version": "1.0.0",
4 | "description": "Sage cell that can be embedded into a webpage",
5 | "main": "main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build:copystatic": "mkdir -p build/vendor && cp static/sagecell.css static/fontawesome.css static/colorpicker/js/colorpicker.js static/colorpicker/css/colorpicker.css build/vendor",
9 | "build:deps": "npm run build:copystatic && node fetch_vendor_js.mjs",
10 | "build": "webpack --mode production",
11 | "watch": "webpack --watch --mode development"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/sagemath/"
16 | },
17 | "keywords": [
18 | "sage"
19 | ],
20 | "author": "Jason Grout, Andrey Novoseltsev, Ira Hanson, Alex Kramer",
21 | "license": "SEE LICENSE IN LICENSE.txt",
22 | "dependencies": {
23 | "codemirror": "^5.65.1",
24 | "domready": "^1.0.8",
25 | "es6-promise": "^4.2.8",
26 | "jquery": "^3.6.0",
27 | "jquery-ui": "^1.13.2",
28 | "jquery-ui-themes": "^1.12.0",
29 | "jsmol": "^1.0.0",
30 | "moment": "^2.29.4",
31 | "node-fetch": "^3.2.10",
32 | "sockjs": "^0.3.24",
33 | "sockjs-client": "^1.5.2",
34 | "source-map-loader": "^3.0.1",
35 | "ts-loader": "^9.2.6",
36 | "underscore": "^1.13.2",
37 | "webpack-jquery-ui": "^2.0.1"
38 | },
39 | "devDependencies": {
40 | "@babel/core": "^7.17.2",
41 | "@babel/plugin-transform-modules-amd": "^7.16.7",
42 | "@babel/preset-env": "^7.16.11",
43 | "babel-loader": "^8.2.3",
44 | "eslint": "^8.9.0",
45 | "raw-loader": "^4.0.2",
46 | "webpack": "^5.94.0",
47 | "webpack-bundle-analyzer": "^4.5.0",
48 | "webpack-cli": "^4.9.2"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/contrib/vm/build_host.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 | set -o xtrace
5 |
6 | APTPROXY="http://your-proxy-here-or-delete-proxy-from-preseed/"
7 | MAC=52:54:00:5a:9e:c1 # Must start with 52:54:00
8 |
9 | VM_NAME=schostvm
10 | OSVARIANT=ubuntu18.04
11 | LOCATION="http://archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/"
12 |
13 | sed "s|APTPROXY|$APTPROXY|" preseed.host > preseed.cfg
14 |
15 | if ! [ -f ${VM_NAME}_rsa ]; then
16 | ssh-keygen -q -N "" -C "sc_admin" -f ${VM_NAME}_rsa
17 | fi
18 | SSHKEY=`cat ${VM_NAME}_rsa.pub`
19 | sed -i "s|SSHKEY|$SSHKEY|" preseed.cfg
20 |
21 | virt-install \
22 | --connect qemu:///system \
23 | --name $VM_NAME \
24 | --description "Host for SageCell instances." \
25 | --ram=32768 \
26 | --cpu host \
27 | --vcpus=12 \
28 | --location $LOCATION \
29 | --initrd-inject=preseed.cfg \
30 | --extra-args="console=ttyS0" \
31 | --os-type=linux \
32 | --os-variant=$OSVARIANT \
33 | --disk pool=default,size=100,device=disk,bus=virtio,format=qcow2,cache=writeback \
34 | --network network=default,model=virtio,mac=$MAC \
35 | --graphics none \
36 | --autostart \
37 | --check-cpu \
38 | --noreboot \
39 |
40 | # For a dedicated partition use
41 | #--disk path=/dev/???,bus=virtio \
42 |
43 | # Make a script to SSH inside, assuming that IP will not change
44 | virsh --connect qemu:///system start $VM_NAME
45 | sleep 30
46 | IP=`ip n|grep $MAC|grep -Eo "^[0-9.]{7,15}"`
47 | cat < ssh_host.sh
48 | #!/usr/bin/env bash
49 |
50 | if [[ \`virsh --connect qemu:///system domstate $VM_NAME\` != "running" ]]; then
51 | if ! virsh --connect qemu:///system start $VM_NAME; then
52 | echo "Failed to start $VM_NAME"
53 | exit 1
54 | fi
55 | sleep 30
56 | fi
57 |
58 | ssh -i ${VM_NAME}_rsa root@$IP
59 | EOF
60 | chmod u+x ssh_host.sh
61 | # Power cycle VM, otherwise bash completion does not work for LXC.
62 | virsh --connect qemu:///system shutdown $VM_NAME
63 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack");
2 | const path = require("path");
3 |
4 | module.exports = {
5 | entry: "./js/main.js",
6 | output: {
7 | filename: "./embedded_sagecell.js",
8 | path: path.resolve(__dirname, "build"),
9 | },
10 | // Enable sourcemaps for debugging webpack's output.
11 | devtool: "source-map",
12 | resolve: {
13 | extensions: ["", ".webpack.js", ".web.js", ".js"],
14 | modules: ["build/vendor", "node_modules"],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.m?js$/,
20 | exclude: /(node_modules|bower_components|JSmol.js)/,
21 | use: {
22 | loader: "babel-loader",
23 | options: {
24 | presets: ["@babel/preset-env"],
25 | plugins: ["@babel/plugin-transform-modules-amd"],
26 | },
27 | },
28 | },
29 | // JSmol.js is not written in strict mode, so the babel-loader
30 | // will error if it is imported. Instead we directly load
31 | // it in an unprocessed form.
32 | { test: /JSmol.js$/, loader: "source-map-loader" },
33 | {
34 | test: /\.(html|css)$/i,
35 | use: "raw-loader",
36 | },
37 | ],
38 | },
39 | plugins: [
40 | new webpack.ProvidePlugin({
41 | jQuery: "jquery",
42 | $: "jquery",
43 | // Normally the following lines are used to make sure that jQuery
44 | // cannot "leak" into the outside environment. However, since
45 | // we *want* to initialize the global jQuery object, we omit them.
46 | // "window.jQuery": "jquery",
47 | // "window.$": "jquery",
48 | }),
49 | new webpack.optimize.LimitChunkCountPlugin({
50 | maxChunks: 1,
51 | }),
52 | ],
53 | };
54 |
--------------------------------------------------------------------------------
/contrib/sagecell-client/sagecell-service.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 |
3 | from datetime import datetime
4 | import random
5 | import requests
6 | import sys
7 | import time
8 |
9 |
10 | retries = 3
11 |
12 | def message(s):
13 | print('{}: {} attempts left. {}'.format(datetime.now(), retries, s))
14 |
15 | while retries:
16 | retries -= 1
17 | a, b = random.randint(-2**31, 2**31), random.randint(-2**31, 2**31)
18 | # The handling of temporary files in Sage 9.7 does not allow SageMathCell to
19 | # function properly if there are no regular requests producing temporary
20 | # files. To fight it, we'll generate one during health checks. See
21 | # https://groups.google.com/g/sage-devel/c/jpwUb8OCVVc/m/R4r5bnOkBQAJ
22 | code = 'show(plot(sin)); print({} + {})'.format(a, b)
23 | try:
24 | r = requests.post(sys.argv[1] + '/service',
25 | data={"code": code, "accepted_tos": "true"},
26 | timeout=5)
27 | reply = r.json()
28 | # Every few hours we have a request that comes back as executed, but the
29 | # stdout is not in the dictionary. It seems that the compute message
30 | # never actually gets sent to the kernel and it appears the problem is
31 | # in the zmq connection between the webserver and the kernel.
32 | #
33 | # Also sometimes reply is unsuccessful, yet the server keeps running
34 | # and other requests are serviced. Since a restart breaks all active
35 | # interacts, better not to restart the server that "mostly works" and
36 | # instead we'll just accumulate statistics on these random errors to
37 | # help resolve them.
38 | if (reply['success']
39 | and 'stdout' in reply
40 | and int(reply['stdout'].strip()) == a + b):
41 | exit(0)
42 | message(reply)
43 | except Exception as e:
44 | message(e)
45 | time.sleep(0.5)
46 | message('The server is not working!')
47 | exit(1)
48 |
--------------------------------------------------------------------------------
/contrib/sphinx2/README.rst:
--------------------------------------------------------------------------------
1 | This extension defines a directive 'sagecellserver' which allows to embedd sage cell inside sphinx doc. To learn more about sage cell server visit: http://aleph.sagemath.org/static/about.html
2 |
3 |
4 | Installation
5 | =========
6 | 1. Install this extension: 'python setup.py install --user'
7 | 2. Move 'layout.html' to your '_templates' directory. Change sagecell paths if necessary
8 | 3. Add 'icsecontrib.sagecellserver' to your extensions in 'conf.py'
9 |
10 |
11 | How to use it
12 | ===========
13 |
14 | Example of usage::
15 |
16 | .. sagecellserver::
17 |
18 | sage: A = matrix([[1,1],[-1,1]])
19 | sage: D = [vector([0,0]), vector([1,0])]
20 | sage: @interact
21 | sage: def f(A = matrix([[1,1],[-1,1]]), D = '[[0,0],[1,0]]', k=(3..17)):
22 | ... print("Det = {}".format(A.det()))
23 | ... D = matrix(eval(D)).rows()
24 | ... def Dn(k):
25 | ... ans = []
26 | ... for d in Tuples(D, k):
27 | ... s = sum(A**n * d[n] for n in range(k))
28 | ... ans.append(s)
29 | ... return ans
30 | ... G = points([v.list() for v in Dn(k)], size=50)
31 | ... show(G, frame=True, axes=False)
32 |
33 |
34 | .. end of output
35 |
36 | Options
37 | ======
38 |
39 | The sage prompts can be removed by adding setting 'prompt_tag' option to False::
40 |
41 | .. sagecellserver::
42 | :prompt_tag: False
43 |
44 | Setting 'prompt_tag' to True has same effect as removing ':prompt_tag:'.
45 |
46 | During latex/pdf generation sagecell code can be displayed inside '\begin{verbatim}' and '\end{verbatim}' tags or as a single \textbf '***SAGE CELL***' message. This message is a reminder of sage cell exsistence. For example later this text can be manually replaced by screenshoot of sagcell example (mostly @interact example).
47 |
48 | This option is controlled using 'is_verbatim' option. Default is 'True'.::
49 |
50 | .. sagecellserver::
51 | :is_verbatim: True
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/static/colorpicker/js/layout.js:
--------------------------------------------------------------------------------
1 | (function($){
2 | var initLayout = function() {
3 | var hash = window.location.hash.replace('#', '');
4 | var currentTab = $('ul.navigationTabs a')
5 | .bind('click', showTab)
6 | .filter('a[rel=' + hash + ']');
7 | if (currentTab.size() == 0) {
8 | currentTab = $('ul.navigationTabs a:first');
9 | }
10 | showTab.apply(currentTab.get(0));
11 | $('#colorpickerHolder').ColorPicker({flat: true});
12 | $('#colorpickerHolder2').ColorPicker({
13 | flat: true,
14 | color: '#00ff00',
15 | onSubmit: function(hsb, hex, rgb) {
16 | $('#colorSelector2 div').css('backgroundColor', '#' + hex);
17 | }
18 | });
19 | $('#colorpickerHolder2>div').css('position', 'absolute');
20 | var widt = false;
21 | $('#colorSelector2').bind('click', function() {
22 | $('#colorpickerHolder2').stop().animate({height: widt ? 0 : 173}, 500);
23 | widt = !widt;
24 | });
25 | $('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({
26 | onSubmit: function(hsb, hex, rgb, el) {
27 | $(el).val(hex);
28 | $(el).ColorPickerHide();
29 | },
30 | onBeforeShow: function () {
31 | $(this).ColorPickerSetColor(this.value);
32 | }
33 | })
34 | .bind('keyup', function(){
35 | $(this).ColorPickerSetColor(this.value);
36 | });
37 | $('#colorSelector').ColorPicker({
38 | color: '#0000ff',
39 | onShow: function (colpkr) {
40 | $(colpkr).fadeIn(500);
41 | return false;
42 | },
43 | onHide: function (colpkr) {
44 | $(colpkr).fadeOut(500);
45 | return false;
46 | },
47 | onChange: function (hsb, hex, rgb) {
48 | $('#colorSelector div').css('backgroundColor', '#' + hex);
49 | }
50 | });
51 | };
52 |
53 | var showTab = function(e) {
54 | var tabIndex = $('ul.navigationTabs a')
55 | .removeClass('active')
56 | .index(this);
57 | $(this)
58 | .addClass('active')
59 | .blur();
60 | $('div.tab')
61 | .hide()
62 | .eq(tabIndex)
63 | .show();
64 | };
65 |
66 | EYE.register(initLayout, 'init');
67 | })(jQuery)
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Most of the files in this repository are individually licensed with
2 | the modified BSD license:
3 |
4 | Copyright (c) 2011, Jason Grout, Ira Hanson, Alex Kramer, William Stein
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are
9 | met:
10 |
11 | a. Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 |
14 | b. Redistributions in binary form must reproduce the above copyright
15 | notice, this list of conditions and the following disclaimer in
16 | the documentation and/or other materials provided with the
17 | distribution.
18 |
19 | c. Neither the name of the Sage Cell project nor the names of its
20 | contributors may be used to endorse or promote products derived
21 | from this software without specific prior written permission.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 |
35 |
36 | Some files (like interact_compatibility.py and interact_sagecell.py)
37 | are licensed GPLv2+ for the sole reason that they import Sage GPLv2+
38 | code (see the header for those files). If those imports are removed,
39 | the files may be licensed with the modified BSD license.
40 |
41 | Since this package includes GPLv2+ code (namely those files above),
42 | the repository as a whole is licensed GPLv2+.
43 |
--------------------------------------------------------------------------------
/config_default.py:
--------------------------------------------------------------------------------
1 | import os.path
2 |
3 |
4 | # Location of the Sage executable
5 | if 'SAGE_ROOT' in os.environ:
6 | # Assume that the worker should run the same Sage
7 | # that is used to run the web server
8 | sage = os.path.join(os.environ["SAGE_ROOT"], "sage")
9 | else:
10 | # Assume both the web server and the worker have Sage in their paths
11 | sage = "sage"
12 |
13 | # Require the user to accept terms of service before evaluation
14 | requires_tos = True
15 |
16 | db = "sqlalchemy"
17 | db_config = {"uri": "sqlite:///sqlite.db"}
18 |
19 | # db = "web"
20 | # db_config = {"uri": "http://localhost:8889"}
21 |
22 | permalink_server = {
23 | 'db': 'sqlalchemy',
24 | 'db_config': {'uri': 'sqlite:///sqlite.db'}
25 | }
26 |
27 | pid_file = 'sagecell.pid'
28 | permalink_pid_file = 'sagecell_permalink_server.pid'
29 |
30 | dir = "/tmp/sagecell"
31 |
32 | # Parameters for heartbeat channels checking whether a given kernel is alive.
33 | # Setting first_beat lower than 1.0 may cause JavaScript errors.
34 | beat_interval = 0.5
35 | first_beat = 1.0
36 |
37 | # Allowed idling between interactions with a kernel
38 | max_timeout = 60 * 15
39 | # Even an actively used kernel will be killed after this time
40 | max_lifespan = 60 * 30
41 |
42 | # Recommended settings for kernel providers
43 | provider_settings = {
44 | "max_kernels": 10,
45 | "max_preforked": 1,
46 | # The keys to resource_limits can be any available resources
47 | # for the resource module. See http://docs.python.org/library/resource.html
48 | # for more information (section 35.13.1)
49 | # RLIMIT_AS is more of a suggestion than a hard limit in Mac OS X
50 | # Also, Sage may allocate huge AS, making this limit pointless:
51 | # https://groups.google.com/d/topic/sage-devel/1MM7UPcrW18/discussion
52 | "preforked_rlimits": {
53 | "RLIMIT_CPU": 30, # CPU time in seconds
54 | },
55 | }
56 |
57 | # Location information for kernel providers
58 | provider_info = {
59 | "host": "localhost",
60 | "username": None,
61 | "python": sage + " -python",
62 | "location": os.path.dirname(os.path.abspath(__file__))
63 | }
64 |
65 | providers = [provider_info]
66 |
--------------------------------------------------------------------------------
/timing/test_scripts/sagecell.py:
--------------------------------------------------------------------------------
1 | import random
2 | from MultipartPostHandler import encode_request
3 | from urllib2 import urlopen, Request
4 | from urllib import urlencode
5 | from json import loads
6 |
7 |
8 | EVAL_PATH='/eval'
9 | POLL_PATH='/output_poll'
10 | FILE_PATH='/files'
11 |
12 |
13 | class Session:
14 | def __init__(self, server):
15 | server=server.rstrip('/')
16 | self.server=server
17 | self.session=random.random()
18 |
19 | def prepare_execution_request(self, code, files=None, sage_mode=True):
20 | """
21 | Prepare an execution request prior to sending it.
22 |
23 | We break up the preparation and sending phases so that it is easy
24 | to time just the request.
25 | """
26 | msg=[('session_id', self.session),
27 | ('commands', code),
28 | ('msg_id', random.random()),
29 | ('sage_mode', True if sage_mode else False)]
30 | if files is not None:
31 | for filename in files:
32 | msg.append(('file', open(filename,"rb")))
33 | request=Request(self.server+EVAL_PATH, msg)
34 | return encode_request(request)
35 |
36 | def send_execution_request(self, request):
37 | """
38 | Send an execution request along with a number of files.
39 |
40 | TODO: break into a "prepare" and "send" function for timing?
41 | """
42 | result=urlopen(request).read()
43 | if result:
44 | try:
45 | jsonresult=loads(result)
46 | self.session = jsonresult["session_id"]
47 | return jsonresult
48 | except ValueError:
49 | return result
50 | else:
51 | return result
52 |
53 | def output_poll(self, sequence=0):
54 | query=urlencode([('computation_id', self.session),
55 | ('sequence',sequence)])
56 | url=self.server+POLL_PATH+'?'+query
57 | return loads(urlopen(url).read())
58 |
59 | def get_file(self, filename):
60 | return urlopen(self.server+"%s/%s/%s"%(FILE_PATH,self.session,filename)).read()
61 |
62 |
--------------------------------------------------------------------------------
/fetch_vendor_js.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Script to download all required vendor javascript files.
3 | */
4 |
5 | import fs from "fs";
6 | import path from "path";
7 | import fetch from "node-fetch";
8 | import { fileURLToPath } from "url";
9 |
10 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
11 |
12 | const TARGET_DIR = path.resolve(__dirname, "build/vendor");
13 |
14 | const URLS = {
15 | "jquery.min.js":
16 | "https://code.jquery.com/jquery-3.7.1.min.js",
17 | "base/js/utils.js":
18 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/base/js/utils.js",
19 | "base/js/namespace.js":
20 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/base/js/namespace.js",
21 | "base/js/events.js":
22 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/base/js/events.js",
23 | "services/kernels/kernel.js":
24 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/services/kernels/kernel.js",
25 | "services/kernels/comm.js":
26 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/services/kernels/comm.js",
27 | "services/kernels/serialize.js":
28 | "https://raw.githubusercontent.com/jupyter/nbclassic/master/nbclassic/static/services/kernels/serialize.js",
29 | "mpl.js":
30 | "https://raw.githubusercontent.com/matplotlib/matplotlib/main/lib/matplotlib/backends/web_backend/js/mpl.js",
31 | };
32 |
33 | async function fetchFile(fileName, url) {
34 | const resp = await fetch(url);
35 | const body = await resp.text();
36 |
37 | const fullPath = `${TARGET_DIR}/${fileName}`;
38 | const base = path.dirname(fullPath);
39 | fs.mkdirSync(base, { recursive: true });
40 |
41 | const stream = fs.createWriteStream(fullPath);
42 | stream.once("open", function (fd) {
43 | stream.write(body);
44 | stream.end();
45 | console.log(`Downloaded ${fileName}`);
46 | });
47 | }
48 |
49 | // Ensure the target directory has been created
50 | fs.mkdirSync(TARGET_DIR, { recursive: true });
51 |
52 | for (const [fileName, url] of Object.entries(URLS)) {
53 | fetchFile(fileName, url);
54 | }
55 |
--------------------------------------------------------------------------------
/log.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 | from logging.handlers import SysLogHandler
4 | import sys
5 |
6 |
7 | LOG_LEVEL = logging.DEBUG
8 | LOG_VERSION = 0
9 |
10 |
11 | class StatsMessage(object):
12 | def __init__(self, kernel_id, code, execute_type, remote_ip, referer):
13 | self.msg = [LOG_VERSION, remote_ip, referer, execute_type, kernel_id, code]
14 | def __str__(self):
15 | return json.dumps(self.msg)
16 |
17 |
18 | syslog = SysLogHandler(address="/dev/log", facility=SysLogHandler.LOG_LOCAL3)
19 | syslog.setFormatter(logging.Formatter(
20 | "%(asctime)s %(process)5d %(name)-28s %(message)s"))
21 |
22 | # Default logger for SageCell
23 | logger = logging.getLogger("sagecell")
24 | permalink_logger = logger.getChild("permalink")
25 | stats_logger = logger.getChild("stats")
26 | # Intermediate loggers to be parents for actual receivers and kernels.
27 | kernel_logger = logger.getChild("kernel")
28 | provider_logger = logger.getChild("provider")
29 |
30 | root = logging.getLogger()
31 | root.addHandler(syslog)
32 | root.setLevel(LOG_LEVEL)
33 |
34 | class TornadoFilter(logging.Filter):
35 | """
36 | Drop HA-Proxy healthchecks.
37 | """
38 | def filter(self, record):
39 | return len(record.args) != 3 or \
40 | record.args[:2] != (200, 'OPTIONS / (10.0.3.1)')
41 |
42 | logging.getLogger("tornado.access").addFilter(TornadoFilter())
43 |
44 |
45 | class StdLog(object):
46 | """
47 | A file-like object for sending stdout/stderr to a log.
48 | """
49 | def __init__(self, logger, level):
50 | self.logger = logger
51 | self.level = level
52 |
53 | def fileno(self):
54 | return 1
55 |
56 | def flush(self):
57 | pass
58 |
59 | def write(self, data):
60 | self.logger.log(self.level, data)
61 |
62 |
63 | def std_redirect(logger):
64 | """
65 | Redirect stdout and stderr to the given logger.
66 |
67 | Also set their underscore versions to make IPython happier.
68 | """
69 | sys.__stdout__ = sys.stdout = StdLog(
70 | logger.getChild("stdout"), logging.DEBUG)
71 | sys.__stderr__ = sys.stderr = StdLog(
72 | logger.getChild("stderr"), logging.WARNING)
73 |
--------------------------------------------------------------------------------
/js/cell_body.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
16 |
17 |
32 |
33 |
34 |
45 |
46 |
47 |
48 |
49 |
50 | Messages
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/contrib/sphinx/sagecellext.py:
--------------------------------------------------------------------------------
1 | """
2 | Sphinx extension to insert sagecell in sphinx docs.
3 |
4 | Add the following lines to your layout.html file (e.g., in source/_templates)
5 |
6 | ######### BEGIN layout.html ###############
7 | {% extends "!layout.html" %}
8 |
9 | {%- block extrahead %}
10 |
11 |
12 |
13 | {% endblock %}
14 |
15 | ############ END ########################
16 |
17 | Add the directory of this file to the path in conf.py
18 |
19 | import sys, os
20 | sys.path.append(os.path.abspath('path/to/file'))
21 |
22 | Add sagecellext to the list of extensions in conf.py.
23 |
24 | extensions = ['sphinx.ext.mathjax', 'sphinx.ext.graphviz', 'sagecellext']
25 |
26 |
27 | USAGE:
28 | .. sagecell::
29 |
30 | 1+1
31 | print("hello world")
32 |
33 |
34 | """
35 | from docutils import nodes, utils
36 | from docutils.nodes import Body, Element
37 | from docutils.parsers.rst import directives
38 |
39 | from sphinx.util.nodes import set_source_info
40 | from sphinx.util.compat import Directive
41 |
42 | class sagecell(Body, Element):
43 | pass
44 |
45 |
46 | class Sagecell(Directive):
47 |
48 | has_content = True
49 | required_arguments = 0
50 | optional_arguments = 0
51 | final_argument_whitespace = False
52 |
53 |
54 | def run(self):
55 | node = sagecell()
56 | node['code'] = u'\n'.join(self.content)
57 | return [node]
58 |
59 | def html_sagecell(self, node):
60 | """
61 | Convert block to the script here.
62 | """
63 | from uuid import uuid4
64 |
65 | template= """
66 |
67 |
72 | """
73 | self.body.append(template%{'random': uuid4(), 'code': node['code']})
74 | raise nodes.SkipNode
75 |
76 |
77 | def setup(app):
78 | app.add_node(sagecell,
79 | html=(html_sagecell, None))
80 |
81 | app.add_directive('sagecell', Sagecell)
82 |
--------------------------------------------------------------------------------
/js/urls.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 | import sagecell from "./sagecell";
3 |
4 | export const URLs = {};
5 |
6 | /**
7 | * Initialize the important URLs. The root URL derived from one of
8 | * the following locations:
9 | * 1. the variable sagecell.root
10 | * 2. a tag of the form
11 | * 3. the root of the URL of the executing script
12 | */
13 | export function initializeURLs() {
14 | var root;
15 | var el;
16 | if (sagecell.root) {
17 | root = sagecell.root;
18 | } else if ((el = $("link[property=sagecell-root]")).length > 0) {
19 | root = el.last().attr("href");
20 | } else {
21 | /* get the first part of the last script element's src that loaded something called 'embedded_sagecell.js'
22 | also, strip off the static/ part of the url if the src looked like 'static/embedded_sagecell.js'
23 | modified from MathJax source
24 | We could use the jquery reverse plugin at http://www.mail-archive.com/discuss@jquery.com/msg04272.html
25 | and the jquery .each() to get this as well, but this approach avoids creating a reversed list, etc. */
26 | var scripts = (
27 | document.documentElement || document
28 | ).getElementsByTagName("script");
29 | var namePattern = /^.*?(?=(?:static\/)?embedded_sagecell.js)/;
30 | for (var i = scripts.length - 1; i >= 0; i--) {
31 | var m = (scripts[i].src || "").match(namePattern);
32 | if (m) {
33 | root = m[0];
34 | break;
35 | }
36 | }
37 | if (!root || root === "/") {
38 | root = window.location.protocol + "//" + window.location.host + "/";
39 | }
40 | }
41 | if (root.slice(-1) !== "/") {
42 | root += "/";
43 | }
44 | if (root === "http://sagecell.sagemath.org/") {
45 | root = "https://sagecell.sagemath.org/";
46 | }
47 |
48 | Object.assign(URLs, {
49 | cell: root + "sagecell.html",
50 | completion: root + "complete",
51 | help: root + "help.html",
52 | kernel: root + "kernel",
53 | permalink: root + "permalink",
54 | root: root,
55 | sockjs: root + "sockjs",
56 | spinner: root + "static/spinner.gif",
57 | terms: root + "tos.html",
58 | });
59 | }
60 |
--------------------------------------------------------------------------------
/static/fontawesome.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 3.0.2
3 | * the iconic font designed for use with Twitter Bootstrap
4 | * -------------------------------------------------------
5 | * The full suite of pictographic icons, examples, and documentation
6 | * can be found at: http://fortawesome.github.com/Font-Awesome/
7 | *
8 | * License
9 | * -------------------------------------------------------
10 | * - The Font Awesome font is licensed under the SIL Open Font License - http://scripts.sil.org/OFL
11 | * - Font Awesome CSS, LESS, and SASS files are licensed under the MIT License -
12 | * http://opensource.org/licenses/mit-license.html
13 | * - The Font Awesome pictograms are licensed under the CC BY 3.0 License - http://creativecommons.org/licenses/by/3.0/
14 | * - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
15 | * "Font Awesome by Dave Gandy - http://fortawesome.github.com/Font-Awesome"
16 |
17 | * Contact
18 | * -------------------------------------------------------
19 | * Email: dave@davegandy.com
20 | * Twitter: http://twitter.com/fortaweso_me
21 | * Work: Lead Product Designer @ http://kyruus.com
22 | */
23 | @font-face {
24 | font-family: 'FontAwesomeSagecell';
25 | src: url('fontawesome-webfont.eot?v=3.0.1');
26 | src: url('fontawesome-webfont.eot?#iefix&v=3.0.1') format('embedded-opentype'),
27 | url('fontawesome-webfont.woff?v=3.0.1') format('woff'),
28 | url('fontawesome-webfont.ttf?v=3.0.1') format('truetype');
29 | font-weight: normal;
30 | font-style: normal;
31 | }
32 | /* Font Awesome styles
33 | ------------------------------------------------------- */
34 | .sagecell [class^="sagecell_icon-"],
35 | .sagecell [class*=" sagecell_icon-"] {
36 | font-family: FontAwesomeSagecell;
37 | font-weight: normal;
38 | font-style: normal;
39 | text-decoration: inherit;
40 | -webkit-font-smoothing: antialiased;
41 |
42 | font-size: 125%;
43 | background: transparent;
44 | /* sprites.less reset */
45 | display: inline;
46 | width: auto;
47 | height: auto;
48 | line-height: normal;
49 | vertical-align: baseline;
50 | margin-top: 0;
51 | }
52 | .sagecell [class^="sagecell_icon-"]:before,
53 | .sagecell [class*=" sagecell_icon-"]:before {
54 | text-decoration: inherit;
55 | display: inline-block;
56 | speak: none;
57 | }
58 | .sagecell .sagecell_icon-resize-full:before { content: "\f021"; }
59 | .sagecell .sagecell_icon-resize-small:before { content: "\f022"; }
60 |
--------------------------------------------------------------------------------
/contrib/dokuwiki/action.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 |
9 | // must be run within Dokuwiki
10 | if (!defined('DOKU_INC')) die();
11 |
12 | if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
13 | if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14 | if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15 |
16 | require_once DOKU_PLUGIN.'action.php';
17 |
18 | class action_plugin_sagecell extends DokuWiki_Action_Plugin {
19 |
20 | public function register(Doku_Event_Handler &$controller) {
21 |
22 | $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle_tpl_metaheader_output');
23 |
24 | }
25 |
26 | public function handle_tpl_metaheader_output(Doku_Event &$event, $param) {
27 | $url = rtrim($this->getConf('url'), '/');
28 | // Adding js
29 | $event->data["script"][] = array (
30 | "type" => "text/javascript",
31 | "src" => $url . "/static/jquery.min.js",
32 | "_data" => "",
33 | );
34 | $event->data["script"][] = array (
35 | "type" => "text/javascript",
36 | "src" => $url . "/static/embedded_sagecell.js",
37 | "_data" => "",
38 | );
39 | // Initializing cells
40 | $event->data["script"][] = array (
41 | "type" => "text/javascript",
42 | "charset" => "utf-8",
43 | "_data" => "sagecell.makeSagecell({inputLocation: '.sage'});",
44 | );
45 | // Adding stylesheet
46 | $event->data["link"][] = array (
47 | "type" => "text/css",
48 | "rel" => "stylesheet",
49 | "href" => $url . "/static/sagecell_embed.css",
50 | );
51 | $event->data['style'][] = array('type' => 'text/css',
52 | '_data' => $this->getConf('style'));
53 | }
54 |
55 | }
56 |
57 | // vim:ts=4:sw=4:et:
58 |
--------------------------------------------------------------------------------
/templates/info.html:
--------------------------------------------------------------------------------
1 |
About
2 |
3 |
SageMathCell project is an easy-to-use web interface to a free open-source mathematics software system SageMath. You can help SageMath by becoming a .
Unfortunately, we can no longer allow user code in cells to freely access Internet. See this discussion for details.
16 |
17 |
If you experience any problems or have suggestions on improving this service (e.g., you want a package installed), please email Andrey Novoseltsev.
18 |
19 |
SageMathCell is expected to work with any modern browser and without any downtime.
20 |
21 |
22 |
23 |
Need more power and flexibility but still prefer to avoid your own installation of Sage? CoCalc will allow you to work with multiple persistent worksheets in Sage, IPython, LaTeX, and much, much more!