Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e0ce2ea

Browse filesBrowse files
pgbovinemmmicedcoffee
authored andcommitted
added matrix demos
1 parent fa0418b commit e0ce2ea
Copy full SHA for e0ce2ea

File tree

Expand file treeCollapse file tree

8 files changed

+516
-1
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+516
-1
lines changed
Open diff view settings
Collapse file

‎v3/bottle_server.py‎

Copy file name to clipboard
+64Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Lightweight OPT server that works on both Python 2 and 3
2+
3+
# to invoke, run 'python bottle_server.py'
4+
# and visit http://localhost:8080/index.html
5+
#
6+
# external dependencies: bottle
7+
#
8+
# easy_install pip
9+
# pip install bottle
10+
11+
from bottle import route, get, request, run, template, static_file
12+
import cStringIO
13+
import json
14+
import pg_logger
15+
16+
@route('/<filepath:path>')
17+
def index(filepath):
18+
return static_file(filepath, root='.')
19+
20+
@get('/exec')
21+
def get_exec():
22+
out_s = cStringIO.StringIO()
23+
24+
def json_finalizer(input_code, output_trace):
25+
ret = dict(code=input_code, trace=output_trace)
26+
json_output = json.dumps(ret, indent=None)
27+
out_s.write(json_output)
28+
29+
options = json.loads(request.query.options_json)
30+
31+
pg_logger.exec_script_str_local(request.query.user_script,
32+
request.query.raw_input_json,
33+
options['cumulative_mode'],
34+
options['heap_primitives'],
35+
json_finalizer)
36+
37+
return out_s.getvalue()
38+
39+
40+
@get('/load_matrix_problem')
41+
def load_matrix_problem():
42+
prob_name = request.query.problem_name
43+
assert type(prob_name) in (str, unicode)
44+
45+
# whitelist
46+
assert prob_name in ('python_comprehension-1',)
47+
48+
fn = 'matrix-demo/' + prob_name + '.py'
49+
cod = open(fn).read()
50+
51+
import doctest
52+
import sys
53+
p = doctest.DocTestParser()
54+
examples = p.get_examples(cod)
55+
if len(examples):
56+
first_ex = examples[0]
57+
#print >> sys.stderr, 'Source:', `first_ex.source`
58+
testCod = 'result = ' + first_ex.source
59+
60+
return json.dumps(dict(code=cod, test=testCod))
61+
62+
63+
if __name__ == "__main__":
64+
run(host='localhost', port=8080, reloader=True)
Collapse file

‎v3/css/matrixtutor.css‎

Copy file name to clipboard
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* custom CSS for ../matrixtutor.html
2+
3+
always include this file AFTER pytutor.css
4+
*/
5+
6+
#testInputPane {
7+
margin-top: 5px;
8+
font-size: 12pt;
9+
border: 1px solid #ddd;
10+
}
Collapse file

‎v3/js/matrixtutor.js‎

Copy file name to clipboard
+289Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*
2+
3+
Online Python Tutor
4+
https://github.com/pgbovine/OnlinePythonTutor/
5+
6+
Copyright (C) 2010-2013 Philip J. Guo (philip@pgbovine.net)
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a
9+
copy of this software and associated documentation files (the
10+
"Software"), to deal in the Software without restriction, including
11+
without limitation the rights to use, copy, modify, merge, publish,
12+
distribute, sublicense, and/or sell copies of the Software, and to
13+
permit persons to whom the Software is furnished to do so, subject to
14+
the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included
17+
in all copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26+
27+
*/
28+
29+
30+
// custom version of opt-frontend.js for ../matrixtutor.html
31+
32+
33+
// Pre-reqs:
34+
// - pytutor.js
35+
// - jquery.ba-bbq.min.js
36+
// - opt-frontend-common.js
37+
// should all be imported BEFORE this file
38+
39+
40+
var appMode = 'edit'; // 'edit', 'display', or 'display_no_frills'
41+
42+
var preseededCurInstr = null; // if you passed in a 'curInstr=<number>' in the URL, then set this var
43+
44+
var myVisualizer = null; // singleton ExecutionVisualizer instance
45+
46+
47+
function enterEditMode() {
48+
$.bbq.pushState({ mode: 'edit' }, 2 /* completely override other hash strings to keep URL clean */);
49+
}
50+
51+
function enterDisplayNoFrillsMode() {
52+
$.bbq.pushState({ mode: 'display_no_frills' }, 2 /* completely override other hash strings to keep URL clean */);
53+
}
54+
55+
var pyInputCodeMirror; // CodeMirror object that contains the solution code
56+
var pyTestInputCodeMirror; // CodeMirror object that contains the test code
57+
58+
59+
$(document).ready(function() {
60+
61+
$("#embedLinkDiv").hide();
62+
63+
pyInputCodeMirror = CodeMirror(document.getElementById('codeInputPane'), {
64+
mode: 'python',
65+
lineNumbers: true,
66+
tabSize: 4,
67+
indentUnit: 4,
68+
// convert tab into four spaces:
69+
extraKeys: {Tab: function(cm) {cm.replaceSelection(" ", "end");}}
70+
});
71+
pyInputCodeMirror.setSize(null, '300px');
72+
73+
pyTestInputCodeMirror = CodeMirror(document.getElementById('testInputPane'), {
74+
mode: 'python',
75+
lineNumbers: true,
76+
tabSize: 4,
77+
indentUnit: 4,
78+
// convert tab into four spaces:
79+
extraKeys: {Tab: function(cm) {cm.replaceSelection(" ", "end");}}
80+
});
81+
pyTestInputCodeMirror.setSize(null, '100px');
82+
83+
84+
// be friendly to the browser's forward and back buttons
85+
// thanks to http://benalman.com/projects/jquery-bbq-plugin/
86+
$(window).bind("hashchange", function(e) {
87+
appMode = $.bbq.getState('mode'); // assign this to the GLOBAL appMode
88+
89+
if (appMode === undefined || appMode == 'edit') {
90+
$("#pyInputPane").show();
91+
$("#pyOutputPane").hide();
92+
$("#embedLinkDiv").hide();
93+
94+
// destroy all annotation bubbles (NB: kludgy)
95+
if (myVisualizer) {
96+
myVisualizer.destroyAllAnnotationBubbles();
97+
}
98+
}
99+
else if (appMode == 'display') {
100+
$("#pyInputPane").hide();
101+
$("#pyOutputPane").show();
102+
103+
$("#embedLinkDiv").show();
104+
105+
$('#executeBtn').html("Visualize Execution");
106+
$('#executeBtn').attr('disabled', false);
107+
108+
109+
// do this AFTER making #pyOutputPane visible, or else
110+
// jsPlumb connectors won't render properly
111+
myVisualizer.updateOutput();
112+
113+
// customize edit button click functionality AFTER rendering (NB: awkward!)
114+
$('#pyOutputPane #editCodeLinkDiv').show();
115+
$('#pyOutputPane #editBtn').click(function() {
116+
enterEditMode();
117+
});
118+
}
119+
else if (appMode == 'display_no_frills') {
120+
$("#pyInputPane").hide();
121+
$("#pyOutputPane").show();
122+
$("#embedLinkDiv").show();
123+
}
124+
else {
125+
assert(false);
126+
}
127+
128+
$('#urlOutput,#embedCodeOutput').val(''); // clear to avoid stale values
129+
});
130+
131+
132+
function executeCode(inputCod, testCod) {
133+
backend_script = python3_backend_script;
134+
135+
var allCod = inputCod + '\n\n# test code (ungraded)\n' + testCod;
136+
137+
var nCodeLines = inputCod.split('\n').length + 2;
138+
139+
$('#executeBtn').html("Please wait ... processing your code");
140+
$('#executeBtn').attr('disabled', true);
141+
$("#pyOutputPane").hide();
142+
$("#embedLinkDiv").hide();
143+
144+
var backendOptionsObj = {cumulative_mode: ($('#cumulativeModeSelector').val() == 'true'),
145+
heap_primitives: false,
146+
show_only_outputs: false,
147+
py_crazy_mode: false,
148+
origin: 'matrixtutor.js'};
149+
150+
var frontendOptionsObj = {updateOutputCallback: function() {$('#urlOutput,#embedCodeOutput').val('');},
151+
compactFuncLabels: true,
152+
jumpToEnd: true,
153+
}
154+
155+
function handleSuccessFunc() {
156+
// also scroll to top to make the UI more usable on smaller monitors
157+
$(document).scrollTop(0);
158+
159+
$.bbq.pushState({ mode: 'display' }, 2 /* completely override other hash strings to keep URL clean */);
160+
}
161+
162+
function handleUncaughtExceptionFunc(trace) {
163+
if (trace.length == 1) {
164+
var errorLineNo = trace[0].line - 1; /* CodeMirror lines are zero-indexed */
165+
if (errorLineNo !== undefined) {
166+
167+
if (errorLineNo < nCodeLines) {
168+
// highlight the faulting line in pyInputCodeMirror
169+
pyInputCodeMirror.focus();
170+
pyInputCodeMirror.setCursor(errorLineNo, 0);
171+
pyInputCodeMirror.setLineClass(errorLineNo, null, 'errorLine');
172+
173+
pyInputCodeMirror.setOption('onChange', function() {
174+
pyInputCodeMirror.setLineClass(errorLineNo, null, null); // reset line back to normal
175+
pyInputCodeMirror.setOption('onChange', null); // cancel
176+
});
177+
}
178+
else {
179+
console.log('wtf?', errorLineNo, nCodeLines);
180+
// instead highlight the faulting line in pyTestInputCodeMirror
181+
errorLineNo -= nCodeLines;
182+
183+
pyTestInputCodeMirror.focus();
184+
pyTestInputCodeMirror.setCursor(errorLineNo, 0);
185+
pyTestInputCodeMirror.setLineClass(errorLineNo, null, 'errorLine');
186+
187+
pyTestInputCodeMirror.setOption('onChange', function() {
188+
pyTestInputCodeMirror.setLineClass(errorLineNo, null, null);
189+
pyTestInputCodeMirror.setOption('onChange', null); // cancel
190+
});
191+
}
192+
}
193+
194+
$('#executeBtn').html("Visualize Execution");
195+
$('#executeBtn').attr('disabled', false);
196+
}
197+
}
198+
199+
executePythonCode(allCod,
200+
backend_script, backendOptionsObj,
201+
frontendOptionsObj,
202+
'pyOutputPane',
203+
handleSuccessFunc, handleUncaughtExceptionFunc);
204+
}
205+
206+
function executeCodeFromScratch() {
207+
var inputCod = pyInputCodeMirror.getValue();
208+
var testCod = pyTestInputCodeMirror.getValue();
209+
210+
// don't execute empty string:
211+
if (($.trim(inputCod) == '') && ($.trim(testCod) == '')) {
212+
alert('Type in some code to visualize.');
213+
return;
214+
}
215+
216+
executeCode(inputCod, testCod);
217+
}
218+
219+
$("#executeBtn").attr('disabled', false);
220+
$("#executeBtn").click(executeCodeFromScratch);
221+
222+
223+
var queryStrOptions = getQueryStringOptions();
224+
225+
// ugh, ugly tristate due to the possibility of each being undefined
226+
if (queryStrOptions.cumulativeState !== undefined) {
227+
$('#cumulativeModeSelector').val(queryStrOptions.cumulativeState);
228+
}
229+
230+
appMode = $.bbq.getState('mode'); // assign this to the GLOBAL appMode
231+
if ((appMode == "display") && queryStrOptions.preseededCode /* jump to display only with pre-seeded code */) {
232+
preseededCurInstr = queryStrOptions.preseededCurInstr; // ugly global
233+
$("#executeBtn").trigger('click');
234+
}
235+
else {
236+
if (appMode === undefined) {
237+
// default mode is 'edit', don't trigger a "hashchange" event
238+
appMode = 'edit';
239+
}
240+
else {
241+
// fail-soft by killing all passed-in hashes and triggering a "hashchange"
242+
// event, which will then go to 'edit' mode
243+
$.bbq.removeState();
244+
}
245+
}
246+
247+
248+
// log a generic AJAX error handler
249+
$(document).ajaxError(function() {
250+
alert("Server error (possibly due to memory/resource overload). " +
251+
"Report a bug to philip@pgbovine.net\n\n" +
252+
"(Click the 'Generate URL' button to include a unique URL in your email bug report.)");
253+
254+
$('#executeBtn').html("Visualize Execution");
255+
$('#executeBtn').attr('disabled', false);
256+
});
257+
258+
259+
// redraw connector arrows on window resize
260+
$(window).resize(function() {
261+
if (appMode == 'display') {
262+
myVisualizer.redrawConnectors();
263+
}
264+
});
265+
266+
$('#genUrlBtn').bind('click', function() {
267+
var myArgs = {code: pyInputCodeMirror.getValue(),
268+
mode: appMode,
269+
cumulative: $('#cumulativeModeSelector').val(),
270+
py: $('#pythonVersionSelector').val()};
271+
272+
if (appMode == 'display') {
273+
myArgs.curInstr = myVisualizer.curInstr;
274+
}
275+
276+
var urlStr = $.param.fragment(window.location.href, myArgs, 2 /* clobber all */);
277+
$('#urlOutput').val(urlStr);
278+
});
279+
280+
281+
$.get('load_matrix_problem',
282+
{problem_name: 'python_comprehension-1'},
283+
function(dataFromBackend) {
284+
pyInputCodeMirror.setValue(dataFromBackend.code.rtrim());
285+
pyTestInputCodeMirror.setValue(dataFromBackend.test.rtrim());
286+
},
287+
"json");
288+
});
289+
Collapse file

‎v3/js/opt-frontend-common.js‎

Copy file name to clipboardExpand all lines: v3/js/opt-frontend-common.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4343

4444
// uncomment below if you're running on Google App Engine using the built-in app.yaml
4545
var python2_backend_script = 'exec';
46-
var python3_backend_script = null;
46+
var python3_backend_script = 'exec';
4747

4848
// KRAZY experimental KODE!!! Use a custom hacked CPython interpreter
4949
var python2crazy_backend_script = 'web_exec_py2-crazy.py';
Collapse file
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
def increments(L):
2+
'''
3+
Input:
4+
-L: a list of numbers
5+
Output:
6+
- a list where the elements in L were incremented by 1
7+
Example:
8+
>>> increments([1,4,6])
9+
[2,5,7]
10+
'''
11+
pass
Collapse file
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def increments(L): return [1+i for i in L]

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.