Commit 66a01957 by Bridger Maxwell

Merged in stable.

parents 1df5fa19 ca4c73a9
......@@ -78,17 +78,23 @@ def evaluator(variables, functions, string, cs=False):
# log.debug("functions: {0}".format(functions))
# log.debug("string: {0}".format(string))
def lower_dict(d):
return dict([(k.lower(), d[k]) for k in d])
all_variables = copy.copy(default_variables)
all_variables.update(variables)
all_functions = copy.copy(default_functions)
if not cs:
all_variables = lower_dict(all_variables)
all_functions = lower_dict(all_functions)
all_variables.update(variables)
all_functions.update(functions)
if not cs:
string_cs = string.lower()
for v in all_variables.keys():
all_variables[v.lower()]=all_variables[v]
for f in all_functions.keys():
all_functions[f.lower()]=all_functions[f]
all_functions = lower_dict(all_functions)
all_variables = lower_dict(all_variables)
CasedLiteral = CaselessLiteral
else:
string_cs = string
......
......@@ -35,6 +35,11 @@ class ModelsTest(unittest.TestCase):
self.assertTrue(abs(calc.evaluator(variables, functions, "k*T/q-0.025"))<0.001)
self.assertTrue(abs(calc.evaluator(variables, functions, "e^(j*pi)")+1)<0.00001)
self.assertTrue(abs(calc.evaluator(variables, functions, "j||1")-0.5-0.5j)<0.00001)
variables['t'] = 1.0
self.assertTrue(abs(calc.evaluator(variables, functions, "t")-1.0)<0.00001)
self.assertTrue(abs(calc.evaluator(variables, functions, "T")-1.0)<0.00001)
self.assertTrue(abs(calc.evaluator(variables, functions, "t", cs=True)-1.0)<0.00001)
self.assertTrue(abs(calc.evaluator(variables, functions, "T", cs=True)-298)<0.2)
exception_happened = False
try:
calc.evaluator({},{}, "5+7 QWSEKO")
......
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^$', 'heartbeat.views.heartbeat', name='heartbeat'),
)
import json
from datetime import datetime
from django.http import HttpResponse
def heartbeat(request):
"""
Simple view that a loadbalancer can check to verify that the app is up
"""
output = {
'date': datetime.now().isoformat()
}
return HttpResponse(json.dumps(output, indent=4))
......@@ -24,7 +24,7 @@ from django_future.csrf import ensure_csrf_cookie
from models import Registration, UserProfile, PendingNameChange, PendingEmailChange
log = logging.getLogger("mitx.user")
log = logging.getLogger("mitx.student")
def csrf_token(context):
''' A csrf token that can be included in a form.
......
Transitional for moving to new settings scheme.
To use:
django-admin.py runserver --settings=envs.dev --pythonpath=.
NOTE: Using manage.py will automatically run mitx/settings.py first, regardless
of what you send it for an explicit --settings flag. It still works, but might
have odd side effects. Using django-admin.py avoids that problem.
django-admin.py is installed by default when you install Django.
To use with gunicorn_django in debug mode:
gunicorn_django envs/dev.py
# askbot livesettings
"""
There are other askbot settings in common.py that covers things like where the
templates are located, etc. This file is purely for askbot forum *behavior*.
This means things like karma limits, the ability to post questions as wikis,
anonymous questions, etc.
"""
LIVESETTINGS_OPTIONS = {
1: {
'DB' : False,
......@@ -88,9 +94,9 @@ LIVESETTINGS_OPTIONS = {
'MIN_TITLE_LENGTH' : 1,
'MIN_QUESTION_BODY_LENGTH' : 1,
'MIN_ANSWER_BODY_LENGTH' : 1,
'WIKI_ON' : True,
'WIKI_ON' : False,
'ALLOW_ASK_ANONYMOUSLY' : True,
'ALLOW_POSTING_BEFORE_LOGGING_IN' : True,
'ALLOW_POSTING_BEFORE_LOGGING_IN' : False,
'ALLOW_SWAPPING_QUESTION_WITH_ANSWER' : False,
'MAX_TAG_LENGTH' : 20,
'MIN_TITLE_LENGTH' : 1,
......@@ -172,8 +178,8 @@ LIVESETTINGS_OPTIONS = {
},
'MARKUP' : {
'MARKUP_CODE_FRIENDLY' : False,
'ENABLE_MATHJAX' : False, # FIXME: Test with this enabled
'MATHJAX_BASE_URL' : u'',
'ENABLE_MATHJAX' : True,
'MATHJAX_BASE_URL' : u'/static/js/mathjax-MathJax-c9db6ac/',
'ENABLE_AUTO_LINKING' : False,
'AUTO_LINK_PATTERNS' : u'',
'AUTO_LINK_URLS' : u'',
......@@ -181,21 +187,21 @@ LIVESETTINGS_OPTIONS = {
'MIN_REP' : {
'MIN_REP_TO_ACCEPT_OWN_ANSWER' : 1,
'MIN_REP_TO_ANSWER_OWN_QUESTION' : 1,
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 100,
'MIN_REP_TO_CLOSE_OTHERS_QUESTIONS' : 1200,
'MIN_REP_TO_CLOSE_OWN_QUESTIONS' : 1,
'MIN_REP_TO_DELETE_OTHERS_COMMENTS' : 2000,
'MIN_REP_TO_DELETE_OTHERS_POSTS' : 5000,
'MIN_REP_TO_EDIT_OTHERS_POSTS' : 2000,
'MIN_REP_TO_EDIT_WIKI' : 1,
'MIN_REP_TO_DELETE_OTHERS_COMMENTS' : 5000,
'MIN_REP_TO_DELETE_OTHERS_POSTS' : 10000,
'MIN_REP_TO_EDIT_OTHERS_POSTS' : 5000,
'MIN_REP_TO_EDIT_WIKI' : 200,
'MIN_REP_TO_FLAG_OFFENSIVE' : 1,
'MIN_REP_TO_HAVE_STRONG_URL' : 250,
'MIN_REP_TO_LEAVE_COMMENTS' : 1,
'MIN_REP_TO_LOCK_POSTS' : 4000,
'MIN_REP_TO_LOCK_POSTS' : 10000,
'MIN_REP_TO_REOPEN_OWN_QUESTIONS' : 1,
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 1,
'MIN_REP_TO_RETAG_OTHERS_QUESTIONS' : 100,
'MIN_REP_TO_UPLOAD_FILES' : 1,
'MIN_REP_TO_VIEW_OFFENSIVE_FLAGS' : 2000,
'MIN_REP_TO_VOTE_DOWN' : 1,
'MIN_REP_TO_VOTE_DOWN' : 15,
'MIN_REP_TO_VOTE_UP' : 1,
},
'QA_SITE_SETTINGS' : {
......@@ -275,7 +281,7 @@ LIVESETTINGS_OPTIONS = {
'VOTE_RULES' : {
'MAX_VOTES_PER_USER_PER_DAY' : 30,
'MAX_FLAGS_PER_USER_PER_DAY' : 5,
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 7,
'MIN_DAYS_FOR_STAFF_TO_ACCEPT_ANSWER' : 0,
'MIN_DAYS_TO_ANSWER_OWN_QUESTION' : 0,
'MIN_FLAGS_TO_DELETE_POST' : 5,
'MIN_FLAGS_TO_HIDE_POST' : 3,
......@@ -284,4 +290,4 @@ LIVESETTINGS_OPTIONS = {
},
},
},
}
}
\ No newline at end of file
"""
This is the default template for our main set of AWS servers. This does NOT
cover the content machines, which use content.py
Common traits:
* Use memcached, and cache-backed sessions
* Use a MySQL 5.1 database
"""
import json
from common import *
############################### ALWAYS THE SAME ################################
DEBUG = False
TEMPLATE_DEBUG = False
EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
########################### NON-SECURE ENV CONFIG ##############################
# Things like server locations, ports, etc.
with open(ENV_ROOT / "env.json") as env_file:
ENV_TOKENS = json.load(env_file)
SITE_NAME = ENV_TOKENS['SITE_NAME']
CSRF_COOKIE_DOMAIN = ENV_TOKENS['CSRF_COOKIE_DOMAIN']
BOOK_URL = ENV_TOKENS['BOOK_URL']
MEDIA_URL = ENV_TOKENS['MEDIA_URL']
LOG_DIR = ENV_TOKENS['LOG_DIR']
CACHES = ENV_TOKENS['CACHES']
LOGGING = logsettings.get_logger_config(LOG_DIR,
logging_env=ENV_TOKENS['LOGGING_ENV'],
syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
debug=False)
############################## SECURE AUTH ITEMS ###############################
# Secret things: passwords, access keys, etc.
with open(ENV_ROOT / "auth.json") as auth_file:
AUTH_TOKENS = json.load(auth_file)
SECRET_KEY = AUTH_TOKENS['SECRET_KEY']
AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
DATABASES = AUTH_TOKENS['DATABASES']
\ No newline at end of file
"""
These are debug machines used for content creators, so they're kind of a cross
between dev machines and AWS machines.
"""
from aws import *
DEBUG = True
TEMPLATE_DEBUG = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
################################ DEBUG TOOLBAR #################################
INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
DEBUG_TOOLBAR_PANELS = (
'debug_toolbar.panels.version.VersionDebugPanel',
'debug_toolbar.panels.timer.TimerDebugPanel',
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
'debug_toolbar.panels.headers.HeaderDebugPanel',
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
# Enabling the profiler has a weird bug as of django-debug-toolbar==0.9.4 and
# Django=1.3.1/1.4 where requests to views get duplicated (your method gets
# hit twice). So you can uncomment when you need to diagnose performance
# problems, but you shouldn't leave it on.
# 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
)
"""
This config file runs the simplest dev environment using sqlite, and db-based
sessions. Assumes structure:
/envroot/
/db # This is where it'll write the database file
/mitx # The location of this repo
/log # Where we're going to write log files
"""
from common import *
DEBUG = True
TEMPLATE_DEBUG = True
LOGGING = logsettings.get_logger_config(ENV_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
debug=True)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ENV_ROOT / "db" / "mitx.db",
}
}
CACHES = {
# This is the cache used for most things. Askbot will not work without a
# functioning cache -- it relies on caching to load its settings in places.
# In staging/prod envs, the sessions also live here.
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'mitx_loc_mem_cache'
},
# The general cache is what you get if you use our util.cache. It's used for
# things like caching the course.xml file for different A/B test groups.
# We set it to be a DummyCache to force reloading of course.xml in dev.
# In staging environments, we would grab VERSION from data uploaded by the
# push process.
'general': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'KEY_PREFIX': 'general',
'VERSION': 4,
}
}
# Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
################################ DEBUG TOOLBAR #################################
INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
INTERNAL_IPS = ('127.0.0.1',)
DEBUG_TOOLBAR_PANELS = (
'debug_toolbar.panels.version.VersionDebugPanel',
'debug_toolbar.panels.timer.TimerDebugPanel',
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
'debug_toolbar.panels.headers.HeaderDebugPanel',
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
# Enabling the profiler has a weird bug as of django-debug-toolbar==0.9.4 and
# Django=1.3.1/1.4 where requests to views get duplicated (your method gets
# hit twice). So you can uncomment when you need to diagnose performance
# problems, but you shouldn't leave it on.
# 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
)
############################ FILE UPLOADS (ASKBOT) #############################
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
MEDIA_ROOT = ENV_ROOT / "uploads"
MEDIA_URL = "/static/uploads/"
STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads"
FILE_UPLOAD_HANDLERS = (
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
)
"""
This config file tries to mimic the production environment more closely than the
normal dev.py. It assumes you're running a local instance of MySQL 5.1 and that
you're running memcached. You'll want to use this to test caching and database
migrations.
Assumptions:
* MySQL 5.1 (version important -- askbot breaks on 5.5)
Dir structure:
/envroot/
/mitx # The location of this repo
/log # Where we're going to write log files
"""
from dev import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'wwc',
'USER': 'root',
'PASSWORD': '',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
},
'general': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'KEY_PREFIX' : 'general',
'VERSION' : 5,
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
import os
import os.path
import platform
import sys
def get_logger_config(log_dir,
logging_env="no_env",
tracking_filename=None,
syslog_addr=None,
debug=False):
"""Return the appropriate logging config dictionary. You should assign the
result of this to the LOGGING var in your settings. The reason it's done
this way instead of registering directly is because I didn't want to worry
about resetting the logging state if this is called multiple times when
settings are extended."""
# If we're given an explicit place to put tracking logs, we do that (say for
# debugging). However, logging is not safe for multiple processes hitting
# the same file. So if it's left blank, we dynamically create the filename
# based on the PID of this worker process.
if tracking_filename:
tracking_file_loc = os.path.join(log_dir, tracking_filename)
else:
pid = os.getpid() # So we can log which process is creating the log
tracking_file_loc = os.path.join(log_dir, "tracking_{0}.log".format(pid))
hostname = platform.node().split(".")[0]
syslog_format = ("[%(name)s][env:{logging_env}] %(levelname)s [{hostname} " +
" %(process)d] [%(filename)s:%(lineno)d] - %(message)s").format(
logging_env=logging_env, hostname=hostname)
handlers = ['console'] if debug else ['console', 'syslogger']
return {
'version': 1,
'disable_existing_loggers': True,
'formatters' : {
'standard' : {
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
},
'syslog_format' : { 'format' : syslog_format },
'raw' : { 'format' : '%(message)s' },
},
'handlers' : {
'console' : {
'level' : 'DEBUG' if debug else 'INFO',
'class' : 'logging.StreamHandler',
'formatter' : 'standard',
'stream' : sys.stdout,
},
'syslogger' : {
'level' : 'INFO',
'class' : 'logging.handlers.SysLogHandler',
'address' : syslog_addr,
'formatter' : 'syslog_format',
},
'tracking' : {
'level' : 'DEBUG',
'class' : 'logging.handlers.WatchedFileHandler',
'filename' : tracking_file_loc,
'formatter' : 'raw',
},
},
'loggers' : {
'django' : {
'handlers' : handlers,
'propagate' : True,
'level' : 'INFO'
},
'tracking' : {
'handlers' : ['tracking'],
'level' : 'DEBUG',
'propagate' : False,
},
'root' : {
'handlers' : handlers,
'level' : 'DEBUG',
'propagate' : False
},
'mitx' : {
'handlers' : handlers,
'level' : 'DEBUG',
'propagate' : False
},
}
}
\ No newline at end of file
"""
This config file runs the simplest dev environment using sqlite, and db-based
sessions. Assumes structure:
/envroot/
/db # This is where it'll write the database file
/mitx # The location of this repo
/log # Where we're going to write log files
"""
from common import *
LOGGING = logsettings.get_logger_config(PROJECT_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
debug=True)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': PROJECT_ROOT / "db" / "mitx.db",
}
}
CACHES = {
# This is the cache used for most things. Askbot will not work without a
# functioning cache -- it relies on caching to load its settings in places.
# In staging/prod envs, the sessions also live here.
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'mitx_loc_mem_cache'
},
# The general cache is what you get if you use our util.cache. It's used for
# things like caching the course.xml file for different A/B test groups.
# We set it to be a DummyCache to force reloading of course.xml in dev.
# In staging environments, we would grab VERSION from data uploaded by the
# push process.
'general': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'KEY_PREFIX': 'general',
'VERSION': 4,
}
}
# Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
############################ FILE UPLOADS (ASKBOT) #############################
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
MEDIA_ROOT = PROJECT_ROOT / "uploads"
MEDIA_URL = "/static/uploads/"
STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
FILE_UPLOAD_TEMP_DIR = PROJECT_ROOT / "uploads"
FILE_UPLOAD_HANDLERS = (
'django.core.files.uploadhandler.MemoryFileUploadHandler',
'django.core.files.uploadhandler.TemporaryFileUploadHandler',
)
import sys
import json
import random
import copy
from collections import defaultdict
from argparse import ArgumentParser, FileType
def generate_user(user_number):
return {
"pk": user_number,
"model": "auth.user",
"fields": {
"status": "w",
"last_name": "Last",
"gold": 0,
"is_staff": False,
"user_permissions": [],
"interesting_tags": "",
"email_key": None,
"date_joined": "2012-04-26 11:36:39",
"first_name": "",
"email_isvalid": False,
"avatar_type": "n",
"website": "",
"is_superuser": False,
"date_of_birth": None,
"last_login": "2012-04-26 11:36:48",
"location": "",
"new_response_count": 0,
"email": "user{num}@example.com".format(num=user_number),
"username": "user{num}".format(num=user_number),
"is_active": True,
"consecutive_days_visit_count": 0,
"email_tag_filter_strategy": 1,
"groups": [],
"password": "sha1$90e6f$562a1d783a0c47ce06ebf96b8c58123a0671bbf0",
"silver": 0,
"bronze": 0,
"questions_per_page": 10,
"about": "",
"show_country": True,
"country": "",
"display_tag_filter_strategy": 0,
"seen_response_count": 0,
"real_name": "",
"ignored_tags": "",
"reputation": 1,
"gravatar": "366d981a10116969c568a18ee090f44c",
"last_seen": "2012-04-26 11:36:39"
}
}
def parse_args(args=sys.argv[1:]):
parser = ArgumentParser()
parser.add_argument('-d', '--data', type=FileType('r'), default=sys.stdin)
parser.add_argument('-o', '--output', type=FileType('w'), default=sys.stdout)
parser.add_argument('count', type=int)
return parser.parse_args(args)
def main(args=sys.argv[1:]):
args = parse_args(args)
data = json.load(args.data)
unique_students = set(entry['fields']['student'] for entry in data)
if args.count > len(unique_students) * 0.1:
raise Exception("Can't be sufficiently anonymous selecting {count} of {unique} students".format(
count=args.count, unique=len(unique_students)))
by_problems = defaultdict(list)
for entry in data:
by_problems[entry['fields']['module_id']].append(entry)
out_data = []
out_pk = 1
for name, answers in by_problems.items():
for student_id in xrange(args.count):
sample = random.choice(answers)
data = copy.deepcopy(sample)
data["fields"]["student"] = student_id + 1
data["pk"] = out_pk
out_pk += 1
out_data.append(data)
for student_id in xrange(args.count):
out_data.append(generate_user(student_id))
json.dump(out_data, args.output, indent=2)
if __name__ == "__main__":
sys.exit(main())
......@@ -6,12 +6,12 @@ REPO_ROOT = File.dirname(__FILE__)
BUILD_DIR = File.join(REPO_ROOT, "build")
# Packaging constants
DEPLOY_DIR = "/opt/packages"
DEPLOY_DIR = "/opt/wwc"
PACKAGE_NAME = "mitx"
LINK_PATH = "/opt/wwc/mitx"
VERSION = "0.1"
COMMIT = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()[0, 10]
BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '').gsub('/', '_')
BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '')
BUILD_NUMBER = (ENV["BUILD_NUMBER"] || "dev").chomp()
if BRANCH == "master"
......@@ -19,14 +19,23 @@ if BRANCH == "master"
else
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BRANCH}-#{BUILD_NUMBER}-#{COMMIT}"
end
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, DEPLOY_NAME)
PACKAGE_REPO = "packages@gp.mitx.mit.edu:/opt/pkgrepo.incoming"
NORMALIZED_DEPLOY_NAME = DEPLOY_NAME.downcase().gsub(/[_\/]/, '-')
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, NORMALIZED_DEPLOY_NAME)
# Set up the clean and clobber tasks
CLOBBER.include('build')
CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
task :default do
sh("mkdir -p reports")
sh("touch reports/nosetests.xml")
end
task :test do
sh("django-admin.py test --settings=envs.test --pythonpath=. $(ls djangoapps)")
end
task :package do
FileUtils.mkdir_p(BUILD_DIR)
......@@ -38,10 +47,13 @@ task :package do
#! /bin/sh
set -e
set -x
chown -R makeitso:makeitso #{INSTALL_DIR_PATH}
service gunicorn stop
rm -f #{LINK_PATH}
ln -s #{INSTALL_DIR_PATH} #{LINK_PATH}
chown makeitso:makeitso #{LINK_PATH}
service gunicorn start
POSTINSTALL
postinstall.close()
......@@ -50,23 +62,13 @@ task :package do
args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb",
"--after-install=#{postinstall.path}",
"--prefix=#{INSTALL_DIR_PATH}",
"--exclude=build",
"--exclude=rakefile",
"--exclude=.git",
"--exclude=**/*.pyc",
"-C", "#{REPO_ROOT}",
"--depends=python-mysqldb",
"--depends=python-django",
"--depends=python-pip",
"--depends=python-flup",
"--depends=python-numpy",
"--depends=python-scipy",
"--depends=python-matplotlib",
"--depends=python-libxml2",
"--depends=python2.7-dev",
"--depends=libxml2-dev",
"--depends=libxslt-dev",
"--depends=python-markdown",
"--depends=python-pygments",
"--depends=mysql-client",
"--provides=#{PACKAGE_NAME}",
"--name=#{DEPLOY_NAME}",
"--name=#{NORMALIZED_DEPLOY_NAME}",
"--version=#{VERSION}",
"-a", "all",
"."]
......@@ -75,5 +77,5 @@ task :package do
end
task :publish => :package do
sh("scp #{BUILD_DIR}/#{DEPLOY_NAME}_#{VERSION}-1_all.deb #{PACKAGE_REPO}")
sh("scp #{BUILD_DIR}/#{NORMALIZED_DEPLOY_NAME}_#{VERSION}*.deb #{PACKAGE_REPO}")
end
Transitional for moving to new settings scheme.
To use:
django-admin runserver --settings=settings2.dev --pythonpath="."
from common import *
EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
CSRF_COOKIE_DOMAIN = '.mitx.mit.edu'
LIB_URL = 'https://mitxstatic.s3.amazonaws.com/js/'
BOOK_URL = 'https://mitxstatic.s3.amazonaws.com/book_images/'
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
}
}
DEBUG = False
TEMPLATE_DEBUG = False
"""
This config file runs the simplest dev environment using sqlite, and db-based
sessions.
"""
from common import *
CSRF_COOKIE_DOMAIN = 'localhost'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ENV_ROOT / "db" / "mitx.db",
}
}
# Make this unique, and don't share it with anybody.
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
DEBUG = True
TEMPLATE_DEBUG = False
# This is disabling ASKBOT, but not properly overwriting INSTALLED_APPS. ???
# It's because our ASKBOT_ENABLED here is actually shadowing the real one.
#
# ASKBOT_ENABLED = True
# MITX_FEATURES['SAMPLE'] = True # Switch to this system so we get around the shadowing
#
# INSTALLED_APPS = installed_apps()
"""
This config file tries to mimic the production environment more closely than the
normal dev.py. It assumes you're running a local instance of MySQL 5.1 and that
you're running memcached.
"""
from common import *
CSRF_COOKIE_DOMAIN = 'localhost'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'wwc', # Or path to database file if using sqlite3.
'USER': 'root', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '127.0.0.1', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '3306', # Set to empty string for default. Not used with sqlite3.
}
}
# Make this unique, and don't share it with anybody.
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
DEBUG = True
TEMPLATE_DEBUG = True
\ No newline at end of file
from common import *
GENERATE_RANDOM_USER_CREDENTIALS = True
from aws import *
# Staging specific overrides
SITE_NAME = "staging.mitx.mit.edu"
AWS_STORAGE_BUCKET_NAME = 'mitx_askbot_stage'
CACHES['default']['LOCATION'] = ['***REMOVED***',
'***REMOVED***']
### Secure Data Below Here ###
SECRET_KEY = ""
AWS_ACCESS_KEY_ID = ""
AWS_SECRET_ACCESS_KEY = ""
/* line 1, sass/marketing-ie.scss */
body {
margin: 0;
padding: 0; }
/* line 6, sass/marketing-ie.scss */
.wrapper, .subpage, section.copyright, section.tos, section.privacy-policy, section.honor-code, header.announcement div, section.index-content, footer {
margin: 0;
overflow: hidden; }
/* line 12, sass/marketing-ie.scss */
div#enroll form {
display: none; }
......@@ -671,6 +671,11 @@ section.index-content section.course h2 {
@media screen and (min-width: 500px) and (max-width: 781px) {
section.index-content section.course h2 {
padding-top: 207.104px; } }
section.index-content section.course div.announcement p.announcement-button a {
margin-top: 0; }
section.index-content section.course div.announcement img {
max-width: 100%;
margin-bottom: 25.888px; }
section.index-content section.about-course {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
......
/*
* jQuery UI Touch Punch 0.2.2
*
* Copyright 2011, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
(function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return;}var c=b.ui.mouse.prototype,e=c._mouseInit,a;function d(g,h){if(g.originalEvent.touches.length>1){return;}g.preventDefault();var i=g.originalEvent.changedTouches[0],f=document.createEvent("MouseEvents");f.initMouseEvent(h,true,true,window,1,i.screenX,i.screenY,i.clientX,i.clientY,false,false,false,false,0,null);g.target.dispatchEvent(f);}c._touchStart=function(g){var f=this;if(a||!f._mouseCapture(g.originalEvent.changedTouches[0])){return;}a=true;f._touchMoved=false;d(g,"mouseover");d(g,"mousemove");d(g,"mousedown");};c._touchMove=function(f){if(!a){return;}this._touchMoved=true;d(f,"mousemove");};c._touchEnd=function(f){if(!a){return;}d(f,"mouseup");d(f,"mouseout");if(!this._touchMoved){d(f,"click");}a=false;};c._mouseInit=function(){var f=this;f.element.bind("touchstart",b.proxy(f,"_touchStart")).bind("touchmove",b.proxy(f,"_touchMove")).bind("touchend",b.proxy(f,"_touchEnd"));e.call(f);};})(jQuery);
\ No newline at end of file
mathjax-MathJax-c9db6ac/
\ No newline at end of file
......@@ -7,21 +7,12 @@
<ul>
% for section in chapter['sections']:
<li
% if 'active' in section and section['active']:
class="active"
% endif
>
<li${' class="active"' if 'active' in section and section['active'] else ''}>
<a href="${reverse('courseware_section', args=format_url_params([course_name, chapter['name'], section['name']]))}">
<p>${section['name']}</p>
<p class="subtitle">
${section['format']}
% if 'due' in section and section['due']!="":
due ${section['due']}
% endif
${section['format']} ${"due " + section['due'] if 'due' in section and section['due'] != '' else ''}
</p>
</a>
% endfor
......
<%inherit file="main.html" />
<%block name="bodyclass">courseware</%block>
<%block name="title"><title>Courseware – MITx 6.002x</title></%block>
<%block name="js_extra">
......
......@@ -6,9 +6,7 @@
<p class="ie-warning"> Enrollment requires a modern web browser with JavaScript enabled. You don't have this. You can&rsquo;t enroll without upgrading, since you couldn&rsquo;t take the course without upgrading. Feel free to download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Mozilla Firefox</a> or <a href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=95346">Google Chrome</a>, for free, to enroll and take this course.</p>
<![endif]-->
<p class="disclaimer">
Please note that 6.002x has already started.
Several assignment due dates for 6.002x have already passed. It is now impossible for newly enrolled students to get 100% of the points in the course, although new students can still earn points for assignments whose due dates have not passed, and students have access to all of the course material that has been released for the course.
</p>
Please note that 6.002x has now passed its half-way point. The midterm exam and several assignment due dates for 6.002x have already passed. It is now impossible for newly enrolled students to earn a passing grade and a completion certificate for the course. However, new students have access to all of the course material that has been released for the course, so you are welcome to enroll and browse the course. </p>
<form name="enroll" id="enroll_form" method="get">
<fieldset><% if 'error' in locals(): e = error %>
......
MITx's prototype offering, 6.002x, is now open. To log in, visit
MITx's prototype offering, 6.002x, is open. To log in, visit
% if is_secure:
https://6002x.mitx.mit.edu
......@@ -16,7 +16,7 @@ place to reset it.
Once you log in, we recommend that you start the course by reviewing
the "System Usage Sequence" in the Overview section, and the "6.002x
At-a-Glance (Calendar)" handout under the Course Info tab. After you
familiarize yourself with the various features of the MITx platform,
familiarize yourself with the features of the MITx platform,
you can jump right into the coursework by working on "Administrivia
and Circuit Elements", the first Lecture Sequence in Week 1.
......
......@@ -11,7 +11,7 @@
<h2>6.002x</h2>
<a class="enroll" rel="leanModal" href="#enroll"><noscript>In order to</noscript> Enroll in 6.002x Circuits <span>&amp;</span> Electronics <noscript>you need to have javascript enabled</noscript></a>
</section>
<p>6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT&rsquo;s first undergraduate analog design course: 6.002. This course will run, free of charge, for students worldwide from March 5, 2012 through June 8, 2012.</p>
<p>6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT&rsquo;s first undergraduate analog design course: 6.002. This course is running, free of charge, for students worldwide from March 5, 2012 through June 8, 2012.</p>
</section>
</%block>
......
......@@ -4,7 +4,7 @@
<%block name="title"><title>MITx 6.002x</title></%block>
<link rel="stylesheet" href="${ settings.LIB_URL }jquery.treeview.css" type="text/css" media="all" />
<link rel="stylesheet" href="/static/css/application.css" type="text/css" media="all" />
<link rel="stylesheet" href="/static/css/application.css?v4" type="text/css" media="all" />
<script type="text/javascript" src="${ settings.LIB_URL }jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="${ settings.LIB_URL }jquery-ui-1.8.16.custom.min.js"></script>
......@@ -26,7 +26,7 @@
<script type="text/javascript" src="${ settings.LIB_URL }mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-AMS_HTML-full"></script>
</head>
<body class="<%block name="bodyclass"/>">
<body class="<%block name='bodyclass'/>">
<!--[if lte IE 9]>
<p class="ie-warning">You are using a browser that is not supported by <em>MITx</em>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p>
<![endif]-->
......@@ -127,15 +127,11 @@ $(function() {
$("#feedback_div").html("Feedback submitted. Thank you");
});
});
});
// Calculator
$(function() {
$("#calculator_wrapper").hide();
$(".calc").click(function(){
$("#calculator_wrapper").slideToggle("fast");
$("li.calc-main").toggleClass('open');
$("#calculator_wrapper #calculator_input").focus();
$(this).toggleClass("closed");
return false;
......@@ -156,10 +152,9 @@ $(function() {
$("#calculator_output").attr("value",data.result);
});
});
});
$(function(){
$("a[rel*=leanModal]").leanModal();
});
</script>
......
......@@ -8,7 +8,7 @@
<section class="intro">
<section class="intro-text">
<p><em>MITx</em> will offer a portfolio of MIT courses for free to a virtual community of learners around the world. It will also enhance the educational experience of its on-campus students, offering them online tools that supplement and enrich their classroom and laboratory experiences.</p>
<p>The first <em>MITx</em> course, 6.002x (Circuits and Electronics), will be launched in an experimental prototype form. Watch this space for further upcoming courses, which will become available in Fall 2012.</p>
<p>The first <em>MITx</em> course, 6.002x (Circuits and Electronics), was launched in an experimental prototype form. Watch this space for further upcoming courses, which will become available in Fall 2012.</p>
</section>
<section class="intro-video">
......@@ -33,17 +33,29 @@
</section>
<section class="course">
<hgroup>
<h1>Spring 2012 Course offering</h1>
<h2>Circuits and Electronics</h2>
<h3>6.002x</h3>
</hgroup>
<div class="announcement">
<h1> Announcement </h1>
<img src="/static/images/marketing/edx-logo.png" alt="" />
<p>
On May 2, it was announced that Harvard University will join MIT as a partner in edX. MITx, which offers online versions of MIT courses, will be a core offering of edX, as will Harvardx, a set of course offerings from Harvard.
</p>
<p class="announcement-button">
<a href="http://edxonline.org">Read more details here <span class="arrow">&#8227;</span></a>
</p>
</div>
<hgroup>
<h1>Spring 2012 Course offering</h1>
<h2>Circuits and Electronics</h2>
<h3>6.002x</h3>
</hgroup>
<p>
<a href="http://6002x.mitx.mit.edu/" class="more-info">More information <span>&amp;</span> Enroll <span class="arrow">&#8227;</span></a>
</p>
<p>Taught by Anant Agarwal, with Gerald Sussman and Piotr Mitros, 6.002x (Circuits and Electronics) is an on-line adaption of 6.002, MIT&rsquo;s first undergraduate analog design course. This prototype course will run, free of charge, for students worldwide from March 5, 2012 through June 8, 2012. Students will be given the opportunity to demonstrate their mastery of the material and earn a certificate from <em>MITx</em>.</p>
<p>Taught by Anant Agarwal, with Gerald Sussman and Piotr Mitros, 6.002x (Circuits and Electronics) is an on-line adaption of 6.002, MIT&rsquo;s first undergraduate analog design course. This prototype course is running, free of charge, for students worldwide from March 5, 2012 through June 8, 2012. Students are given the opportunity to demonstrate their mastery of the material and earn a certificate from <em>MITx</em>.</p>
</section>
</section>
......
......@@ -63,7 +63,7 @@ a {
p &, li > &, span > &, .inline {
border-bottom: 1px solid #bbb;
font-style: italic;
// font-style: italic;
}
&:hover, &:focus {
......
......@@ -2,7 +2,7 @@
// ---------------------------------------- //
// fonts
$body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;;
$body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
$body-font-size: 14px;
// grid
......
// JM MOSFET AMPLIFIER
div#graph-container {
section.tool-wrapper {
background: #073642;
border-top: 1px solid darken(#002b36, 10%);
border-bottom: 1px solid darken(#002b36, 10%);
@include box-shadow(inset 0 0 0 4px darken(#094959, 2%));
margin: lh() (-(lh())) 0;
color: #839496;
@extend .clearfix;
border-top: 1px solid #ddd;
padding-top: lh(1.0);
canvas#graph {
width: flex-grid(4.5, 9);
float: left;
margin-right: flex-gutter(9);
}
div.graph-controls {
width: flex-grid(4.5, 9);
float: left;
select#musicTypeSelect {
display: block;
margin-bottom: lh();
display: table;
div#graph-container {
background: none;
@include box-sizing(border-box);
display: table-cell;
padding: lh();
vertical-align: top;
width: flex-grid(4.5, 9) + flex-gutter(9);
.ui-widget-content {
background: none;
border: none;
@include border-radius(0);
}
div#graph-output {
display: block;
margin-bottom: lh();
canvas {
width: 100%;
}
div#graph-listen {
display: block;
margin-bottom: lh();
ul.ui-tabs-nav {
background: darken(#073642, 2%);
margin: (-(lh())) (-(lh())) 0;
padding: 0;
position: relative;
width: 110%;
@include border-radius(0);
border-bottom: 1px solid darken(#073642, 8%);
li {
margin-bottom: 0;
background: none;
color: #fff;
border: none;
@include border-radius(0);
&.ui-tabs-selected {
border-right: 1px solid darken(#073642, 8%);
border-left: 1px solid darken(#073642, 8%);
background-color: #073642;
&:first-child {
border-left: none;
}
a {
color: #eee8d5;
}
}
a {
border: none;
font: bold 12px $body-font-family;
text-transform: uppercase;
letter-spacing: 1px;
color: #839496;
&:hover {
color: #eee8d5;
}
}
}
}
}
p {
margin-bottom: lh(.5);
}
div#controlls-container {
@extend .clearfix;
background: darken(#073642, 2%);
border-right: 1px solid darken(#002b36, 6%);
@include box-shadow(1px 0 0 lighten(#002b36, 6%), inset 0 0 0 4px darken(#094959, 6%));
@include box-sizing(border-box);
display: table-cell;
padding: lh();
vertical-align: top;
width: flex-grid(4.5, 9);
div#label {
display: inline-block;
div.graph-controls {
div.music-wrapper {
padding: 0 0 lh();
margin-bottom: lh();
border-bottom: 1px solid darken(#073642, 10%);
@include box-shadow(0 1px 0 lighten(#073642, 2%));
@extend .clearfix;
input#playButton {
display: block;
@include button(simple, lighten( #586e75, 5% ));
font: bold 14px $body-font-family;
border-color: darken(#002b36, 6%);
float: right;
&:active {
@include box-shadow(none);
}
&[value="Stop"] {
@include button(simple, darken(#268bd2, 30%));
font: bold 14px $body-font-family;
&:active {
@include box-shadow(none);
}
}
}
}
div.inputs-wrapper {
@include clearfix;
margin-bottom: lh();
padding: 0 0 lh();
margin-bottom: lh();
border-bottom: 1px solid darken(#073642, 10%);
@include box-shadow(0 1px 0 lighten(#073642, 2%));
@extend .clearfix;
}
p {
@include inline-block();
margin: 0;
-webkit-font-smoothing: antialiased;
font-weight: bold;
text-shadow: 0 -1px 0 darken(#073642, 10%);
}
ul {
@include inline-block();
margin-bottom: 0;
li {
@include inline-block();
margin-bottom: 0;
input {
margin-right: 5px;
}
}
}
div#graph-listen {
margin-top: 8px;
margin-right: 20px;
display: block;
text-align: right;
float: left;
margin-bottom: 0;
}
}
input#playButton {
display: block;
label {
@include border-radius(2px);
font-weight: bold;
color: #fff;
padding: 3px;
-webkit-font-smoothing: antialiased;
}
}
}
div#schematic-container {
@extend .clearfix;
//MOSFET AMPLIFIER
label[for="vinCheckbox"], label[for="vinRadioButton"]{
color: desaturate(#00bfff, 50%);
}
canvas {
width: flex-grid(4.5, 9);
float: left;
margin-right: flex-gutter(9);
}
label[for="voutCheckbox"], label[for="voutRadioButton"]{
color: darken(#ffcf48, 20%);
}
div.schematic-sliders {
width: flex-grid(4.5, 9);
float: left;
label[for="vrCheckbox"], label[for="vrRadioButton"]{
color: desaturate(#1df914, 40%);
}
div.slider-label#vs {
margin-top: lh(2.0);
//RC Filters
label[for="vcCheckbox"], label[for="vcRadioButton"]{
color: darken(#ffcf48, 20%);
}
div.slider-label {
margin-bottom: lh(0.5);
//RLC Series
label[for="vlCheckbox"], label[for="vlRadioButton"]{
color: desaturate(#d33682, 40%);
}
div.slider {
margin-bottom: lh(1);
div.schematic-sliders {
div.top-sliders {
padding: 0 0 lh();
margin-bottom: lh();
border-bottom: 1px solid darken(#073642, 10%);
@include box-shadow(0 1px 0 lighten(#073642, 2%));
@extend .clearfix;
select#musicTypeSelect {
@include inline-block();
font: 16px $body-font-family;
margin-bottom: 0;
}
p {
@include inline-block();
-webkit-font-smoothing: antialiased;
text-shadow: 0 -1px 0 darken(#073642, 10%);
margin: 0 lh(.5) lh() 0;
font-weight: bold;
}
}
div.slider-label {
margin-bottom: lh(0.5);
font-weight: bold;
text-shadow: 0 -1px 0 darken(#073642, 10%);
-webkit-font-smoothing: antialiased;
}
div.slider {
margin-bottom: lh(1);
&.ui-slider-horizontal {
height: 0.4em;
background: darken(#002b36, 2%);
border: 1px solid darken(#002b36, 8%);
@include box-shadow(none);
}
.ui-slider-handle {
background: lighten( #586e75, 5% ) url('/static/images/amplifier-slider-handle.png') center no-repeat;
border: 1px solid darken(#002b36, 8%);
@include box-shadow(inset 0 1px 0 lighten( #586e75, 20% ));
margin-top: -.3em;
&:hover, &:active {
background-color: lighten( #586e75, 10% );
}
}
}
}
}
}
//End JM MOSFET AMPLIFIER
// Labels
div.graph-controls, div#graph-listen {
label {
@include border-radius(2px);
font-weight: bold;
padding: 3px;
}
//MOSFET AMPLIFIER
label[for="vinCheckbox"], label[for="vinRadioButton"]{
color: desaturate(#00bfff, 50%);
}
label[for="voutCheckbox"], label[for="voutRadioButton"]{
color: darken(#ffcf48, 20%);
}
label[for="vrCheckbox"], label[for="vrRadioButton"]{
color: desaturate(#1df914, 40%);
}
//RC Filters
label[for="vcCheckbox"], label[for="vcRadioButton"]{
color: darken(#ffcf48, 20%);
}
//RLC Series
label[for="vlCheckbox"], label[for="vlRadioButton"]{
color: desaturate(#d33682, 40%);
}
}
html {
height: 100%;
max-height: 100%;
}
body.courseware {
height: 100%;
max-height: 100%;
}
div.course-wrapper {
@extend .table-wrapper;
......@@ -7,9 +17,10 @@ div.course-wrapper {
section.course-content {
@extend .content;
overflow: hidden;
h1 {
@extend .top-header;
margin: 0 0 lh();
}
p {
......@@ -159,18 +170,63 @@ div.course-wrapper {
margin-bottom: 15px;
padding: 0 0 15px;
header {
@extend h1.top-header;
margin-bottom: 0;
h1 {
margin: 0;
}
h2 {
float: right;
margin-right: 0;
margin-top: 8px;
text-align: right;
padding-right: 0;
}
}
&:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
ul {
list-style: disc outside none;
padding-left: 1em;
}
}
}
section.tutorials {
h2 {
margin-bottom: lh();
}
ul {
list-style: disc outside none;
margin-left: lh();
margin: 0;
@include clearfix();
li {
width: flex-grid(3, 9);
float: left;
margin-right: flex-gutter(9);
margin-bottom: lh();
&:nth-child(3n) {
margin-right: 0;
}
&:nth-child(3n+1) {
clear: both;
}
a {
font-weight: bold;
}
}
}
}
......@@ -202,6 +258,24 @@ div.course-wrapper {
}
}
}
div.ui-tabs {
border: 0;
@include border-radius(0);
margin: 0;
padding: 0;
.ui-tabs-nav {
background: none;
border: 0;
margin-bottom: lh(.5);
}
.ui-tabs-panel {
@include border-radius(0);
padding: 0;
}
}
}
&.closed {
......
......@@ -3,9 +3,11 @@ nav.sequence-nav {
@include box-sizing(border-box);
margin-bottom: $body-line-height;
position: relative;
top: -1px;
ol {
border-bottom: 1px solid darken($cream, 20%);
border-top: 1px solid darken($cream, 20%);
@include box-sizing(border-box);
display: table;
padding-right: flex-grid(1, 9);
......@@ -171,6 +173,7 @@ nav.sequence-nav {
ul {
margin-right: 1px;
list-style: none !important;
position: absolute;
right: 0;
top: 0;
......@@ -232,26 +235,20 @@ nav.sequence-nav {
section.course-content {
div#seq_content {
margin-bottom: 60px;
}
position: relative;
nav.sequence-bottom {
bottom: (-(lh()));
position: relative;
margin: lh(2) 0 0;
text-align: center;
ul {
@extend .clearfix;
background-color: darken(#F6EFD4, 5%);
background-color: darken($cream, 5%);
border: 1px solid darken(#f6efd4, 20%);
border-bottom: 0;
@include border-radius(3px 3px 0 0);
@include border-radius(3px);
@include box-shadow(inset 0 0 0 1px lighten(#f6efd4, 5%));
margin: 0 auto;
overflow: hidden;
width: 106px;
@include inline-block();
li {
float: left;
......@@ -264,15 +261,13 @@ section.course-content {
background-repeat: no-repeat;
border-bottom: none;
display: block;
display: block;
padding: lh(.75) 4px;
padding: lh(.5) 4px;
text-indent: -9999px;
@include transition(all, .4s, $ease-in-out-quad);
width: 45px;
&:hover {
background-color: darken($cream, 10%);
color: darken(#F6EFD4, 60%);
color: darken($cream, 60%);
opacity: .5;
text-decoration: none;
......@@ -288,6 +283,7 @@ section.course-content {
&.prev {
a {
background-image: url('/static/images/sequence-nav/previous-icon.png');
border-right: 1px solid darken(#f6efd4, 20%);
&:hover {
background-color: none;
......
......@@ -20,6 +20,7 @@ section.index-content {
p {
line-height: lh();
margin-bottom: lh();
}
ul {
......@@ -237,6 +238,19 @@ section.index-content {
padding-top: lh(8);
}
}
div.announcement {
p.announcement-button {
a {
margin-top: 0;
}
}
img {
max-width: 100%;
margin-bottom: lh();
}
}
}
......
li.calc-main {
bottom: -36px;
bottom: -126px;
left: 0;
position: fixed;
width: 100%;
@include transition(bottom);
z-index: 99;
-webkit-appearance: none;
&.open {
bottom: -36px;
div#calculator_wrapper form div.input-wrapper div.help-wrapper dl {
display: block;
}
}
a.calc {
@include hide-text;
......@@ -33,11 +44,12 @@ li.calc-main {
position: relative;
top: -36px;
clear: both;
max-height: 90px;
form {
padding: lh();
@extend .clearfix;
@include box-sizing(border-box);
input#calculator_button {
background: #111;
......@@ -46,13 +58,14 @@ li.calc-main {
@include box-shadow(none);
@include box-sizing(border-box);
color: #fff;
float: left;
font-size: 30px;
font-weight: bold;
margin: 0 (flex-gutter() / 2);
padding: 0;
text-shadow: none;
-webkit-appearance: none;
width: flex-grid(.5) + flex-gutter();
float: left;
margin: 0 (flex-gutter() / 2);
&:hover {
color: #333;
......@@ -70,15 +83,16 @@ li.calc-main {
font-weight: bold;
margin: 1px 0 0;
padding: 10px;
-webkit-appearance: none;
width: flex-grid(4);
}
div.input-wrapper {
position: relative;
@extend .clearfix;
width: flex-grid(7.5);
margin: 0;
float: left;
margin: 0;
position: relative;
width: flex-grid(7.5);
input#calculator_input {
border: none;
......@@ -86,6 +100,7 @@ li.calc-main {
@include box-sizing(border-box);
font-size: 16px;
padding: 10px;
-webkit-appearance: none;
width: 100%;
&:focus {
......@@ -117,6 +132,7 @@ li.calc-main {
right: -40px;
top: -110px;
width: 500px;
display: none;
@include transition();
&.shown {
......
......@@ -30,6 +30,17 @@ html {
}
}
div.qtip {
div.ui-tooltip-content {
border: none;
background: rgba(#000, .8);
color: #fff;
font: 12px $body-font-family;
margin-top: -30px;
margin-right: -20px;
}
}
section.outside-app {
@extend .main-content;
max-width: 600px;
......
% if name is not UNDEFINED and name != None:
% if name is not UNDEFINED and name != None:
<h1> ${name} </h1>
% endif
<div class="video-subtitles">
<div class="tc-wrapper">
<div class="video-wrapper">
<div class="video-player">
......@@ -28,12 +29,16 @@
<div class="secondary-controls">
<div class="speeds">
<h3>Speed</h3>
<p class="active"></p>
<ol id="video_speeds"></ol>
<a href="#">
<h3>Speed</h3>
<p class="active"></p>
<ol id="video_speeds"></ol>
</a>
</div>
<a href="#" class="hide-subtitles">Captions</a>
<a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>
<a href="#" class="hide-subtitles" title="Turn off captions">Captions</a>
</div>
</section>
</section>
......@@ -57,18 +62,63 @@
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 7);"></div></li>
<li id="stt_p6"><div id="std_p7" onclick="title_seek( 8);"></div></li>
</ol>
</div>
</div>
<%block name="js_extra">
<script src="/static/js/jquery.ui.touch-punch.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
// tooltips for full browser and closed caption
$('.add-fullscreen, .hide-subtitles ').qtip({
position: {
my: 'top right',
at: 'top center'
}
});
//full browser
$('.add-fullscreen').click(function() {
$('div.video-subtitles').toggleClass('fullscreen');
if ($('div.video-subtitles').hasClass('fullscreen')) {
$('div.video-subtitles').append('<a href="#" class="exit">Exit</a>');
} else {
$('a.exit').remove();
}
$('.exit').click(function() {
$('div.video-subtitles').removeClass('fullscreen');
$(this).remove();
return false;
});
var link_title = $(this).attr('title');
$(this).attr('title', (link_title == 'Exit fill browser') ? 'Fill browser' : 'Exit fill browser');
return false;
});
//hide subtitles
$('.hide-subtitles').click(function() {
$('div.video-subtitles').toggleClass('closed');
$(this).toggleClass("off");
var link_title = $(this).attr('title');
$(this).attr('title', (link_title == 'Turn on captions') ? 'Turn off captions' : 'Turn on captions');
return false;
});
$("div.speeds a").hover(function() {
$(this).toggleClass("open");
});
$("div.speeds a").click(function() {
return false;
});
});
</script>
</%block>
......@@ -88,6 +88,7 @@ function add_speed(key, stream) {
var active = $(this).text();
$("p.active").text(active);
});
}
var l=[]
......@@ -128,6 +129,9 @@ $(document).ready(function() {
add_speed(l[i], streams[l[i]])
}
var dropUpHeight = $('ol#video_speeds').height();
console.log(dropUpHeight);
$('ol#video_speeds').css('top', -(dropUpHeight + 2));
});
function toggleVideo(){
......
from django.conf import settings
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
import django.contrib.auth.views
# Uncomment the next two lines to enable the admin:
......@@ -46,38 +48,44 @@ if settings.END_COURSE_ENABLED:
)
if settings.PERFSTATS:
urlpatterns=urlpatterns + (url(r'^reprofile$','perfstats.views.end_profile'),)
urlpatterns += (url(r'^reprofile$','perfstats.views.end_profile'),)
if settings.COURSEWARE_ENABLED:
urlpatterns=urlpatterns + (url(r'^courseware/$', 'courseware.views.index', name="courseware"),
url(r'^info$', 'util.views.info'),
url(r'^wiki/', include('simplewiki.urls')),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index', name="courseware_course"),
url(r'^section/(?P<section>[^/]*)/$', 'courseware.views.render_section'),
url(r'^modx/(?P<module>[^/]*)/(?P<id>[^/]*)/(?P<dispatch>[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'),
url(r'^profile$', 'courseware.views.profile'),
url(r'^profile/(?P<student_id>[^/]*)/$', 'courseware.views.profile'),
url(r'^change_setting$', 'student.views.change_setting'),
url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'),
url(r'^book/(?P<page>[^/]*)$', 'staticbook.views.index'),
url(r'^book-shifted/(?P<page>[^/]*)$', 'staticbook.views.index_shifted'),
url(r'^book*$', 'staticbook.views.index'),
# url(r'^course_info/$', 'student.views.courseinfo'),
# url(r'^show_circuit/(?P<circuit>[^/]*)$', 'circuit.views.show_circuit'),
url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
url(r'^calculate$', 'util.views.calculate'),
)
urlpatterns += (
url(r'^courseware/$', 'courseware.views.index', name="courseware"),
url(r'^info$', 'util.views.info'),
url(r'^wiki/', include('simplewiki.urls')),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index', name="courseware_section"),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index', name="courseware_chapter"),
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index', name="courseware_course"),
url(r'^section/(?P<section>[^/]*)/$', 'courseware.views.render_section'),
url(r'^modx/(?P<module>[^/]*)/(?P<id>[^/]*)/(?P<dispatch>[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'),
url(r'^profile$', 'courseware.views.profile'),
url(r'^profile/(?P<student_id>[^/]*)/$', 'courseware.views.profile'),
url(r'^change_setting$', 'student.views.change_setting'),
url(r'^s/(?P<template>[^/]*)$', 'static_template_view.views.auth_index'),
url(r'^book/(?P<page>[^/]*)$', 'staticbook.views.index'),
url(r'^book-shifted/(?P<page>[^/]*)$', 'staticbook.views.index_shifted'),
url(r'^book*$', 'staticbook.views.index'),
# url(r'^course_info/$', 'student.views.courseinfo'),
# url(r'^show_circuit/(?P<circuit>[^/]*)$', 'circuit.views.show_circuit'),
url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
url(r'^calculate$', 'util.views.calculate'),
url(r'^heartbeat$', include('heartbeat.urls')),
)
if settings.ASKBOT_ENABLED:
urlpatterns=urlpatterns + (url(r'^%s' % settings.ASKBOT_URL, include('askbot.urls')), \
url(r'^admin/', include(admin.site.urls)), \
url(r'^settings/', include('askbot.deps.livesettings.urls')), \
url(r'^followit/', include('followit.urls')), \
# url(r'^robots.txt$', include('robots.urls')),
urlpatterns += (url(r'^%s' % settings.ASKBOT_URL, include('askbot.urls')), \
url(r'^admin/', include(admin.site.urls)), \
url(r'^settings/', include('askbot.deps.livesettings.urls')), \
url(r'^followit/', include('followit.urls')), \
# url(r'^robots.txt$', include('robots.urls')),
)
urlpatterns = patterns(*urlpatterns)
if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns()
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