Commit 16f0da19 by Piotr Mitros

Merge branch 'master' into pmitros/dexml

parents be1e308d 725cbe14
readline
sqlite
gdbm
pkg-config
gfortran
python
yuicompressor
node
#!/bin/bash
set -e
trap "ouch" ERR
ouch() {
printf '\E[31m'
cat<<EOL
!! ERROR !!
The last command did not complete successfully,
see $LOG for more details or trying running the
script again with the -v flag.
EOL
}
error() {
printf '\E[31m'; echo "$@"; printf '\E[0m'
}
output() {
printf '\E[36m'; echo "$@"; printf '\E[0m'
}
usage() {
cat<<EO
Usage: $PROG [-c] [-v] [-h]
-c compile scipy and numpy
-v set -x + spew
-h this
EO
info
}
info() {
cat<<EO
MITx base dir : $BASE
Python dir : $PYTHON_DIR
Ruby dir : $RUBY_DIR
Ruby ver : $RUBY_VER
EO
}
clone_repos() {
cd "$BASE"
output "Cloning mitx"
if [[ -d "$BASE/mitx" ]]; then
mv "$BASE/mitx" "${BASE}/mitx.bak.$$"
fi
git clone git@github.com:MITx/mitx.git >>$LOG
output "Cloning askbot-devel"
if [[ -d "$BASE/askbot-devel" ]]; then
mv "$BASE/askbot-devel" "${BASE}/askbot-devel.bak.$$"
fi
git clone git@github.com:MITx/askbot-devel >>$LOG
output "Cloning data"
if [[ -d "$BASE/data" ]]; then
mv "$BASE/data" "${BASE}/data.bak.$$"
fi
hg clone ssh://hg-content@gp.mitx.mit.edu/data >>$LOG
}
PROG=${0##*/}
BASE="$HOME/mitx_all"
PYTHON_DIR="$BASE/python"
RUBY_DIR="$BASE/ruby"
RUBY_VER="1.9.3"
NUMPY_VER="1.6.2"
SCIPY_VER="0.10.1"
BREW_FILE="$BASE/mitx/brew-formulas.txt"
LOG="/var/tmp/install.log"
APT_PKGS="curl git mercurial python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor coffeescript"
if [[ $EUID -eq 0 ]]; then
error "This script should not be run using sudo or as the root user"
usage
exit 1
fi
ARGS=$(getopt "cvh" "$*")
if [[ $? != 0 ]]; then
usage
exit 1
fi
eval set -- "$ARGS"
while true; do
case $1 in
-c)
compile=true
shift
;;
-v)
set -x
verbose=true
shift
;;
-h)
usage
exit 0
;;
--)
shift
break
;;
esac
done
cat<<EO
This script will setup a local MITx environment, this
includes
* Django
* A local copy of Python and library dependencies
* A local copy of Ruby and library dependencies
It will also attempt to install operating system dependencies
with apt(debian) or brew(OSx).
To compile scipy and numpy from source use the -c option
STDOUT is redirected to /var/tmp/install.log, run
$ tail -f /var/tmp/install.log
to monitor progress
EO
info
output "Press return to begin or control-C to abort"
read dummy
if [[ -f $HOME/.rvmrc ]]; then
output "$HOME/.rvmrc alredy exists, not adding $RUBY_DIR"
else
output "Creating $HOME/.rmrc so rvm uses $RUBY_DIR"
echo "export rvm_path=$RUBY_DIR" > $HOME/.rvmrc
fi
mkdir -p $BASE
rm -f $LOG
case `uname -s` in
[Ll]inux)
command -v lsb_release &>/dev/null || {
error "Please install lsb-release."
exit 1
}
distro=`lsb_release -cs`
case $distro in
lisa|natty|oneiric|precise)
output "Installing ubuntu requirements"
sudo apt-get -y update
sudo apt-get -y install $APT_PKGS
clone_repos
;;
*)
error "Unsupported distribution - $distro"
exit 1
;;
esac
;;
Darwin)
command -v brew &>/dev/null || {
output "Installing brew"
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"
}
command -v git &>/dev/null || {
output "Installing git"
brew install git >> $LOG
}
command -v hg &>/dev/null || {
output "Installaing mercurial"
brew install mercurial >> $LOG
}
clone_repos
output "Installing OSX requirements"
if [[ ! -r $BREW_FILE ]]; then
error "$BREW_FILE does not exist, needed to install brew deps"
exit 1
fi
# brew errors if the package is already installed
for pkg in $(cat $BREW_FILE); do
grep $pkg <(brew list) &>/dev/null || {
output "Installing $pkg"
brew install $pkg >>$LOG
}
done
command -v pip &>/dev/null || {
output "Installing pip"
sudo easy_install pip >>$LOG
}
command -v virtualenv &>/dev/null || {
output "Installing virtualenv"
sudo pip install virtualenv virtualenvwrapper >> $LOG
}
command -v coffee &>/dev/null || {
output "Installing coffee script"
curl http://npmjs.org/install.sh | sh
npm install -g coffee-script
}
;;
*)
error "Unsupported platform"
exit 1
;;
esac
output "Installing rvm and ruby"
curl -sL get.rvm.io | bash -s stable
source $RUBY_DIR/scripts/rvm
rvm install $RUBY_VER
virtualenv "$PYTHON_DIR"
source $PYTHON_DIR/bin/activate
output "Installing gem bundler"
gem install bundler
output "Installing ruby packages"
# hack :(
cd $BASE/mitx || true
bundle install
cd $BASE
if [[ -n $compile ]]; then
output "Downloading numpy and scipy"
curl -sL -o numpy.tar.gz http://downloads.sourceforge.net/project/numpy/NumPy/${NUMPY_VER}/numpy-${NUMPY_VER}.tar.gz
curl -sL -o scipy.tar.gz http://downloads.sourceforge.net/project/scipy/scipy/${SCIPY_VER}/scipy-${SCIPY_VER}.tar.gz
tar xf numpy.tar.gz
tar xf scipy.tar.gz
rm -f numpy.tar.gz scipy.tar.gz
output "Compiling numpy"
cd "$BASE/numpy-${NUMPY_VER}"
python setup.py install >>$LOG 2>&1
output "Compiling scipy"
cd "$BASE/scipy-${SCIPY_VER}"
python setup.py install >>$LOG 2>&1
cd "$BASE"
rm -rf numpy-${NUMPY_VER} scipy-${SCIPY_VER}
fi
output "Installing askbot requirements"
pip install -r askbot-devel/askbot_requirements.txt >>$LOG
pip install -r askbot-devel/askbot_requirements_dev.txt >>$LOG
output "Installing MITx requirements"
pip install -r mitx/pre-requirements.txt >> $LOG
pip install -r mitx/requirements.txt >>$LOG
mkdir "$BASE/log" || true
mkdir "$BASE/db" || true
cat<<END
Success!!
To start using Django you will need
to activate the local Python and Ruby
environment:
$ source $RUBY_DIR/scripts/rvm
$ source $PYTHON_DIR/bin/activate
To initialize and start a local instance of Django:
$ cd $BASE/mitx
$ django-admin.py syncdb --settings=envs.dev --pythonpath=.
$ django-admin.py migrate --settings=envs.dev --pythonpath=.
$ django-admin.py runserver --settings=envs.dev --pythonpath=.
END
exit 0
...@@ -91,7 +91,7 @@ class LoncapaProblem(object): ...@@ -91,7 +91,7 @@ class LoncapaProblem(object):
self.problem_id = id self.problem_id = id
self.system = system self.system = system
if seed != None: if seed is not None:
self.seed = seed self.seed = seed
if state: if state:
......
...@@ -133,7 +133,7 @@ class SimpleInput():# XModule ...@@ -133,7 +133,7 @@ class SimpleInput():# XModule
def register_render_function(fn, names=None, cls=SimpleInput): def register_render_function(fn, names=None, cls=SimpleInput):
if names == None: if names is None:
SimpleInput.xml_tags[fn.__name__] = fn SimpleInput.xml_tags[fn.__name__] = fn
else: else:
raise NotImplementedError raise NotImplementedError
......
...@@ -109,7 +109,7 @@ class MultipleChoiceResponse(GenericResponse): ...@@ -109,7 +109,7 @@ class MultipleChoiceResponse(GenericResponse):
if rtype not in ["MultipleChoice"]: if rtype not in ["MultipleChoice"]:
response.set("type", "MultipleChoice") # force choicegroup to be MultipleChoice if not valid response.set("type", "MultipleChoice") # force choicegroup to be MultipleChoice if not valid
for choice in list(response): for choice in list(response):
if choice.get("name") == None: if choice.get("name") is None:
choice.set("name", "choice_"+str(i)) choice.set("name", "choice_"+str(i))
i+=1 i+=1
else: else:
...@@ -121,7 +121,7 @@ class TrueFalseResponse(MultipleChoiceResponse): ...@@ -121,7 +121,7 @@ class TrueFalseResponse(MultipleChoiceResponse):
for response in self.xml.xpath("choicegroup"): for response in self.xml.xpath("choicegroup"):
response.set("type", "TrueFalse") response.set("type", "TrueFalse")
for choice in list(response): for choice in list(response):
if choice.get("name") == None: if choice.get("name") is None:
choice.set("name", "choice_"+str(i)) choice.set("name", "choice_"+str(i))
i+=1 i+=1
else: else:
...@@ -292,7 +292,7 @@ def sympy_check2(): ...@@ -292,7 +292,7 @@ def sympy_check2():
self.code = '' self.code = ''
else: else:
answer_src = answer.get('src') answer_src = answer.get('src')
if answer_src != None: if answer_src is not None:
self.code = open(settings.DATA_DIR+'src/'+answer_src).read() self.code = open(settings.DATA_DIR+'src/'+answer_src).read()
else: else:
self.code = answer.text self.code = answer.text
...@@ -418,7 +418,7 @@ class ExternalResponse(GenericResponse): ...@@ -418,7 +418,7 @@ class ExternalResponse(GenericResponse):
id=xml.get('id'))[0] id=xml.get('id'))[0]
answer_src = answer.get('src') answer_src = answer.get('src')
if answer_src != None: if answer_src is not None:
self.code = open(settings.DATA_DIR+'src/'+answer_src).read() self.code = open(settings.DATA_DIR+'src/'+answer_src).read()
else: else:
self.code = answer.text self.code = answer.text
...@@ -489,7 +489,7 @@ class FormulaResponse(GenericResponse): ...@@ -489,7 +489,7 @@ class FormulaResponse(GenericResponse):
self.context = context self.context = context
ts = xml.get('type') ts = xml.get('type')
if ts == None: if ts is None:
typeslist = [] typeslist = []
else: else:
typeslist = ts.split(',') typeslist = ts.split(',')
...@@ -558,7 +558,7 @@ class SchematicResponse(GenericResponse): ...@@ -558,7 +558,7 @@ class SchematicResponse(GenericResponse):
answer = xml.xpath('//*[@id=$id]//answer', answer = xml.xpath('//*[@id=$id]//answer',
id=xml.get('id'))[0] id=xml.get('id'))[0]
answer_src = answer.get('src') answer_src = answer.get('src')
if answer_src != None: if answer_src is not None:
self.code = self.system.filestore.open('src/'+answer_src).read() # Untested; never used self.code = self.system.filestore.open('src/'+answer_src).read() # Untested; never used
else: else:
self.code = answer.text self.code = answer.text
......
...@@ -126,7 +126,7 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None): ...@@ -126,7 +126,7 @@ def propogate_downward_tag(element, attribute_name, parent_attribute = None):
child (A) already has that attribute, A will keep the same attribute and child (A) already has that attribute, A will keep the same attribute and
all of A's children will inherit A's attribute. This is a recursive call.''' all of A's children will inherit A's attribute. This is a recursive call.'''
if (parent_attribute == None): #This is the entry call. Select all elements with this attribute if (parent_attribute is None): #This is the entry call. Select all elements with this attribute
all_attributed_elements = element.xpath("//*[@" + attribute_name +"]") all_attributed_elements = element.xpath("//*[@" + attribute_name +"]")
for attributed_element in all_attributed_elements: for attributed_element in all_attributed_elements:
attribute_value = attributed_element.get(attribute_name) attribute_value = attributed_element.get(attribute_name)
......
...@@ -190,7 +190,7 @@ def get_score(user, problem, cache, coursename=None): ...@@ -190,7 +190,7 @@ def get_score(user, problem, cache, coursename=None):
correct=float(response.grade) correct=float(response.grade)
# Grab max grade from cache, or if it doesn't exist, compute and save to DB # Grab max grade from cache, or if it doesn't exist, compute and save to DB
if id in cache and response.max_grade != None: if id in cache and response.max_grade is not None:
total = response.max_grade total = response.max_grade
else: else:
## HACK 1: We shouldn't specifically reference capa_module ## HACK 1: We shouldn't specifically reference capa_module
......
...@@ -76,7 +76,7 @@ def grade_histogram(module_id): ...@@ -76,7 +76,7 @@ def grade_histogram(module_id):
grades = list(cursor.fetchall()) grades = list(cursor.fetchall())
grades.sort(key=lambda x:x[0]) # Probably not necessary grades.sort(key=lambda x:x[0]) # Probably not necessary
if (len(grades) == 1 and grades[0][0] == None): if (len(grades) == 1 and grades[0][0] is None):
return [] return []
return grades return grades
......
...@@ -100,7 +100,7 @@ class Module(XModule): ...@@ -100,7 +100,7 @@ class Module(XModule):
reset_button = False reset_button = False
# We don't need a "save" button if infinite number of attempts and non-randomized # We don't need a "save" button if infinite number of attempts and non-randomized
if self.max_attempts == None and self.rerandomize != "always": if self.max_attempts is None and self.rerandomize != "always":
save_button = False save_button = False
# Check if explanation is available, and if so, give a link # Check if explanation is available, and if so, give a link
...@@ -225,7 +225,7 @@ class Module(XModule): ...@@ -225,7 +225,7 @@ class Module(XModule):
''' Is the student still allowed to submit answers? ''' ''' Is the student still allowed to submit answers? '''
if self.attempts == self.max_attempts: if self.attempts == self.max_attempts:
return True return True
if self.close_date != None and datetime.datetime.utcnow() > self.close_date: if self.close_date is not None and datetime.datetime.utcnow() > self.close_date:
return True return True
return False return False
......
...@@ -52,7 +52,7 @@ class Module(XModule): ...@@ -52,7 +52,7 @@ class Module(XModule):
## Returns a set of all types of all sub-children ## Returns a set of all types of all sub-children
child_classes = [set([i.tag for i in e.iter()]) for e in self.xmltree] child_classes = [set([i.tag for i in e.iter()]) for e in self.xmltree]
titles = ["\n".join([i.get("name").strip() for i in e.iter() if i.get("name") != None]) \ titles = ["\n".join([i.get("name").strip() for i in e.iter() if i.get("name") is not None]) \
for e in self.xmltree] for e in self.xmltree]
self.contents = self.rendered_children() self.contents = self.rendered_children()
...@@ -86,7 +86,7 @@ class Module(XModule): ...@@ -86,7 +86,7 @@ class Module(XModule):
self.position = 1 self.position = 1
if state != None: if state is not None:
state = json.loads(state) state = json.loads(state)
if 'position' in state: self.position = int(state['position']) if 'position' in state: self.position = int(state['position'])
......
...@@ -50,7 +50,7 @@ class Module(XModule): ...@@ -50,7 +50,7 @@ class Module(XModule):
self.youtube = xmltree.get('youtube') self.youtube = xmltree.get('youtube')
self.name = xmltree.get('name') self.name = xmltree.get('name')
self.position = 0 self.position = 0
if state != None: if state is not None:
state = json.loads(state) state = json.loads(state)
if 'position' in state: if 'position' in state:
self.position = int(float(state['position'])) self.position = int(float(state['position']))
......
...@@ -57,7 +57,7 @@ def profile(request, student_id = None): ...@@ -57,7 +57,7 @@ def profile(request, student_id = None):
''' User profile. Show username, location, etc, as well as grades . ''' User profile. Show username, location, etc, as well as grades .
We need to allow the user to change some of these settings .''' We need to allow the user to change some of these settings .'''
if student_id == None: if student_id is None:
student = request.user student = request.user
else: else:
if 'course_admin' not in content_parser.user_groups(request.user): if 'course_admin' not in content_parser.user_groups(request.user):
...@@ -194,7 +194,7 @@ def index(request, course=None, chapter="Using the System", section="Hints"): ...@@ -194,7 +194,7 @@ def index(request, course=None, chapter="Using the System", section="Hints"):
else: else:
module_wrapper = dom_module[0] module_wrapper = dom_module[0]
if module_wrapper == None: if module_wrapper is None:
module = None module = None
elif module_wrapper.get("src"): elif module_wrapper.get("src"):
module = content_parser.section_file(user=user, section=module_wrapper.get("src"), coursename=course) module = content_parser.section_file(user=user, section=module_wrapper.get("src"), coursename=course)
...@@ -202,7 +202,7 @@ def index(request, course=None, chapter="Using the System", section="Hints"): ...@@ -202,7 +202,7 @@ def index(request, course=None, chapter="Using the System", section="Hints"):
module = etree.XML(etree.tostring(module_wrapper[0])) # Copy the element out of the tree module = etree.XML(etree.tostring(module_wrapper[0])) # Copy the element out of the tree
module_ids = [] module_ids = []
if module: if module is not None:
module_ids = module.xpath("//@id", module_ids = module.xpath("//@id",
course=course, chapter=chapter, section=section) course=course, chapter=chapter, section=section)
......
...@@ -482,7 +482,7 @@ def check_permissions(request, article, check_read=False, check_write=False, che ...@@ -482,7 +482,7 @@ def check_permissions(request, article, check_read=False, check_write=False, che
locked_err = check_locked and article.locked locked_err = check_locked and article.locked
if revision == None: if revision is None:
revision = article.current_revision revision = article.current_revision
deleted_err = check_deleted and not (revision.deleted == 0) deleted_err = check_deleted and not (revision.deleted == 0)
if (request.user.is_superuser): if (request.user.is_superuser):
......
This document describes how to set up the MITx development environment
for both Linux (Ubuntu) and MacOS (OSX Lion).
There is also a script "create-dev-env.sh" that automates these steps.
1) Make an mitx_all directory and clone the repos
(download and install git and mercurial if you don't have them already)
mkdir ~/mitx_all
cd ~/mitx_all
git clone git@github.com:MITx/mitx.git
git clone git@github.com:MITx/askbot-devel
hg clone ssh://hg-content@gp.mitx.mit.edu/data
2) Install OSX dependencies (Mac users only)
a) Install the brew utility if necessary
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"
b) Install the brew package list
cat ~/mitx_all/mitx/brew-formulas.txt | xargs brew install
c) Install python pip if necessary
sudo easy_install pip
d) Install python virtualenv if necessary
sudo pip install virtualenv virtualenvwrapper
e) Install coffee script
curl http://npmjs.org/install.sh | sh
npm install -g coffee-script
3) Install Ubuntu dependencies (Linux users only)
sudo apt-get install curl python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor coffeescript
4) Install rvm, ruby, and libraries
echo "export rvm_path=$HOME/mitx_all/ruby" > $HOME/.rvmrc
curl -sL get.rvm.io | bash -s stable
source ~/mitx_all/ruby/scripts/rvm
rvm install 1.9.3
gem install bundler
cd ~/mitx_all/mitx
bundle install
5) Install python libraries
source ~/mitx_all/python/bin/activate
cd ~/mitx_all
pip install -r askbot-devel/askbot_requirements.txt
pip install -r askbot-devel/askbot_requirements_dev.txt
pip install -r mitx/pre-requirements.txt
pip install -r mitx/requirements.txt
6) Create log and db dirs
mkdir ~/mitx_all/log
mkdir ~/mitx_all/db
7) Start the dev server
To start using Django you will need
to activate the local Python and Ruby
environment:
$ source ~/mitx_all/ruby/scripts/rvm
$ source ~/mitx_all/python/bin/activate
To initialize and start a local instance of Django:
$ cd ~/mitx_all/mitx
$ django-admin.py syncdb --settings=envs.dev --pythonpath=.
$ django-admin.py migrate --settings=envs.dev --pythonpath=.
$ django-admin.py runserver --settings=envs.dev --pythonpath=.
...@@ -126,6 +126,14 @@ describe 'VideoPlayer', -> ...@@ -126,6 +126,14 @@ describe 'VideoPlayer', ->
it 'trigger pause event', -> it 'trigger pause event', ->
expect('pause').toHaveBeenTriggeredOn @player expect('pause').toHaveBeenTriggeredOn @player
describe 'when the video is unstarted', ->
beforeEach ->
spyOnEvent @player, 'pause'
@player.onStateChange data: YT.PlayerState.UNSTARTED
it 'trigger pause event', ->
expect('pause').toHaveBeenTriggeredOn @player
describe 'when the video is ended', -> describe 'when the video is ended', ->
beforeEach -> beforeEach ->
spyOnEvent @player, 'ended' spyOnEvent @player, 'ended'
......
...@@ -12,6 +12,8 @@ $ -> ...@@ -12,6 +12,8 @@ $ ->
window.onTouchBasedDevice = -> window.onTouchBasedDevice = ->
navigator.userAgent.match /iPhone|iPod|iPad/i navigator.userAgent.match /iPhone|iPod|iPad/i
$('body').addClass 'touch-based-device' if onTouchBasedDevice()
$("a[rel*=leanModal]").leanModal() $("a[rel*=leanModal]").leanModal()
$('#csrfmiddlewaretoken').attr 'value', $.cookie('csrftoken') $('#csrfmiddlewaretoken').attr 'value', $.cookie('csrftoken')
......
class @VideoPlayer class @VideoPlayer
constructor: (@video) -> constructor: (@video) ->
# Define a missing constant of Youtube API
YT.PlayerState.UNSTARTED = -1
@currentTime = 0 @currentTime = 0
@element = $("#video_#{@video.id}") @element = $("#video_#{@video.id}")
@render() @render()
...@@ -57,7 +60,7 @@ class @VideoPlayer ...@@ -57,7 +60,7 @@ class @VideoPlayer
switch event.data switch event.data
when YT.PlayerState.PLAYING when YT.PlayerState.PLAYING
$(@).trigger('play') $(@).trigger('play')
when YT.PlayerState.PAUSED when YT.PlayerState.PAUSED, YT.PlayerState.UNSTARTED
$(@).trigger('pause') $(@).trigger('pause')
when YT.PlayerState.ENDED when YT.PlayerState.ENDED
$(@).trigger('ended') $(@).trigger('ended')
......
...@@ -10,7 +10,9 @@ class @VideoSpeedControl ...@@ -10,7 +10,9 @@ class @VideoSpeedControl
$(@player).bind('speedChange', @onSpeedChange) $(@player).bind('speedChange', @onSpeedChange)
@$('.video_speeds a').click @changeVideoSpeed @$('.video_speeds a').click @changeVideoSpeed
if onTouchBasedDevice() if onTouchBasedDevice()
@$('.speeds').click -> $(this).toggleClass('open') @$('.speeds').click (event) ->
event.preventDefault()
$(this).toggleClass('open')
else else
@$('.speeds').mouseenter -> @$('.speeds').mouseenter ->
$(this).addClass('open') $(this).addClass('open')
......
...@@ -123,7 +123,7 @@ nav.sequence-nav { ...@@ -123,7 +123,7 @@ nav.sequence-nav {
background-position: center; background-position: center;
} }
p { p {
background: #333; background: #333;
color: #fff; color: #fff;
display: none; display: none;
...@@ -231,6 +231,10 @@ nav.sequence-nav { ...@@ -231,6 +231,10 @@ nav.sequence-nav {
} }
} }
} }
body.touch-based-device & ol li a:hover p {
display: none;
}
} }
...@@ -304,3 +308,4 @@ section.course-content { ...@@ -304,3 +308,4 @@ section.course-content {
} }
} }
} }
% if name is not UNDEFINED and name != None: % if name is not UNDEFINED and name is not None:
<h1> ${name} </h1> <h1> ${name} </h1>
% endif % endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment