From 8a6b9a56662b078b18a25192a23139a07435e9cb Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 13:42:11 -0400
Subject: [PATCH 01/55] update lms readme
---
lms/envs/README.txt | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/lms/envs/README.txt b/lms/envs/README.txt
index 7a527b290f..6d1512e6f6 100644
--- a/lms/envs/README.txt
+++ b/lms/envs/README.txt
@@ -1,14 +1,16 @@
-Transitional for moving to new settings scheme.
+Transitional for moving to new settings scheme.
-To use:
- django-admin.py runserver --settings=envs.dev --pythonpath=.
+To use:
+ rake lms
+ or
+ django-admin.py runserver --settings=lms.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.
+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
+ gunicorn_django lms/envs/dev.py
From d43831e11c157188ea027945eea9ccb12a369297 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 13:42:54 -0400
Subject: [PATCH 02/55] add to overview of course.xml processing
---
doc/overview.md | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/doc/overview.md b/doc/overview.md
index 88ea3bdb5e..36e22e16eb 100644
--- a/doc/overview.md
+++ b/doc/overview.md
@@ -13,17 +13,17 @@ You should be familiar with the following. If you're not, go read some docs...
- css
- git
- mako templates -- we use these instead of django templates, because they support embedding real python.
-
+
## Other relevant terms
- CAPA -- lon-capa.org -- content management system that has defined a standard for online learning and assessment materials. Many of our materials follow this standard.
- - TODO: add more details / link to relevant docs. lon-capa.org is not immediately intuitive.
+ - TODO: add more details / link to relevant docs. lon-capa.org is not immediately intuitive.
- lcp = loncapa problem
## Parts of the system
- - LMS -- Learning Management System. The student-facing parts of the system. Handles student accounts, displaying videos, tutorials, exercies, problems, etc.
+ - LMS -- Learning Management System. The student-facing parts of the system. Handles student accounts, displaying videos, tutorials, exercies, problems, etc.
- CMS -- Course Management System. The instructor-facing parts of the system. Allows instructors to see and modify their course, add lectures, problems, reorder things, etc.
@@ -42,7 +42,7 @@ You should be familiar with the following. If you're not, go read some docs...
## High Level Entities in the code
-### Common libraries
+### Common libraries
- xmodule: generic learning modules. *x* can be sequence, video, template, html,
vertical, capa, etc. These are the things that one puts inside sections
@@ -51,7 +51,7 @@ You should be familiar with the following. If you're not, go read some docs...
- XModuleDescriptor: This defines the problem and all data and UI needed to edit
that problem. It is unaware of any student data, but can be used to retrieve
an XModule, which is aware of that student state.
-
+
- XModule: The XModule is a problem instance that is particular to a student. It knows
how to render itself to html to display the problem, how to score itself,
and how to handle ajax calls from the front end.
@@ -59,19 +59,25 @@ You should be familiar with the following. If you're not, go read some docs...
- Both XModule and XModuleDescriptor take system context parameters. These are named
ModuleSystem and DescriptorSystem respectively. These help isolate the XModules
from any interactions with external resources that they require.
-
+
For instance, the DescriptorSystem has a function to load an XModuleDescriptor
from a Location object, and the ModuleSystem knows how to render things,
track events, and complain about 404s
- - TODO: document the system context interface--it's different in `x_module.XModule.__init__` and in `x_module tests.py` (do this in the code, not here)
+
+ - `course.xml` format. We use python setuptools to connect supported tags with the descriptors that handle them. See `common/lib/xmodule/setup.py`. There are checking and validation tools in `common/validate`.
+
+ - the xml import+export functionality is in `xml_module.py:XmlDescriptor`, which is a mixin class that's used by the actual descriptor classes.
+
+ - There is a distinction between descriptor _definitions_ that stay the same for any use of that descriptor (e.g. here is what a particular problem is), and _metadata_ describing how that descriptor is used (e.g. whether to allow checking of answers, due date, etc). When reading in `from_xml`, the code pulls out the metadata attributes into a separate structure, and puts it back on export.
+
- in `common/lib/xmodule`
-- capa modules -- defines `LoncapaProblem` and many related things.
+- capa modules -- defines `LoncapaProblem` and many related things.
- in `common/lib/capa`
-### LMS
+### LMS
-The LMS is a django site, with root in `lms/`. It runs in many different environments--the settings files are in `lms/envs`.
+The LMS is a django site, with root in `lms/`. It runs in many different environments--the settings files are in `lms/envs`.
- We use the Django Auth system, including the is_staff and is_superuser flags. User profiles and related code lives in `lms/djangoapps/student/`. There is support for groups of students (e.g. 'want emails about future courses', 'have unenrolled', etc) in `lms/djangoapps/student/models.py`.
@@ -79,19 +85,19 @@ The LMS is a django site, with root in `lms/`. It runs in many different enviro
- `lms/djangoapps/courseware/models.py`
- Core rendering path:
- - `lms/urls.py` points to `courseware.views.index`, which gets module info from the course xml file, pulls list of `StudentModule` objects for this user (to avoid multiple db hits).
+ - `lms/urls.py` points to `courseware.views.index`, which gets module info from the course xml file, pulls list of `StudentModule` objects for this user (to avoid multiple db hits).
- Calls `render_accordion` to render the "accordion"--the display of the course structure.
- To render the current module, calls `module_render.py:render_x_module()`, which gets the `StudentModule` instance, and passes the `StudentModule` state and other system context to the module constructor the get an instance of the appropriate module class for this user.
- calls the module's `.get_html()` method. If the module has nested submodules, render_x_module() will be called again for each.
-
+
- ajax calls go to `module_render.py:modx_dispatch()`, which passes it to the module's `handle_ajax()` function, and then updates the grade and state if they changed.
- [This diagram](https://github.com/MITx/mitx/wiki/MITx-Architecture) visually shows how the clients communicate with problems + modules.
-
-- See `lms/urls.py` for the wirings of urls to views.
+
+- See `lms/urls.py` for the wirings of urls to views.
- Tracking: there is support for basic tracking of client-side events in `lms/djangoapps/track`.
@@ -110,7 +116,7 @@ environments, defined in `cms/envs`.
- _mako_ -- we use this for templates, and have wrapper called mitxmako that makes mako look like the django templating calls.
-We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings.
+We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings.
In production, the django `collectstatic` command recompiles everything and puts all the generated static files in a static/ dir. A starting point in the code is `django-pipeline/pipeline/packager.py:pack`.
@@ -127,8 +133,6 @@ See `testing.md`.
## TODO:
-- update lms/envs/README.txt
-
- describe our production environment
- describe the front-end architecture, tools, etc. Starting point: `lms/static`
From 63f34f2e70f4b930a02a36ed99cf54750fad05a4 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 13:58:19 -0400
Subject: [PATCH 03/55] Line length and doc string cleanups
* no functionality changed in this commit.
---
.../lib/xmodule/xmodule/backcompat_module.py | 20 +-
common/lib/xmodule/xmodule/capa_module.py | 35 ++-
common/lib/xmodule/xmodule/course_module.py | 11 +-
common/lib/xmodule/xmodule/mako_module.py | 7 +-
.../xmodule/xmodule/modulestore/__init__.py | 49 ++--
common/lib/xmodule/xmodule/raw_module.py | 2 +-
common/lib/xmodule/xmodule/seq_module.py | 15 +-
common/lib/xmodule/xmodule/x_module.py | 233 +++++++++++-------
common/lib/xmodule/xmodule/xml_module.py | 34 ++-
9 files changed, 261 insertions(+), 145 deletions(-)
diff --git a/common/lib/xmodule/xmodule/backcompat_module.py b/common/lib/xmodule/xmodule/backcompat_module.py
index d379ced507..c040eca398 100644
--- a/common/lib/xmodule/xmodule/backcompat_module.py
+++ b/common/lib/xmodule/xmodule/backcompat_module.py
@@ -12,8 +12,8 @@ log = logging.getLogger(__name__)
def process_includes(fn):
"""
Wraps a XModuleDescriptor.from_xml method, and modifies xml_data to replace
- any immediate child items with the contents of the file that they are
- supposed to include
+ any immediate child items with the contents of the file that they
+ are supposed to include
"""
@wraps(fn)
def from_xml(cls, xml_data, system, org=None, course=None):
@@ -25,15 +25,19 @@ def process_includes(fn):
try:
ifp = system.resources_fs.open(file)
except Exception:
- log.exception('Error in problem xml include: %s' % (etree.tostring(next_include, pretty_print=True)))
- log.exception('Cannot find file %s in %s' % (file, dir))
+ msg = 'Error in problem xml include: %s\n' % (
+ etree.tostring(next_include, pretty_print=True))
+ msg += 'Cannot find file %s in %s' % (file, dir)
+ log.exception(msg)
raise
try:
# read in and convert to XML
incxml = etree.XML(ifp.read())
except Exception:
- log.exception('Error in problem xml include: %s' % (etree.tostring(next_include, pretty_print=True)))
- log.exception('Cannot parse XML in %s' % (file))
+ msg = 'Error in problem xml include: %s\n' % (
+ etree.tostring(next_include, pretty_print=True))
+ msg += 'Cannot parse XML in %s' % (file)
+ log.exception(msg)
raise
# insert new XML into tree in place of inlcude
parent = next_include.getparent()
@@ -50,8 +54,8 @@ class SemanticSectionDescriptor(XModuleDescriptor):
@process_includes
def from_xml(cls, xml_data, system, org=None, course=None):
"""
- Removes sections single child elements in favor of just embedding the child element
-
+ Removes sections with single child elements in favor of just embedding
+ the child element
"""
xml_object = etree.fromstring(xml_data)
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 263e062887..5ff0c13198 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -67,7 +67,8 @@ class ComplexEncoder(json.JSONEncoder):
class CapaModule(XModule):
'''
- An XModule implementing LonCapa format problems, implemented by way of capa.capa_problem.LoncapaProblem
+ An XModule implementing LonCapa format problems, implemented by way of
+ capa.capa_problem.LoncapaProblem
'''
icon_class = 'problem'
@@ -77,8 +78,10 @@ class CapaModule(XModule):
js_module_name = "Problem"
css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]}
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition, instance_state=None,
+ shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition, instance_state,
+ shared_state, **kwargs)
self.attempts = 0
self.max_attempts = None
@@ -133,7 +136,8 @@ class CapaModule(XModule):
seed = None
try:
- self.lcp = LoncapaProblem(self.definition['data'], self.location.html_id(), instance_state, seed=seed, system=self.system)
+ self.lcp = LoncapaProblem(self.definition['data'], self.location.html_id(),
+ instance_state, seed=seed, system=self.system)
except Exception:
msg = 'cannot create LoncapaProblem %s' % self.location.url()
log.exception(msg)
@@ -141,15 +145,20 @@ class CapaModule(XModule):
msg = '%s
' % msg.replace('<', '<')
msg += '
%s
' % traceback.format_exc().replace('<', '<')
# create a dummy problem with error message instead of failing
- problem_text = 'Problem %s has an error: %s ' % (self.location.url(), msg)
- self.lcp = LoncapaProblem(problem_text, self.location.html_id(), instance_state, seed=seed, system=self.system)
+ problem_text = (''
+ 'Problem %s has an error: %s ' %
+ (self.location.url(), msg))
+ self.lcp = LoncapaProblem(
+ problem_text, self.location.html_id(),
+ instance_state, seed=seed, system=self.system)
else:
raise
@property
def rerandomize(self):
"""
- Property accessor that returns self.metadata['rerandomize'] in a canonical form
+ Property accessor that returns self.metadata['rerandomize'] in a
+ canonical form
"""
rerandomize = self.metadata.get('rerandomize', 'always')
if rerandomize in ("", "always", "true"):
@@ -203,7 +212,10 @@ class CapaModule(XModule):
except Exception, err:
if self.system.DEBUG:
log.exception(err)
- msg = '[courseware.capa.capa_module] Failed to generate HTML for problem %s ' % (self.location.url())
+ msg = (
+ '[courseware.capa.capa_module] '
+ 'Failed to generate HTML for problem %s ' %
+ (self.location.url()))
msg += 'Error:
%s ' % str(err).replace('<', '<')
msg += '
%s ' % traceback.format_exc().replace('<', '<')
html = msg
@@ -215,8 +227,8 @@ class CapaModule(XModule):
'weight': self.weight,
}
- # We using strings as truthy values, because the terminology of the check button
- # is context-specific.
+ # We using strings as truthy values, because the terminology of the
+ # check button is context-specific.
check_button = "Grade" if self.max_attempts else "Check"
reset_button = True
save_button = True
@@ -242,7 +254,8 @@ class CapaModule(XModule):
if not self.lcp.done:
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 is None and self.rerandomize != "always":
save_button = False
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index a04324237c..05f440c0f8 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -17,11 +17,12 @@ class CourseDescriptor(SequenceDescriptor):
try:
self.start = time.strptime(self.metadata["start"], "%Y-%m-%dT%H:%M")
except KeyError:
- self.start = time.gmtime(0) # The epoch
- log.critical("Course loaded without a start date. " + str(self.id))
- except ValueError, e:
- self.start = time.gmtime(0) # The epoch
- log.critical("Course loaded with a bad start date. " + str(self.id) + " '" + str(e) + "'")
+ self.start = time.gmtime(0) #The epoch
+ log.critical("Course loaded without a start date. %s", self.id)
+ except ValueError as e:
+ self.start = time.gmtime(0) #The epoch
+ log.critical("Course loaded with a bad start date. %s '%s'",
+ self.id, e)
def has_started(self):
return time.gmtime() > self.start
diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py
index 9a90afb896..da620e4889 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -19,7 +19,9 @@ class MakoModuleDescriptor(XModuleDescriptor):
def __init__(self, system, definition=None, **kwargs):
if getattr(system, 'render_template', None) is None:
- raise TypeError('{system} must have a render_template function in order to use a MakoDescriptor'.format(system=system))
+ raise TypeError('{system} must have a render_template function'
+ ' in order to use a MakoDescriptor'.format(
+ system=system))
super(MakoModuleDescriptor, self).__init__(system, definition, **kwargs)
def get_context(self):
@@ -29,4 +31,5 @@ class MakoModuleDescriptor(XModuleDescriptor):
return {'module': self}
def get_html(self):
- return self.system.render_template(self.mako_template, self.get_context())
+ return self.system.render_template(
+ self.mako_template, self.get_context())
diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py
index 5527d4108e..ac03d92854 100644
--- a/common/lib/xmodule/xmodule/modulestore/__init__.py
+++ b/common/lib/xmodule/xmodule/modulestore/__init__.py
@@ -45,13 +45,17 @@ class Location(_LocationBase):
"""
return re.sub('_+', '_', INVALID_CHARS.sub('_', value))
- def __new__(_cls, loc_or_tag=None, org=None, course=None, category=None, name=None, revision=None):
+ def __new__(_cls, loc_or_tag=None, org=None, course=None, category=None,
+ name=None, revision=None):
"""
Create a new location that is a clone of the specifed one.
location - Can be any of the following types:
- string: should be of the form {tag}://{org}/{course}/{category}/{name}[/{revision}]
+ string: should be of the form
+ {tag}://{org}/{course}/{category}/{name}[/{revision}]
+
list: should be of the form [tag, org, course, category, name, revision]
+
dict: should be of the form {
'tag': tag,
'org': org,
@@ -62,16 +66,19 @@ class Location(_LocationBase):
}
Location: another Location object
- In both the dict and list forms, the revision is optional, and can be ommitted.
+ In both the dict and list forms, the revision is optional, and can be
+ ommitted.
- Components must be composed of alphanumeric characters, or the characters '_', '-', and '.'
+ Components must be composed of alphanumeric characters, or the
+ characters '_', '-', and '.'
- Components may be set to None, which may be interpreted by some contexts to mean
- wildcard selection
+ Components may be set to None, which may be interpreted by some contexts
+ to mean wildcard selection
"""
- if org is None and course is None and category is None and name is None and revision is None:
+ if (org is None and course is None and category is None and
+ name is None and revision is None):
location = loc_or_tag
else:
location = (loc_or_tag, org, course, category, name, revision)
@@ -131,9 +138,11 @@ class Location(_LocationBase):
def html_id(self):
"""
- Return a string with a version of the location that is safe for use in html id attributes
+ Return a string with a version of the location that is safe for use in
+ html id attributes
"""
- return "-".join(str(v) for v in self.list() if v is not None).replace('.', '_')
+ return "-".join(str(v) for v in self.list()
+ if v is not None).replace('.', '_')
def dict(self):
"""
@@ -154,7 +163,8 @@ class Location(_LocationBase):
class ModuleStore(object):
"""
- An abstract interface for a database backend that stores XModuleDescriptor instances
+ An abstract interface for a database backend that stores XModuleDescriptor
+ instances
"""
def get_item(self, location, depth=0):
"""
@@ -164,13 +174,16 @@ class ModuleStore(object):
If any segment of the location is None except revision, raises
xmodule.modulestore.exceptions.InsufficientSpecificationError
- If no object is found at that location, raises xmodule.modulestore.exceptions.ItemNotFoundError
+
+ If no object is found at that location, raises
+ xmodule.modulestore.exceptions.ItemNotFoundError
location: Something that can be passed to Location
- depth (int): An argument that some module stores may use to prefetch descendents of the queried modules
- for more efficient results later in the request. The depth is counted in the number of
- calls to get_children() to cache. None indicates to cache all descendents
+ depth (int): An argument that some module stores may use to prefetch
+ descendents of the queried modules for more efficient results later
+ in the request. The depth is counted in the number of calls to
+ get_children() to cache. None indicates to cache all descendents
"""
raise NotImplementedError
@@ -182,9 +195,10 @@ class ModuleStore(object):
location: Something that can be passed to Location
- depth: An argument that some module stores may use to prefetch descendents of the queried modules
- for more efficient results later in the request. The depth is counted in the number of calls
- to get_children() to cache. None indicates to cache all descendents
+ depth: An argument that some module stores may use to prefetch
+ descendents of the queried modules for more efficient results later
+ in the request. The depth is counted in the number of calls to
+ get_children() to cache. None indicates to cache all descendents
"""
raise NotImplementedError
@@ -228,4 +242,3 @@ class ModuleStore(object):
in this modulestore.
'''
raise NotImplementedError
-
diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py
index 2794e27dd6..2a4c04e512 100644
--- a/common/lib/xmodule/xmodule/raw_module.py
+++ b/common/lib/xmodule/xmodule/raw_module.py
@@ -8,7 +8,7 @@ log = logging.getLogger(__name__)
class RawDescriptor(MakoModuleDescriptor, XmlDescriptor):
"""
- Module that provides a raw editing view of it's data and children
+ Module that provides a raw editing view of its data and children
"""
mako_template = "widgets/raw-edit.html"
diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py
index b39292c2ca..d435be627b 100644
--- a/common/lib/xmodule/xmodule/seq_module.py
+++ b/common/lib/xmodule/xmodule/seq_module.py
@@ -20,12 +20,15 @@ class_priority = ['video', 'problem']
class SequenceModule(XModule):
''' Layout module which lays out content in a temporal sequence
'''
- js = {'coffee': [resource_string(__name__, 'js/src/sequence/display.coffee')]}
+ js = {'coffee': [resource_string(__name__,
+ 'js/src/sequence/display.coffee')]}
css = {'scss': [resource_string(__name__, 'css/sequence/display.scss')]}
js_module_name = "Sequence"
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition, instance_state=None,
+ shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition,
+ instance_state, shared_state, **kwargs)
self.position = 1
if instance_state is not None:
@@ -92,7 +95,8 @@ class SequenceModule(XModule):
self.rendered = True
def get_icon_class(self):
- child_classes = set(child.get_icon_class() for child in self.get_children())
+ child_classes = set(child.get_icon_class()
+ for child in self.get_children())
new_class = 'other'
for c in class_priority:
if c in child_classes:
@@ -114,5 +118,6 @@ class SequenceDescriptor(MakoModuleDescriptor, XmlDescriptor):
def definition_to_xml(self, resource_fs):
xml_object = etree.Element('sequential')
for child in self.get_children():
- xml_object.append(etree.fromstring(child.export_to_xml(resource_fs)))
+ xml_object.append(
+ etree.fromstring(child.export_to_xml(resource_fs)))
return xml_object
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 996d31a83d..0c6d99fcf4 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -31,23 +31,28 @@ class Plugin(object):
def load_class(cls, identifier, default=None):
"""
Loads a single class instance specified by identifier. If identifier
- specifies more than a single class, then logs a warning and returns the first
- class identified.
+ specifies more than a single class, then logs a warning and returns the
+ first class identified.
- If default is not None, will return default if no entry_point matching identifier
- is found. Otherwise, will raise a ModuleMissingError
+ If default is not None, will return default if no entry_point matching
+ identifier is found. Otherwise, will raise a ModuleMissingError
"""
if cls._plugin_cache is None:
cls._plugin_cache = {}
if identifier not in cls._plugin_cache:
identifier = identifier.lower()
- classes = list(pkg_resources.iter_entry_points(cls.entry_point, name=identifier))
+ classes = list(pkg_resources.iter_entry_points(
+ cls.entry_point, name=identifier))
+
if len(classes) > 1:
- log.warning("Found multiple classes for {entry_point} with identifier {id}: {classes}. Returning the first one.".format(
+ log.warning("Found multiple classes for {entry_point} with "
+ "identifier {id}: {classes}. "
+ "Returning the first one.".format(
entry_point=cls.entry_point,
id=identifier,
- classes=", ".join(class_.module_name for class_ in classes)))
+ classes=", ".join(
+ class_.module_name for class_ in classes)))
if len(classes) == 0:
if default is not None:
@@ -79,9 +84,12 @@ class HTMLSnippet(object):
def get_javascript(cls):
"""
Return a dictionary containing some of the following keys:
+
coffee: A list of coffeescript fragments that should be compiled and
placed on the page
- js: A list of javascript fragments that should be included on the page
+
+ js: A list of javascript fragments that should be included on the
+ page
All of these will be loaded onto the page in the CMS
"""
@@ -91,12 +99,15 @@ class HTMLSnippet(object):
def get_css(cls):
"""
Return a dictionary containing some of the following keys:
- css: A list of css fragments that should be applied to the html contents
- of the snippet
- sass: A list of sass fragments that should be applied to the html contents
- of the snippet
- scss: A list of scss fragments that should be applied to the html contents
- of the snippet
+
+ css: A list of css fragments that should be applied to the html
+ contents of the snippet
+
+ sass: A list of sass fragments that should be applied to the html
+ contents of the snippet
+
+ scss: A list of scss fragments that should be applied to the html
+ contents of the snippet
"""
return cls.css
@@ -104,47 +115,70 @@ class HTMLSnippet(object):
"""
Return the html used to display this snippet
"""
- raise NotImplementedError("get_html() must be provided by specific modules - not present in {0}"
+ raise NotImplementedError(
+ "get_html() must be provided by specific modules - not present in {0}"
.format(self.__class__))
class XModule(HTMLSnippet):
''' Implements a generic learning module.
- Subclasses must at a minimum provide a definition for get_html in order to be displayed to users.
+ Subclasses must at a minimum provide a definition for get_html in order
+ to be displayed to users.
See the HTML module for a simple example.
'''
- # The default implementation of get_icon_class returns the icon_class attribute of the class
- # This attribute can be overridden by subclasses, and the function can also be overridden
- # if the icon class depends on the data in the module
+ # The default implementation of get_icon_class returns the icon_class
+ # attribute of the class
+ #
+ # This attribute can be overridden by subclasses, and
+ # the function can also be overridden if the icon class depends on the data
+ # in the module
icon_class = 'other'
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
+ def __init__(self, system, location, definition,
+ instance_state=None, shared_state=None, **kwargs):
'''
Construct a new xmodule
system: A ModuleSystem allowing access to external resources
+
location: Something Location-like that identifies this xmodule
- definition: A dictionary containing 'data' and 'children'. Both are optional
- 'data': is JSON-like (string, dictionary, list, bool, or None, optionally nested).
- This defines all of the data necessary for a problem to display that is intrinsic to the problem.
- It should not include any data that would vary between two courses using the same problem
+
+ definition: A dictionary containing 'data' and 'children'. Both are
+ optional
+
+ 'data': is JSON-like (string, dictionary, list, bool, or None,
+ optionally nested).
+
+ This defines all of the data necessary for a problem to display
+ that is intrinsic to the problem. It should not include any
+ data that would vary between two courses using the same problem
(due dates, grading policy, randomization, etc.)
- 'children': is a list of Location-like values for child modules that this module depends on
- instance_state: A string of serialized json that contains the state of this module for
- current student accessing the system, or None if no state has been saved
- shared_state: A string of serialized json that contains the state that is shared between
- this module and any modules of the same type with the same shared_state_key. This
- state is only shared per-student, not across different students
- kwargs: Optional arguments. Subclasses should always accept kwargs and pass them
- to the parent class constructor.
+
+ 'children': is a list of Location-like values for child modules that
+ this module depends on
+
+ instance_state: A string of serialized json that contains the state of
+ this module for current student accessing the system, or None if
+ no state has been saved
+
+ shared_state: A string of serialized json that contains the state that
+ is shared between this module and any modules of the same type with
+ the same shared_state_key. This state is only shared per-student,
+ not across different students
+
+ kwargs: Optional arguments. Subclasses should always accept kwargs and
+ pass them to the parent class constructor.
+
Current known uses of kwargs:
- metadata: SCAFFOLDING - This dictionary will be split into several different types of metadata
- in the future (course policy, modification history, etc).
- A dictionary containing data that specifies information that is particular
- to a problem in the context of a course
+
+ metadata: SCAFFOLDING - This dictionary will be split into
+ several different types of metadata in the future (course
+ policy, modification history, etc). A dictionary containing
+ data that specifies information that is particular to a
+ problem in the context of a course
'''
self.system = system
self.location = Location(location)
@@ -217,16 +251,21 @@ class XModule(HTMLSnippet):
def max_score(self):
''' Maximum score. Two notes:
- * This is generic; in abstract, a problem could be 3/5 points on one randomization, and 5/7 on another
- * In practice, this is a Very Bad Idea, and (a) will break some code in place (although that code
- should get fixed), and (b) break some analytics we plan to put in place.
+
+ * This is generic; in abstract, a problem could be 3/5 points on one
+ randomization, and 5/7 on another
+
+ * In practice, this is a Very Bad Idea, and (a) will break some code
+ in place (although that code should get fixed), and (b) break some
+ analytics we plan to put in place.
'''
return None
def get_progress(self):
- ''' Return a progress.Progress object that represents how far the student has gone
- in this module. Must be implemented to get correct progress tracking behavior in
- nesting modules like sequence and vertical.
+ ''' Return a progress.Progress object that represents how far the
+ student has gone in this module. Must be implemented to get correct
+ progress tracking behavior in nesting modules like sequence and
+ vertical.
If this module has no notion of progress, return None.
'''
@@ -240,13 +279,14 @@ class XModule(HTMLSnippet):
class XModuleDescriptor(Plugin, HTMLSnippet):
"""
- An XModuleDescriptor is a specification for an element of a course. This could
- be a problem, an organizational element (a group of content), or a segment of video,
- for example.
+ An XModuleDescriptor is a specification for an element of a course. This
+ could be a problem, an organizational element (a group of content), or a
+ segment of video, for example.
- XModuleDescriptors are independent and agnostic to the current student state on a
- problem. They handle the editing interface used by instructors to create a problem,
- and can generate XModules (which do know about student state).
+ XModuleDescriptors are independent and agnostic to the current student state
+ on a problem. They handle the editing interface used by instructors to
+ create a problem, and can generate XModules (which do know about student
+ state).
"""
entry_point = "xmodule.v1"
module_class = XModule
@@ -255,46 +295,58 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
inheritable_metadata = (
'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize',
- # This is used by the XMLModuleStore to provide for locations for static files,
- # and will need to be removed when that code is removed
+ # TODO: This is used by the XMLModuleStore to provide for locations for
+ # static files, and will need to be removed when that code is removed
'data_dir'
)
- # A list of descriptor attributes that must be equal for the descriptors to be
- # equal
- equality_attributes = ('definition', 'metadata', 'location', 'shared_state_key', '_inherited_metadata')
+ # A list of descriptor attributes that must be equal for the descriptors to
+ # be equal
+ equality_attributes = ('definition', 'metadata', 'location',
+ 'shared_state_key', '_inherited_metadata')
- # ============================= STRUCTURAL MANIPULATION ===========================
+ # ============================= STRUCTURAL MANIPULATION ===================
def __init__(self,
system,
definition=None,
**kwargs):
"""
Construct a new XModuleDescriptor. The only required arguments are the
- system, used for interaction with external resources, and the definition,
- which specifies all the data needed to edit and display the problem (but none
- of the associated metadata that handles recordkeeping around the problem).
+ system, used for interaction with external resources, and the
+ definition, which specifies all the data needed to edit and display the
+ problem (but none of the associated metadata that handles recordkeeping
+ around the problem).
- This allows for maximal flexibility to add to the interface while preserving
- backwards compatibility.
+ This allows for maximal flexibility to add to the interface while
+ preserving backwards compatibility.
- system: An XModuleSystem for interacting with external resources
- definition: A dict containing `data` and `children` representing the problem definition
+ system: A DescriptorSystem for interacting with external resources
+
+ definition: A dict containing `data` and `children` representing the
+ problem definition
Current arguments passed in kwargs:
- location: A xmodule.modulestore.Location object indicating the name and ownership of this problem
- shared_state_key: The key to use for sharing StudentModules with other
- modules of this type
+
+ location: A xmodule.modulestore.Location object indicating the name
+ and ownership of this problem
+
+ shared_state_key: The key to use for sharing StudentModules with
+ other modules of this type
+
metadata: A dictionary containing the following optional keys:
- goals: A list of strings of learning goals associated with this module
- display_name: The name to use for displaying this module to the user
+ goals: A list of strings of learning goals associated with this
+ module
+ display_name: The name to use for displaying this module to the
+ user
format: The format of this module ('Homework', 'Lab', etc)
graded (bool): Whether this module is should be graded or not
start (string): The date for which this module will be available
due (string): The due date for this module
- graceperiod (string): The amount of grace period to allow when enforcing the due date
+ graceperiod (string): The amount of grace period to allow when
+ enforcing the due date
showanswer (string): When to show answers for this module
- rerandomize (string): When to generate a newly randomized instance of the module data
+ rerandomize (string): When to generate a newly randomized
+ instance of the module data
"""
self.system = system
self.metadata = kwargs.get('metadata', {})
@@ -321,7 +373,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
self.metadata[attr] = metadata[attr]
def get_children(self):
- """Returns a list of XModuleDescriptor instances for the children of this module"""
+ """Returns a list of XModuleDescriptor instances for the children of
+ this module"""
if self._child_instances is None:
self._child_instances = []
for child_loc in self.definition.get('children', []):
@@ -333,8 +386,9 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
def xmodule_constructor(self, system):
"""
- Returns a constructor for an XModule. This constructor takes two arguments:
- instance_state and shared_state, and returns a fully nstantiated XModule
+ Returns a constructor for an XModule. This constructor takes two
+ arguments: instance_state and shared_state, and returns a fully
+ instantiated XModule
"""
return partial(
self.module_class,
@@ -344,7 +398,7 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
metadata=self.metadata
)
- # ================================= JSON PARSING ===================================
+ # ================================= JSON PARSING ===========================
@staticmethod
def load_from_json(json_data, system, default_class=None):
"""
@@ -366,13 +420,14 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
Creates an instance of this descriptor from the supplied json_data.
This may be overridden by subclasses
- json_data: A json object specifying the definition and any optional keyword arguments for
- the XModuleDescriptor
- system: An XModuleSystem for interacting with external resources
+ json_data: A json object specifying the definition and any optional
+ keyword arguments for the XModuleDescriptor
+
+ system: A DescriptorSystem for interacting with external resources
"""
return cls(system=system, **json_data)
- # ================================= XML PARSING ====================================
+ # ================================= XML PARSING ============================
@staticmethod
def load_from_xml(xml_data,
system,
@@ -487,24 +542,33 @@ class ModuleSystem(object):
'''
def __init__(self, ajax_url, track_function,
get_module, render_template, replace_urls,
- user=None, filestore=None, debug=False, xqueue_callback_url=None):
+ user=None, filestore=None, debug=False,
+ xqueue_callback_url=None):
'''
Create a closure around the system environment.
ajax_url - the url where ajax calls to the encapsulating module go.
+
track_function - function of (event_type, event), intended for logging
or otherwise tracking the event.
TODO: Not used, and has inconsistent args in different
files. Update or remove.
+
get_module - function that takes (location) and returns a corresponding
- module instance object.
- render_template - a function that takes (template_file, context), and returns
- rendered html.
- user - The user to base the random number generator seed off of for this request
- filestore - A filestore ojbect. Defaults to an instance of OSFS based at
- settings.DATA_DIR.
+ module instance object.
+
+ render_template - a function that takes (template_file, context), and
+ returns rendered html.
+
+ user - The user to base the random number generator seed off of for this
+ request
+
+ filestore - A filestore ojbect. Defaults to an instance of OSFS based
+ at settings.DATA_DIR.
+
replace_urls - TEMPORARY - A function like static_replace.replace_urls
- that capa_module can use to fix up the static urls in ajax results.
+ that capa_module can use to fix up the static urls in
+ ajax results.
'''
self.ajax_url = ajax_url
self.xqueue_callback_url = xqueue_callback_url
@@ -529,4 +593,3 @@ class ModuleSystem(object):
def __str__(self):
return str(self.__dict__)
-
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index a7fc686e45..49e0f79976 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -13,13 +13,19 @@ log = logging.getLogger(__name__)
# TODO (cpennington): This was implemented in an attempt to improve performance,
# but the actual improvement wasn't measured (and it was implemented late at night).
# We should check if it hurts, and whether there's a better way of doing lazy loading
+
class LazyLoadingDict(MutableMapping):
"""
- A dictionary object that lazily loads it's contents from a provided
- function on reads (of members that haven't already been set)
+ A dictionary object that lazily loads its contents from a provided
+ function on reads (of members that haven't already been set).
"""
def __init__(self, loader):
+ '''
+ On the first read from this dictionary, it will call loader() to
+ populate its contents. loader() must return something dict-like. Any
+ elements set before the first read will be preserved.
+ '''
self._contents = {}
self._loaded = False
self._loader = loader
@@ -70,10 +76,12 @@ _AttrMapBase = namedtuple('_AttrMap', 'metadata_key to_metadata from_metadata')
class AttrMap(_AttrMapBase):
"""
- A class that specifies a metadata_key, a function to transform an xml attribute to be placed in that key,
- and to transform that key value
+ A class that specifies a metadata_key, a function to transform an xml
+ attribute to be placed in that key, and to transform that key value
"""
- def __new__(_cls, metadata_key, to_metadata=lambda x: x, from_metadata=lambda x: x):
+ def __new__(_cls, metadata_key,
+ to_metadata=lambda x: x,
+ from_metadata=lambda x: x):
return _AttrMapBase.__new__(_cls, metadata_key, to_metadata, from_metadata)
@@ -93,7 +101,9 @@ class XmlDescriptor(XModuleDescriptor):
# A dictionary mapping xml attribute names to functions of the value
# that return the metadata key and value
xml_attribute_map = {
- 'graded': AttrMap('graded', lambda val: val == 'true', lambda val: str(val).lower()),
+ 'graded': AttrMap('graded',
+ lambda val: val == 'true',
+ lambda val: str(val).lower()),
'name': AttrMap('display_name'),
}
@@ -105,12 +115,14 @@ class XmlDescriptor(XModuleDescriptor):
xml_object: An etree Element
"""
- raise NotImplementedError("%s does not implement definition_from_xml" % cls.__name__)
+ raise NotImplementedError(
+ "%s does not implement definition_from_xml" % cls.__name__)
@classmethod
def clean_metadata_from_xml(cls, xml_object):
"""
- Remove any attribute named in self.metadata_attributes from the supplied xml_object
+ Remove any attribute named in cls.metadata_attributes from the supplied
+ xml_object
"""
for attr in cls.metadata_attributes:
if xml_object.get(attr) is not None:
@@ -134,7 +146,7 @@ class XmlDescriptor(XModuleDescriptor):
xml_data: A string of xml that will be translated into data and children for
this module
- system: An XModuleSystem for interacting with external resources
+ system: A DescriptorSystem for interacting with external resources
org and course are optional strings that will be used in the generated modules
url identifiers
"""
@@ -157,6 +169,7 @@ class XmlDescriptor(XModuleDescriptor):
else:
filepath = cls._format_filepath(xml_object.tag, filename)
+ # VS[compat]
# TODO (cpennington): If the file doesn't exist at the right path,
# give the class a chance to fix it up. The file will be written out again
# in the correct format.
@@ -243,4 +256,5 @@ class XmlDescriptor(XModuleDescriptor):
"""
Return a new etree Element object created from this modules definition.
"""
- raise NotImplementedError("%s does not implement definition_to_xml" % self.__class__.__name__)
+ raise NotImplementedError(
+ "%s does not implement definition_to_xml" % self.__class__.__name__)
From 5f84e6192520b31170074616bde1dffe672fb910 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:06:18 -0400
Subject: [PATCH 04/55] Add hook for error handling during xml import
* add error_handler member to DescriptorSystem
* call it where import errors happen
* also includes some refactoring in xml.py
* some more line length and docstring cleanups
---
.../lib/xmodule/xmodule/backcompat_module.py | 2 +
common/lib/xmodule/xmodule/errorhandlers.py | 25 +++
common/lib/xmodule/xmodule/modulestore/xml.py | 200 +++++++++++-------
common/lib/xmodule/xmodule/raw_module.py | 11 +-
common/lib/xmodule/xmodule/x_module.py | 111 +++++++---
common/lib/xmodule/xmodule/xml_module.py | 28 ++-
6 files changed, 251 insertions(+), 126 deletions(-)
create mode 100644 common/lib/xmodule/xmodule/errorhandlers.py
diff --git a/common/lib/xmodule/xmodule/backcompat_module.py b/common/lib/xmodule/xmodule/backcompat_module.py
index c040eca398..456a2c2b07 100644
--- a/common/lib/xmodule/xmodule/backcompat_module.py
+++ b/common/lib/xmodule/xmodule/backcompat_module.py
@@ -29,6 +29,7 @@ def process_includes(fn):
etree.tostring(next_include, pretty_print=True))
msg += 'Cannot find file %s in %s' % (file, dir)
log.exception(msg)
+ system.error_handler(msg)
raise
try:
# read in and convert to XML
@@ -38,6 +39,7 @@ def process_includes(fn):
etree.tostring(next_include, pretty_print=True))
msg += 'Cannot parse XML in %s' % (file)
log.exception(msg)
+ system.error_handler(msg)
raise
# insert new XML into tree in place of inlcude
parent = next_include.getparent()
diff --git a/common/lib/xmodule/xmodule/errorhandlers.py b/common/lib/xmodule/xmodule/errorhandlers.py
new file mode 100644
index 0000000000..6840d9ff74
--- /dev/null
+++ b/common/lib/xmodule/xmodule/errorhandlers.py
@@ -0,0 +1,25 @@
+import sys
+
+def strict_error_handler(msg, exc_info=None):
+ '''
+ Do not let errors pass. If exc_info is not None, ignore msg, and just
+ re-raise. Otherwise, check if we are in an exception-handling context.
+ If so, re-raise. Otherwise, raise Exception(msg).
+
+ Meant for use in validation, where any errors should trap.
+ '''
+ if exc_info is not None:
+ raise exc_info[0], exc_info[1], exc_info[2]
+
+ # Check if there is an exception being handled somewhere up the stack
+ if sys.exc_info() != (None, None, None):
+ raise
+
+ raise Exception(msg)
+
+
+def ignore_errors_handler(msg, exc_info=None):
+ '''Ignore all errors, relying on the caller to workaround.
+ Meant for use in the LMS, where an error in one part of the course
+ shouldn't bring down the whole system'''
+ pass
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 3981009cef..8965f3d028 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -3,6 +3,7 @@ from fs.osfs import OSFS
from importlib import import_module
from lxml import etree
from path import path
+from xmodule.errorhandlers import strict_error_handler
from xmodule.x_module import XModuleDescriptor, XMLParsingSystem
from xmodule.mako_module import MakoDescriptorSystem
from cStringIO import StringIO
@@ -18,32 +19,112 @@ etree.set_default_parser(etree.XMLParser(dtd_validation=False, load_dtd=False,
log = logging.getLogger('mitx.' + __name__)
-# TODO (cpennington): Remove this once all fall 2012 courses have been imported into the cms from xml
+# VS[compat]
+# TODO (cpennington): Remove this once all fall 2012 courses have been imported
+# into the cms from xml
def clean_out_mako_templating(xml_string):
xml_string = xml_string.replace('%include', 'include')
xml_string = re.sub("(?m)^\s*%.*$", '', xml_string)
return xml_string
+class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
+ def __init__(self, xmlstore, org, course, course_dir,
+ error_handler):
+ """
+ A class that handles loading from xml. Does some munging to ensure that
+ all elements have unique slugs.
+
+ xmlstore: the XMLModuleStore to store the loaded modules in
+ """
+ self.unnamed_modules = 0
+ self.used_slugs = set()
+
+ def process_xml(xml):
+ try:
+ # VS[compat]
+ # TODO (cpennington): Remove this once all fall 2012 courses
+ # have been imported into the cms from xml
+ xml = clean_out_mako_templating(xml)
+ xml_data = etree.fromstring(xml)
+ except:
+ log.exception("Unable to parse xml: {xml}".format(xml=xml))
+ raise
+
+ # TODO (vshnayder): is the slug munging permanent, or also intended
+ # to be taken out?
+ if xml_data.get('slug') is None:
+ if xml_data.get('name'):
+ slug = Location.clean(xml_data.get('name'))
+ else:
+ self.unnamed_modules += 1
+ slug = '{tag}_{count}'.format(tag=xml_data.tag,
+ count=self.unnamed_modules)
+
+ if slug in self.used_slugs:
+ self.unnamed_modules += 1
+ slug = '{slug}_{count}'.format(slug=slug,
+ count=self.unnamed_modules)
+
+ self.used_slugs.add(slug)
+ # log.debug('-> slug=%s' % slug)
+ xml_data.set('slug', slug)
+
+ module = XModuleDescriptor.load_from_xml(
+ etree.tostring(xml_data), self, org,
+ course, xmlstore.default_class)
+
+ log.debug('==> importing module location %s' % repr(module.location))
+ module.metadata['data_dir'] = course_dir
+
+ xmlstore.modules[module.location] = module
+
+ if xmlstore.eager:
+ module.get_children()
+ return module
+
+ system_kwargs = dict(
+ render_template=lambda: '',
+ load_item=xmlstore.get_item,
+ resources_fs=OSFS(xmlstore.data_dir / course_dir),
+ process_xml=process_xml,
+ error_handler=error_handler,
+ )
+ MakoDescriptorSystem.__init__(self, **system_kwargs)
+ XMLParsingSystem.__init__(self, **system_kwargs)
+
+
class XMLModuleStore(ModuleStore):
"""
An XML backed ModuleStore
"""
- def __init__(self, data_dir, default_class=None, eager=False, course_dirs=None):
+ def __init__(self, data_dir, default_class=None, eager=False,
+ course_dirs=None,
+ error_handler=strict_error_handler):
"""
Initialize an XMLModuleStore from data_dir
data_dir: path to data directory containing the course directories
- default_class: dot-separated string defining the default descriptor class to use if non is specified in entry_points
- eager: If true, load the modules children immediately to force the entire course tree to be parsed
- course_dirs: If specified, the list of course_dirs to load. Otherwise, load
- all course dirs
+
+ default_class: dot-separated string defining the default descriptor
+ class to use if none is specified in entry_points
+
+ eager: If true, load the modules children immediately to force the
+ entire course tree to be parsed
+
+ course_dirs: If specified, the list of course_dirs to load. Otherwise,
+ load all course dirs
+
+ error_handler: The error handler used here and in the underlying
+ DescriptorSystem. By default, raise exceptions for all errors.
+ See the comments in x_module.py:DescriptorSystem
"""
self.eager = eager
self.data_dir = path(data_dir)
self.modules = {} # location -> XModuleDescriptor
self.courses = {} # course_dir -> XModuleDescriptor for the course
+ self.error_handler = error_handler
if default_class is None:
self.default_class = None
@@ -54,110 +135,63 @@ class XMLModuleStore(ModuleStore):
self.default_class = class_
# TODO (cpennington): We need a better way of selecting specific sets of debug messages to enable. These were drowning out important messages
- #log.debug('XMLModuleStore: eager=%s, data_dir = %s' % (eager, self.data_dir))
- #log.debug('default_class = %s' % self.default_class)
+ log.debug('XMLModuleStore: eager=%s, data_dir = %s' % (eager, self.data_dir))
+ log.debug('default_class = %s' % self.default_class)
- for course_dir in os.listdir(self.data_dir):
- if course_dirs is not None and course_dir not in course_dirs:
- continue
-
- if not os.path.exists(self.data_dir / course_dir / "course.xml"):
- continue
+ # If we are specifically asked for missing courses, that should
+ # be an error. If we are asked for "all" courses, find the ones
+ # that have a course.xml
+ if course_dirs is None:
+ course_dirs = [d for d in os.listdir(self.data_dir) if
+ os.path.exists(self.data_dir / d / "course.xml")]
+ for course_dir in course_dirs:
try:
course_descriptor = self.load_course(course_dir)
self.courses[course_dir] = course_descriptor
except:
- log.exception("Failed to load course %s" % course_dir)
+ msg = "Failed to load course '%s'" % course_dir
+ log.exception(msg)
+ error_handler(msg)
+
def load_course(self, course_dir):
"""
Load a course into this module store
course_path: Course directory name
+
+ returns a CourseDescriptor for the course
"""
with open(self.data_dir / course_dir / "course.xml") as course_file:
- # TODO (cpennington): Remove this once all fall 2012 courses have been imported
- # into the cms from xml
+ # VS[compat]
+ # TODO (cpennington): Remove this once all fall 2012 courses have
+ # been imported into the cms from xml
course_file = StringIO(clean_out_mako_templating(course_file.read()))
course_data = etree.parse(course_file).getroot()
org = course_data.get('org')
if org is None:
- log.error(
- "No 'org' attribute set for course in {dir}. Using default 'edx'".format(
- dir=course_dir))
+ log.error("No 'org' attribute set for course in {dir}. "
+ "Using default 'edx'".format(dir=course_dir))
org = 'edx'
course = course_data.get('course')
if course is None:
- log.error(
- "No 'course' attribute set for course in {dir}. Using default '{default}'".format(
- dir=course_dir,
- default=course_dir
- ))
+ log.error("No 'course' attribute set for course in {dir}."
+ " Using default '{default}'".format(
+ dir=course_dir,
+ default=course_dir
+ ))
course = course_dir
- class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
- def __init__(self, xmlstore):
- """
- xmlstore: the XMLModuleStore to store the loaded modules in
- """
- self.unnamed_modules = 0
- self.used_slugs = set()
+ system = ImportSystem(self, org, course, course_dir,
+ self.error_handler)
- def process_xml(xml):
- try:
- # TODO (cpennington): Remove this once all fall 2012 courses
- # have been imported into the cms from xml
- xml = clean_out_mako_templating(xml)
- xml_data = etree.fromstring(xml)
- except:
- log.exception("Unable to parse xml: {xml}".format(xml=xml))
- raise
- if xml_data.get('slug') is None:
- if xml_data.get('name'):
- slug = Location.clean(xml_data.get('name'))
- else:
- self.unnamed_modules += 1
- slug = '{tag}_{count}'.format(tag=xml_data.tag,
- count=self.unnamed_modules)
-
- if slug in self.used_slugs:
- self.unnamed_modules += 1
- slug = '{slug}_{count}'.format(slug=slug,
- count=self.unnamed_modules)
-
- self.used_slugs.add(slug)
- # log.debug('-> slug=%s' % slug)
- xml_data.set('slug', slug)
-
- module = XModuleDescriptor.load_from_xml(
- etree.tostring(xml_data), self, org,
- course, xmlstore.default_class)
- log.debug('==> importing module location %s' % repr(module.location))
- module.metadata['data_dir'] = course_dir
-
- xmlstore.modules[module.location] = module
-
- if xmlstore.eager:
- module.get_children()
- return module
-
- system_kwargs = dict(
- render_template=lambda: '',
- load_item=xmlstore.get_item,
- resources_fs=OSFS(xmlstore.data_dir / course_dir),
- process_xml=process_xml
- )
- MakoDescriptorSystem.__init__(self, **system_kwargs)
- XMLParsingSystem.__init__(self, **system_kwargs)
-
-
- course_descriptor = ImportSystem(self).process_xml(etree.tostring(course_data))
+ course_descriptor = system.process_xml(etree.tostring(course_data))
log.debug('========> Done with course import')
return course_descriptor
@@ -169,7 +203,9 @@ class XMLModuleStore(ModuleStore):
If any segment of the location is None except revision, raises
xmodule.modulestore.exceptions.InsufficientSpecificationError
- If no object is found at that location, raises xmodule.modulestore.exceptions.ItemNotFoundError
+
+ If no object is found at that location, raises
+ xmodule.modulestore.exceptions.ItemNotFoundError
location: Something that can be passed to Location
"""
diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py
index 2a4c04e512..d8c18b251a 100644
--- a/common/lib/xmodule/xmodule/raw_module.py
+++ b/common/lib/xmodule/xmodule/raw_module.py
@@ -31,8 +31,11 @@ class RawDescriptor(MakoModuleDescriptor, XmlDescriptor):
except etree.XMLSyntaxError as err:
lines = self.definition['data'].split('\n')
line, offset = err.position
- log.exception("Unable to create xml for problem {loc}. Context: '{context}'".format(
- context=lines[line-1][offset - 40:offset + 40],
- loc=self.location
- ))
+ msg = ("Unable to create xml for problem {loc}. "
+ "Context: '{context}'".format(
+ context=lines[line-1][offset - 40:offset + 40],
+ loc=self.location))
+ log.exception(msg)
+ self.system.error_handler(msg)
+ # no workaround possible, so just re-raise
raise
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 0c6d99fcf4..3e564053bd 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -203,13 +203,16 @@ class XModule(HTMLSnippet):
Return module instances for all the children of this module.
'''
if self._loaded_children is None:
- self._loaded_children = [self.system.get_module(child) for child in self.definition.get('children', [])]
+ self._loaded_children = [
+ self.system.get_module(child)
+ for child in self.definition.get('children', [])]
+
return self._loaded_children
def get_display_items(self):
'''
- Returns a list of descendent module instances that will display immediately
- inside this module
+ Returns a list of descendent module instances that will display
+ immediately inside this module
'''
items = []
for child in self.get_children():
@@ -219,8 +222,8 @@ class XModule(HTMLSnippet):
def displayable_items(self):
'''
- Returns list of displayable modules contained by this module. If this module
- is visible, should return [self]
+ Returns list of displayable modules contained by this module. If this
+ module is visible, should return [self]
'''
return [self]
@@ -439,16 +442,19 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
on the contents of xml_data.
xml_data must be a string containing valid xml
+
system is an XMLParsingSystem
- org and course are optional strings that will be used in the generated modules
- url identifiers
+
+ org and course are optional strings that will be used in the generated
+ modules url identifiers
"""
class_ = XModuleDescriptor.load_class(
etree.fromstring(xml_data).tag,
default_class
)
- # leave next line in code, commented out - useful for low-level debugging
- # log.debug('[XModuleDescriptor.load_from_xml] tag=%s, class_=%s' % (etree.fromstring(xml_data).tag,class_))
+ # leave next line, commented out - useful for low-level debugging
+ log.debug('[XModuleDescriptor.load_from_xml] tag=%s, class_=%s' % (
+ etree.fromstring(xml_data).tag,class_))
return class_.from_xml(xml_data, system, org, course)
@classmethod
@@ -457,35 +463,42 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
Creates an instance of this descriptor from the supplied xml_data.
This may be overridden by subclasses
- xml_data: A string of xml that will be translated into data and children for
- this module
+ xml_data: A string of xml that will be translated into data and children
+ for this module
+
system is an XMLParsingSystem
- org and course are optional strings that will be used in the generated modules
- url identifiers
+
+ org and course are optional strings that will be used in the generated
+ module's url identifiers
"""
- raise NotImplementedError('Modules must implement from_xml to be parsable from xml')
+ raise NotImplementedError(
+ 'Modules must implement from_xml to be parsable from xml')
def export_to_xml(self, resource_fs):
"""
- Returns an xml string representing this module, and all modules underneath it.
- May also write required resources out to resource_fs
+ Returns an xml string representing this module, and all modules
+ underneath it. May also write required resources out to resource_fs
- Assumes that modules have single parantage (that no module appears twice in the same course),
- and that it is thus safe to nest modules as xml children as appropriate.
+ Assumes that modules have single parentage (that no module appears twice
+ in the same course), and that it is thus safe to nest modules as xml
+ children as appropriate.
- The returned XML should be able to be parsed back into an identical XModuleDescriptor
- using the from_xml method with the same system, org, and course
+ The returned XML should be able to be parsed back into an identical
+ XModuleDescriptor using the from_xml method with the same system, org,
+ and course
"""
- raise NotImplementedError('Modules must implement export_to_xml to enable xml export')
+ raise NotImplementedError(
+ 'Modules must implement export_to_xml to enable xml export')
- # =============================== Testing ===================================
+ # =============================== Testing ==================================
def get_sample_state(self):
"""
- Return a list of tuples of instance_state, shared_state. Each tuple defines a sample case for this module
+ Return a list of tuples of instance_state, shared_state. Each tuple
+ defines a sample case for this module
"""
return [('{}', '{}')]
- # =============================== BUILTIN METHODS ===========================
+ # =============================== BUILTIN METHODS ==========================
def __eq__(self, other):
eq = (self.__class__ == other.__class__ and
all(getattr(self, attr, None) == getattr(other, attr, None)
@@ -493,38 +506,76 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
if not eq:
for attr in self.equality_attributes:
- print getattr(self, attr, None), getattr(other, attr, None), getattr(self, attr, None) == getattr(other, attr, None)
+ print(getattr(self, attr, None),
+ getattr(other, attr, None),
+ getattr(self, attr, None) == getattr(other, attr, None))
return eq
def __repr__(self):
- return "{class_}({system!r}, {definition!r}, location={location!r}, metadata={metadata!r})".format(
+ return ("{class_}({system!r}, {definition!r}, location={location!r},"
+ " metadata={metadata!r})".format(
class_=self.__class__.__name__,
system=self.system,
definition=self.definition,
location=self.location,
metadata=self.metadata
- )
+ ))
class DescriptorSystem(object):
- def __init__(self, load_item, resources_fs, **kwargs):
+ def __init__(self, load_item, resources_fs,
+ error_handler,
+ **kwargs):
"""
load_item: Takes a Location and returns an XModuleDescriptor
+
resources_fs: A Filesystem object that contains all of the
resources needed for the course
+
+ error_handler: A hook for handling errors in loading the descriptor.
+ Must be a function of (error_msg, exc_info=None).
+ See errorhandlers.py for some simple ones.
+
+ Patterns for using the error handler:
+ try:
+ x = access_some_resource()
+ check_some_format(x)
+ except SomeProblem:
+ msg = 'Grommet {0} is broken'.format(x)
+ log.exception(msg) # don't rely on handler to log
+ self.system.error_handler(msg)
+ # if we get here, work around if possible
+ raise # if no way to work around
+ OR
+ return 'Oops, couldn't load grommet'
+
+ OR, if not in an exception context:
+
+ if not check_something(thingy):
+ msg = "thingy {0} is broken".format(thingy)
+ log.critical(msg)
+ error_handler(msg)
+ # if we get here, work around
+ pass # e.g. if no workaround needed
"""
self.load_item = load_item
self.resources_fs = resources_fs
+ self.error_handler = error_handler
class XMLParsingSystem(DescriptorSystem):
def __init__(self, load_item, resources_fs, process_xml, **kwargs):
"""
- process_xml: Takes an xml string, and returns the the XModuleDescriptor created from that xml
+ load_item: Takes a Location and returns an XModuleDescriptor
+
+ process_xml: Takes an xml string, and returns a XModuleDescriptor
+ created from that xml
+
+
"""
- DescriptorSystem.__init__(self, load_item, resources_fs)
+ DescriptorSystem.__init__(self, load_item, resources_fs, **kwargs)
self.process_xml = process_xml
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 49e0f79976..0b627ad4ee 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -187,7 +187,10 @@ class XmlDescriptor(XModuleDescriptor):
with system.resources_fs.open(filepath) as file:
definition_xml = cls.file_to_xml(file)
except (ResourceNotFoundError, etree.XMLSyntaxError):
- log.exception('Unable to load file contents at path %s' % filepath)
+ msg = 'Unable to load file contents at path %s' % filepath
+ log.exception(msg)
+ system.error_handler(msg)
+ # if error_handler didn't reraise, work around it.
return {'data': 'Error loading file contents at path %s' % filepath}
cls.clean_metadata_from_xml(definition_xml)
@@ -206,20 +209,24 @@ class XmlDescriptor(XModuleDescriptor):
@classmethod
def _format_filepath(cls, category, name):
- return u'{category}/{name}.{ext}'.format(category=category, name=name, ext=cls.filename_extension)
+ return u'{category}/{name}.{ext}'.format(category=category,
+ name=name,
+ ext=cls.filename_extension)
def export_to_xml(self, resource_fs):
"""
- Returns an xml string representing this module, and all modules underneath it.
- May also write required resources out to resource_fs
+ Returns an xml string representing this module, and all modules
+ underneath it. May also write required resources out to resource_fs
- Assumes that modules have single parantage (that no module appears twice in the same course),
- and that it is thus safe to nest modules as xml children as appropriate.
+ Assumes that modules have single parentage (that no module appears twice
+ in the same course), and that it is thus safe to nest modules as xml
+ children as appropriate.
- The returned XML should be able to be parsed back into an identical XModuleDescriptor
- using the from_xml method with the same system, org, and course
+ The returned XML should be able to be parsed back into an identical
+ XModuleDescriptor using the from_xml method with the same system, org,
+ and course
- resource_fs is a pyfilesystem office (from the fs package)
+ resource_fs is a pyfilesystem object (from the fs package)
"""
xml_object = self.definition_to_xml(resource_fs)
self.__class__.clean_metadata_from_xml(xml_object)
@@ -244,7 +251,8 @@ class XmlDescriptor(XModuleDescriptor):
attr_map = self.xml_attribute_map.get(attr, AttrMap(attr))
metadata_key = attr_map.metadata_key
- if metadata_key not in self.metadata or metadata_key in self._inherited_metadata:
+ if (metadata_key not in self.metadata or
+ metadata_key in self._inherited_metadata):
continue
val = attr_map.from_metadata(self.metadata[metadata_key])
From e0513f5f244eee289b615230bdcdf65a14e06130 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:07:12 -0400
Subject: [PATCH 05/55] Fix course tag name on export of definition
---
common/lib/xmodule/xmodule/xml_module.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 0b627ad4ee..9cf744461d 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -231,6 +231,8 @@ class XmlDescriptor(XModuleDescriptor):
xml_object = self.definition_to_xml(resource_fs)
self.__class__.clean_metadata_from_xml(xml_object)
+ xml_object.tag = self.category
+ xml_object.set('slug', self.name)
# Put content in a separate file if it's large (has more than 5 descendent tags)
if len(list(xml_object.iter())) > 5:
@@ -244,9 +246,6 @@ class XmlDescriptor(XModuleDescriptor):
xml_object.set('filename', self.name)
- xml_object.set('slug', self.name)
- xml_object.tag = self.category
-
for attr in self.metadata_attributes:
attr_map = self.xml_attribute_map.get(attr, AttrMap(attr))
metadata_key = attr_map.metadata_key
From 94ac61ffe2121c67acb61e6e82c73faa518f9f9a Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:08:53 -0400
Subject: [PATCH 06/55] Make decision about export file splitting overrideable
* create split_to_file() function
* chapters, html, problems always split
* course never split
* others based on size of subtree for now
---
common/lib/xmodule/xmodule/capa_module.py | 5 +++++
common/lib/xmodule/xmodule/html_module.py | 5 +++++
common/lib/xmodule/xmodule/seq_module.py | 14 ++++++++++++++
common/lib/xmodule/xmodule/xml_module.py | 20 +++++++++++++++++---
4 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 5ff0c13198..735f664b0a 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -550,6 +550,7 @@ class CapaDescriptor(RawDescriptor):
module_class = CapaModule
+ # VS[compat]
# TODO (cpennington): Delete this method once all fall 2012 course are being
# edited in the cms
@classmethod
@@ -558,3 +559,7 @@ class CapaDescriptor(RawDescriptor):
'problems/' + path[8:],
path[8:],
]
+ @classmethod
+ def split_to_file(cls, xml_object):
+ '''Problems always written in their own files'''
+ return True
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 97509c6f34..ce18a05a8a 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -42,3 +42,8 @@ class HtmlDescriptor(RawDescriptor):
def file_to_xml(cls, file_object):
parser = etree.HTMLParser()
return etree.parse(file_object, parser).getroot()
+
+ @classmethod
+ def split_to_file(cls, xml_object):
+ # never include inline html
+ return True
diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py
index d435be627b..5f7f41bf8d 100644
--- a/common/lib/xmodule/xmodule/seq_module.py
+++ b/common/lib/xmodule/xmodule/seq_module.py
@@ -121,3 +121,17 @@ class SequenceDescriptor(MakoModuleDescriptor, XmlDescriptor):
xml_object.append(
etree.fromstring(child.export_to_xml(resource_fs)))
return xml_object
+
+ @classmethod
+ def split_to_file(cls, xml_object):
+ # Note: if we end up needing subclasses, can port this logic there.
+ yes = ('chapter',)
+ no = ('course',)
+
+ if xml_object.tag in yes:
+ return True
+ elif xml_object.tag in no:
+ return False
+
+ # otherwise maybe--delegate to superclass.
+ return XmlDescriptor.split_to_file(xml_object)
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 9cf744461d..ee0b541de5 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -213,6 +213,20 @@ class XmlDescriptor(XModuleDescriptor):
name=name,
ext=cls.filename_extension)
+ @classmethod
+ def split_to_file(cls, xml_object):
+ '''
+ Decide whether to write this object to a separate file or not.
+
+ xml_object: an xml definition of an instance of cls.
+
+ This default implementation will split if this has more than 7
+ descendant tags.
+
+ Can be overridden by subclasses.
+ '''
+ return len(list(xml_object.iter())) > 7
+
def export_to_xml(self, resource_fs):
"""
Returns an xml string representing this module, and all modules
@@ -233,14 +247,14 @@ class XmlDescriptor(XModuleDescriptor):
xml_object.tag = self.category
xml_object.set('slug', self.name)
- # Put content in a separate file if it's large (has more than 5 descendent tags)
- if len(list(xml_object.iter())) > 5:
+ if self.split_to_file(xml_object):
+ # Put this object in it's own file
filepath = self.__class__._format_filepath(self.category, self.name)
resource_fs.makedir(os.path.dirname(filepath), allow_recreate=True)
with resource_fs.open(filepath, 'w') as file:
file.write(etree.tostring(xml_object, pretty_print=True))
-
+ # ...and remove all of its children here
for child in xml_object:
xml_object.remove(child)
From 9461148b6e14224ac919e3dca91f88d22bb0f759 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:09:47 -0400
Subject: [PATCH 07/55] make customtag take impl as attribute rather than child
---
common/lib/xmodule/xmodule/backcompat_module.py | 3 +--
common/lib/xmodule/xmodule/template_module.py | 14 +++++++++-----
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/common/lib/xmodule/xmodule/backcompat_module.py b/common/lib/xmodule/xmodule/backcompat_module.py
index 456a2c2b07..2b6ca5c25a 100644
--- a/common/lib/xmodule/xmodule/backcompat_module.py
+++ b/common/lib/xmodule/xmodule/backcompat_module.py
@@ -82,7 +82,6 @@ class TranslateCustomTagDescriptor(XModuleDescriptor):
xml_object = etree.fromstring(xml_data)
tag = xml_object.tag
xml_object.tag = 'customtag'
- impl = etree.SubElement(xml_object, 'impl')
- impl.text = tag
+ xml_object.attrib['impl'] = tag
return system.process_xml(etree.tostring(xml_object))
diff --git a/common/lib/xmodule/xmodule/template_module.py b/common/lib/xmodule/xmodule/template_module.py
index 268ce24559..3f926555f4 100644
--- a/common/lib/xmodule/xmodule/template_module.py
+++ b/common/lib/xmodule/xmodule/template_module.py
@@ -21,19 +21,23 @@ class CustomTagModule(XModule):
course.xml::
...
- book
+
...
Renders to::
More information given in the text
"""
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition,
+ instance_state=None, shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition,
+ instance_state, shared_state, **kwargs)
+
xmltree = etree.fromstring(self.definition['data'])
- template_name = xmltree.find('impl').text
+ template_name = xmltree.attrib['impl']
params = dict(xmltree.items())
- with self.system.filestore.open('custom_tags/{name}'.format(name=template_name)) as template:
+ with self.system.filestore.open(
+ 'custom_tags/{name}'.format(name=template_name)) as template:
self.html = Template(template.read()).render(**params)
def get_html(self):
From 00da2b48e9eb6be23058adf3d6b14994dcdd339c Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:10:21 -0400
Subject: [PATCH 08/55] make sure course "org" and "course" are preserved on
export
---
common/lib/xmodule/xmodule/course_module.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index 05f440c0f8..0808d5fbb0 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -10,6 +10,7 @@ log = logging.getLogger(__name__)
class CourseDescriptor(SequenceDescriptor):
module_class = SequenceModule
+ metadata_attributes = SequenceDescriptor.metadata_attributes + ('org', 'course')
def __init__(self, system, definition=None, **kwargs):
super(CourseDescriptor, self).__init__(system, definition, **kwargs)
From a7159716f9ef0a7da9d40867a0ee7dc8dd7c00b9 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:11:00 -0400
Subject: [PATCH 09/55] fix out-of-date code
* no more __xmltree.
---
common/lib/xmodule/xmodule/x_module.py | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 3e564053bd..12881a0434 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -3,6 +3,7 @@ import pkg_resources
import logging
from xmodule.modulestore import Location
+
from functools import partial
log = logging.getLogger('mitx.' + __name__)
@@ -192,11 +193,7 @@ class XModule(HTMLSnippet):
self._loaded_children = None
def get_name(self):
- name = self.__xmltree.get('name')
- if name:
- return name
- else:
- raise "We should iterate through children and find a default name"
+ return self.name
def get_children(self):
'''
From beda4f95b26694cf17bcf8cf22a9e98db4392970 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:12:16 -0400
Subject: [PATCH 10/55] Initial version of import/check/export script.
* uses xml modulestore, and new error_handler hook
---
.../management/commands/clean_xml.py | 143 ++++++++++++++++++
1 file changed, 143 insertions(+)
create mode 100644 lms/djangoapps/courseware/management/commands/clean_xml.py
diff --git a/lms/djangoapps/courseware/management/commands/clean_xml.py b/lms/djangoapps/courseware/management/commands/clean_xml.py
new file mode 100644
index 0000000000..1803553ba3
--- /dev/null
+++ b/lms/djangoapps/courseware/management/commands/clean_xml.py
@@ -0,0 +1,143 @@
+import sys
+import traceback
+
+from fs.osfs import OSFS
+from path import path
+from lxml import etree
+
+from django.core.management.base import BaseCommand
+
+from xmodule.modulestore.xml import XMLModuleStore
+
+
+def export(course, export_dir):
+ """Export the specified course to course_dir. Creates dir if it doesn't exist.
+ Overwrites files, does not clean out dir beforehand.
+ """
+ fs = OSFS(export_dir, create=True)
+ if not fs.isdirempty('.'):
+ print ('WARNING: Directory {dir} not-empty.'
+ ' May clobber/confuse things'.format(dir=export_dir))
+
+ try:
+ xml = course.export_to_xml(fs)
+ with fs.open('course.xml', mode='w') as f:
+ f.write(xml)
+
+ return True
+ except:
+ print 'Export failed!'
+ traceback.print_exc()
+
+ return False
+
+
+def traverse_tree(course):
+ '''Load every descriptor in course. Return bool success value.'''
+ queue = [course]
+ while len(queue) > 0:
+ node = queue.pop()
+# print '{0}:'.format(node.location)
+# if 'data' in node.definition:
+# print '{0}'.format(node.definition['data'])
+ queue.extend(node.get_children())
+
+ return True
+
+def make_logging_error_handler():
+ '''Return a tuple (handler, error_list), where
+ the handler appends the message and any exc_info
+ to the error_list on every call.
+ '''
+ errors = []
+
+ def error_handler(msg, exc_info=None):
+ '''Log errors'''
+ if exc_info is None:
+ if sys.exc_info() != (None, None, None):
+ exc_info = sys.exc_info()
+
+ errors.append((msg, exc_info))
+
+ return (error_handler, errors)
+
+def clean_xml(course_dir, export_dir, verbose=True):
+ all_ok = True
+
+ print "Attempting to load '{0}'".format(course_dir)
+
+ course_dir = path(course_dir)
+ data_dir = course_dir.dirname()
+ course_dirs = [course_dir.basename()]
+
+ (error_handler, errors) = make_logging_error_handler()
+ # No default class--want to complain if it doesn't find plugins for any
+ # module.
+ modulestore = XMLModuleStore(data_dir,
+ default_class=None,
+ eager=True,
+ course_dirs=course_dirs,
+ error_handler=error_handler)
+
+ def str_of_err(tpl):
+ (msg, exc_info) = tpl
+ if exc_info is None:
+ return msg
+
+ exc_str = '\n'.join(traceback.format_exception(*exc_info))
+ return '{msg}\n{exc}'.format(msg=msg, exc=exc_str)
+
+ courses = modulestore.get_courses()
+ if len(errors) != 0:
+ all_ok = False
+ print '\n'
+ print "=" * 40
+ print 'ERRORs during import:'
+ print '\n'.join(map(str_of_err,errors))
+ print "=" * 40
+ print '\n'
+
+ n = len(courses)
+ if n != 1:
+ print 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(
+ n=n, lst=courses)
+ return
+
+ course = courses[0]
+
+ print course
+ validators = (
+ traverse_tree,
+ )
+
+ print "=" * 40
+ print "Running validators..."
+
+ for validate in validators:
+ print 'Running {0}'.format(validate.__name__)
+ all_ok = validate(course) and all_ok
+
+
+ if all_ok:
+ print 'Course passes all checks!'
+ export(course, export_dir)
+
+ else:
+ print "Course fails some checks. See above for errors."
+ print "Did NOT export"
+
+
+
+class Command(BaseCommand):
+ help = """Imports specified course.xml, validate it, then exports in
+ a canonical format.
+
+Usage: clean_xml PATH-TO-COURSE-DIR PATH-TO-OUTPUT-DIR
+"""
+
+ def handle(self, *args, **options):
+ if len(args) != 2:
+ print Command.help
+ return
+
+ clean_xml(args[0], args[1])
From a5bacb469622b1b7834b89be95a21c6bea09687c Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 14:16:52 -0400
Subject: [PATCH 11/55] add now-mandatory metadata to toy course.xml
---
common/test/data/toy/course.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/test/data/toy/course.xml b/common/test/data/toy/course.xml
index 645fbd7af8..ba4b295c2e 100644
--- a/common/test/data/toy/course.xml
+++ b/common/test/data/toy/course.xml
@@ -1,4 +1,4 @@
-
+
From e5117dba13347717835880722ca568976cabeeea Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 18:18:39 -0400
Subject: [PATCH 12/55] Mostly fix tests.
* change custom tags in test/data/full to new single-tag format
* fix broken file references
* fix argument to import_from_xml
* error_handler fix in mongo.py in next commit
---
cms/djangoapps/contentstore/tests/tests.py | 2 +-
cms/djangoapps/github_sync/tests/__init__.py | 2 +-
common/test/data/full/course/6.002_Spring_2012.xml | 2 +-
.../Administrivia_and_Circuit_Elements.xml | 8 ++------
.../data/full/sequential/System_Usage_Sequence.xml | 1 -
common/test/data/full/vertical/vertical_58.xml | 12 +++---------
common/test/data/full/vertical/vertical_89.xml | 12 +++---------
common/test/data/full/vertical/vertical_94.xml | 12 +++---------
common/test/data/full/vertical/vertical_98.xml | 12 +++---------
9 files changed, 17 insertions(+), 46 deletions(-)
diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py
index b7c55389b6..9dfe5d614a 100644
--- a/cms/djangoapps/contentstore/tests/tests.py
+++ b/cms/djangoapps/contentstore/tests/tests.py
@@ -196,7 +196,7 @@ class EditTestCase(ContentStoreTestCase):
xmodule.modulestore.django.modulestore().collection.drop()
def check_edit_item(self, test_course_name):
- import_from_xml('common/test/data/', test_course_name)
+ import_from_xml('common/test/data/', [test_course_name])
for descriptor in modulestore().get_items(Location(None, None, None, None, None)):
print "Checking ", descriptor.location.url()
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
index c95d538030..6b374cda2c 100644
--- a/cms/djangoapps/github_sync/tests/__init__.py
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -57,7 +57,7 @@ class GithubSyncTestCase(TestCase):
"""
self.assertEquals('Toy Course', self.import_course.metadata['display_name'])
self.assertIn(
- Location('i4x://edx/local_repo/chapter/Overview'),
+ Location('i4x://edX/toy/chapter/Overview'),
[child.location for child in self.import_course.get_children()])
self.assertEquals(1, len(self.import_course.get_children()))
diff --git a/common/test/data/full/course/6.002_Spring_2012.xml b/common/test/data/full/course/6.002_Spring_2012.xml
index d6398cdc46..0d22e96beb 100644
--- a/common/test/data/full/course/6.002_Spring_2012.xml
+++ b/common/test/data/full/course/6.002_Spring_2012.xml
@@ -6,7 +6,7 @@
-
+
diff --git a/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml b/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
index 28b56fb9b0..5c4c65f12d 100644
--- a/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
+++ b/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
@@ -2,17 +2,13 @@
-
- discuss
-
+
S1E4 has been removed.
Minor correction: Six elements (five resistors)
-
- discuss
-
+
diff --git a/common/test/data/full/sequential/System_Usage_Sequence.xml b/common/test/data/full/sequential/System_Usage_Sequence.xml
index baf73f1e9e..571229be7c 100644
--- a/common/test/data/full/sequential/System_Usage_Sequence.xml
+++ b/common/test/data/full/sequential/System_Usage_Sequence.xml
@@ -3,5 +3,4 @@
-
diff --git a/common/test/data/full/vertical/vertical_58.xml b/common/test/data/full/vertical/vertical_58.xml
index 7eba0f9dad..5707e6acf3 100644
--- a/common/test/data/full/vertical/vertical_58.xml
+++ b/common/test/data/full/vertical/vertical_58.xml
@@ -1,12 +1,6 @@
-
- discuss
-
-
- book
-
-
- slides
-
+
+
+
diff --git a/common/test/data/full/vertical/vertical_89.xml b/common/test/data/full/vertical/vertical_89.xml
index 06b13846d2..da15a6751a 100644
--- a/common/test/data/full/vertical/vertical_89.xml
+++ b/common/test/data/full/vertical/vertical_89.xml
@@ -3,13 +3,7 @@
-
- discuss
-
-
- book
-
-
- slides
-
+
+
+
diff --git a/common/test/data/full/vertical/vertical_94.xml b/common/test/data/full/vertical/vertical_94.xml
index 59fe9ddb07..c97960451d 100644
--- a/common/test/data/full/vertical/vertical_94.xml
+++ b/common/test/data/full/vertical/vertical_94.xml
@@ -1,12 +1,6 @@
-
- discuss
-
-
- book
-
-
- slides
-
+
+
+
diff --git a/common/test/data/full/vertical/vertical_98.xml b/common/test/data/full/vertical/vertical_98.xml
index b91f3caaaa..5afa197574 100644
--- a/common/test/data/full/vertical/vertical_98.xml
+++ b/common/test/data/full/vertical/vertical_98.xml
@@ -1,12 +1,6 @@
-
- discuss
-
-
- book
-
-
- slides
-
+
+
+
From dae9b16a42d258be1d68135a88acbb4a550dc0be Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 18:20:31 -0400
Subject: [PATCH 13/55] Clean up DescriptorSystem constructor hierarchy
In response to spending an hour with a strange argument passing bug that neither I nor Cale could figure out.
* pass all arguments explicitly
* pass arguments in a consistent order between classes
---
common/lib/xmodule/xmodule/mako_module.py | 7 +++--
.../lib/xmodule/xmodule/modulestore/mongo.py | 28 ++++++++++++++-----
common/lib/xmodule/xmodule/modulestore/xml.py | 25 ++++++++---------
common/lib/xmodule/xmodule/x_module.py | 12 +++-----
4 files changed, 42 insertions(+), 30 deletions(-)
diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py
index da620e4889..fcc47aaaaf 100644
--- a/common/lib/xmodule/xmodule/mako_module.py
+++ b/common/lib/xmodule/xmodule/mako_module.py
@@ -2,9 +2,12 @@ from x_module import XModuleDescriptor, DescriptorSystem
class MakoDescriptorSystem(DescriptorSystem):
- def __init__(self, render_template, *args, **kwargs):
+ def __init__(self, load_item, resources_fs, error_handler,
+ render_template):
+ super(MakoDescriptorSystem, self).__init__(
+ load_item, resources_fs, error_handler)
+
self.render_template = render_template
- super(MakoDescriptorSystem, self).__init__(*args, **kwargs)
class MakoModuleDescriptor(XModuleDescriptor):
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index 7cd005336c..95c882824b 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -6,6 +6,7 @@ from fs.osfs import OSFS
from itertools import repeat
from importlib import import_module
+from xmodule.errorhandlers import strict_error_handler
from xmodule.x_module import XModuleDescriptor
from xmodule.mako_module import MakoDescriptorSystem
from mitxmako.shortcuts import render_to_string
@@ -23,15 +24,26 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
A system that has a cache of module json that it will use to load modules
from, with a backup of calling to the underlying modulestore for more data
"""
- def __init__(self, modulestore, module_data, default_class, resources_fs, render_template):
+ def __init__(self, modulestore, module_data, default_class, resources_fs,
+ error_handler, render_template):
"""
modulestore: the module store that can be used to retrieve additional modules
- module_data: a dict mapping Location -> json that was cached from the underlying modulestore
- default_class: The default_class to use when loading an XModuleDescriptor from the module_data
+
+ module_data: a dict mapping Location -> json that was cached from the
+ underlying modulestore
+
+ default_class: The default_class to use when loading an
+ XModuleDescriptor from the module_data
+
resources_fs: a filesystem, as per MakoDescriptorSystem
- render_template: a function for rendering templates, as per MakoDescriptorSystem
+
+ error_handler:
+
+ render_template: a function for rendering templates, as per
+ MakoDescriptorSystem
"""
- super(CachingDescriptorSystem, self).__init__(render_template, self.load_item, resources_fs)
+ super(CachingDescriptorSystem, self).__init__(
+ self.load_item, resources_fs, error_handler, render_template)
self.modulestore = modulestore
self.module_data = module_data
self.default_class = default_class
@@ -127,13 +139,15 @@ class MongoModuleStore(ModuleStore):
"""
Load an XModuleDescriptor from item, using the children stored in data_cache
"""
- resource_fs = OSFS(self.fs_root / item.get('data_dir', item['location']['course']))
+ resource_fs = OSFS(self.fs_root / item.get('data_dir',
+ item['location']['course']))
system = CachingDescriptorSystem(
self,
data_cache,
self.default_class,
resource_fs,
- render_to_string
+ strict_error_handler,
+ render_to_string,
)
return system.load_item(item['location'])
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 8965f3d028..23b812baae 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -13,8 +13,9 @@ import re
from . import ModuleStore, Location
from .exceptions import ItemNotFoundError
-etree.set_default_parser(etree.XMLParser(dtd_validation=False, load_dtd=False,
- remove_comments=True, remove_blank_text=True))
+etree.set_default_parser(
+ etree.XMLParser(dtd_validation=False, load_dtd=False,
+ remove_comments=True, remove_blank_text=True))
log = logging.getLogger('mitx.' + __name__)
@@ -28,8 +29,7 @@ def clean_out_mako_templating(xml_string):
return xml_string
class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
- def __init__(self, xmlstore, org, course, course_dir,
- error_handler):
+ def __init__(self, xmlstore, org, course, course_dir, error_handler):
"""
A class that handles loading from xml. Does some munging to ensure that
all elements have unique slugs.
@@ -82,15 +82,14 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
module.get_children()
return module
- system_kwargs = dict(
- render_template=lambda: '',
- load_item=xmlstore.get_item,
- resources_fs=OSFS(xmlstore.data_dir / course_dir),
- process_xml=process_xml,
- error_handler=error_handler,
- )
- MakoDescriptorSystem.__init__(self, **system_kwargs)
- XMLParsingSystem.__init__(self, **system_kwargs)
+ render_template = lambda: ''
+ load_item = xmlstore.get_item
+ resources_fs = OSFS(xmlstore.data_dir / course_dir)
+
+ MakoDescriptorSystem.__init__(self, load_item, resources_fs,
+ error_handler, render_template)
+ XMLParsingSystem.__init__(self, load_item, resources_fs,
+ error_handler, process_xml)
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index 12881a0434..caeabb5ff5 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -521,9 +521,7 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
class DescriptorSystem(object):
- def __init__(self, load_item, resources_fs,
- error_handler,
- **kwargs):
+ def __init__(self, load_item, resources_fs, error_handler):
"""
load_item: Takes a Location and returns an XModuleDescriptor
@@ -563,16 +561,14 @@ class DescriptorSystem(object):
class XMLParsingSystem(DescriptorSystem):
- def __init__(self, load_item, resources_fs, process_xml, **kwargs):
+ def __init__(self, load_item, resources_fs, error_handler, process_xml):
"""
- load_item: Takes a Location and returns an XModuleDescriptor
+ load_item, resources_fs, error_handler: see DescriptorSystem
process_xml: Takes an xml string, and returns a XModuleDescriptor
created from that xml
-
-
"""
- DescriptorSystem.__init__(self, load_item, resources_fs, **kwargs)
+ DescriptorSystem.__init__(self, load_item, resources_fs, error_handler)
self.process_xml = process_xml
From 3cc601b3988f214db7e77a7fb131c5256e662009 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 19 Jul 2012 13:38:25 -0400
Subject: [PATCH 14/55] Clean up course_info views
* catch exceptions and return a 404 if course not found
* add Location.is_valid(), tests
* stub of jumpto/ view.
---
common/djangoapps/student/views.py | 1 +
common/lib/xmodule/xmodule/course_module.py | 3 +
.../xmodule/xmodule/modulestore/__init__.py | 11 +++
.../modulestore/tests/test_location.py | 62 ++++++++++++++---
lms/djangoapps/courseware/views.py | 67 +++++++------------
lms/urls.py | 3 +-
6 files changed, 95 insertions(+), 52 deletions(-)
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 6e2cf5b791..eeda9a6b65 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -30,6 +30,7 @@ from django_future.csrf import ensure_csrf_cookie
from student.models import Registration, UserProfile, PendingNameChange, PendingEmailChange, CourseEnrollment
from util.cache import cache_if_anonymous
from xmodule.course_module import CourseDescriptor
+from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index 0808d5fbb0..1eda54ea32 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -30,6 +30,9 @@ class CourseDescriptor(SequenceDescriptor):
@classmethod
def id_to_location(cls, course_id):
+ '''Convert the given course_id (org/course/name) to a location object.
+ Throws ValueError if course_id is of the wrong format.
+ '''
org, course, name = course_id.split('/')
return Location('i4x', org, course, 'course', name)
diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py
index ac03d92854..77dfacf372 100644
--- a/common/lib/xmodule/xmodule/modulestore/__init__.py
+++ b/common/lib/xmodule/xmodule/modulestore/__init__.py
@@ -45,6 +45,17 @@ class Location(_LocationBase):
"""
return re.sub('_+', '_', INVALID_CHARS.sub('_', value))
+ @classmethod
+ def is_valid(cls, value):
+ '''
+ Check if the value is a valid location, in any acceptable format.
+ '''
+ try:
+ Location(value)
+ except InvalidLocationError:
+ return False
+ return True
+
def __new__(_cls, loc_or_tag=None, org=None, course=None, category=None,
name=None, revision=None):
"""
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_location.py b/common/lib/xmodule/xmodule/modulestore/tests/test_location.py
index 19bdb105c1..70c6351685 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_location.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_location.py
@@ -13,14 +13,51 @@ def test_string_roundtrip():
check_string_roundtrip("tag://org/course/category/name/revision")
+input_dict = {
+ 'tag': 'tag',
+ 'course': 'course',
+ 'category': 'category',
+ 'name': 'name',
+ 'org': 'org'
+}
+
+input_list = ['tag', 'org', 'course', 'category', 'name']
+
+input_str = "tag://org/course/category/name"
+input_str_rev = "tag://org/course/category/name/revision"
+
+valid = (input_list, input_dict, input_str, input_str_rev)
+
+invalid_dict = {
+ 'tag': 'tag',
+ 'course': 'course',
+ 'category': 'category',
+ 'name': 'name/more_name',
+ 'org': 'org'
+}
+
+invalid_dict2 = {
+ 'tag': 'tag',
+ 'course': 'course',
+ 'category': 'category',
+ 'name': 'name ', # extra space
+ 'org': 'org'
+}
+
+invalid = ("foo", ["foo"], ["foo", "bar"],
+ ["foo", "bar", "baz", "blat", "foo/bar"],
+ "tag://org/course/category/name with spaces/revision",
+ invalid_dict,
+ invalid_dict2)
+
+def test_is_valid():
+ for v in valid:
+ assert_equals(Location.is_valid(v), True)
+
+ for v in invalid:
+ assert_equals(Location.is_valid(v), False)
+
def test_dict():
- input_dict = {
- 'tag': 'tag',
- 'course': 'course',
- 'category': 'category',
- 'name': 'name',
- 'org': 'org'
- }
assert_equals("tag://org/course/category/name", Location(input_dict).url())
assert_equals(dict(revision=None, **input_dict), Location(input_dict).dict())
@@ -30,7 +67,6 @@ def test_dict():
def test_list():
- input_list = ['tag', 'org', 'course', 'category', 'name']
assert_equals("tag://org/course/category/name", Location(input_list).url())
assert_equals(input_list + [None], Location(input_list).list())
@@ -65,3 +101,13 @@ def test_equality():
Location('tag', 'org', 'course', 'category', 'name1'),
Location('tag', 'org', 'course', 'category', 'name')
)
+
+def test_clean():
+ pairs = [ ('',''),
+ (' ', '_'),
+ ('abc,', 'abc_'),
+ ('ab fg!@//\\aj', 'ab_fg_aj'),
+ (u"ab\xA9", "ab_"), # no unicode allowed for now
+ ]
+ for input, output in pairs:
+ assert_equals(Location.clean(input), output)
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index f273778a3c..ca9aa417d1 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -20,12 +20,16 @@ from module_render import toc_for_course, get_module, get_section
from models import StudentModuleCache
from student.models import UserProfile
from multicourse import multicourse_settings
+from xmodule.modulestore import Location
+from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
+from xmodule.modulestore.django import modulestore
+from xmodule.course_module import CourseDescriptor
from util.cache import cache, cache_if_anonymous
from student.models import UserTestGroup, CourseEnrollment
from courseware import grades
from courseware.courses import check_course
-from xmodule.modulestore.django import modulestore
+
log = logging.getLogger("mitx.courseware")
@@ -205,53 +209,30 @@ def index(request, course_id, chapter=None, section=None,
return result
-def jump_to(request, probname=None):
+def jump_to(request, location):
'''
- Jump to viewing a specific problem. The problem is specified by a
- problem name - currently the filename (minus .xml) of the problem.
- Maybe this should change to a more generic tag, eg "name" given as
- an attribute in .
+ Show the page that contains a specific location.
- We do the jump by (1) reading course.xml to find the first
- instance of with the given filename, then (2) finding
- the parent element of the problem, then (3) rendering that parent
- element with a specific computed position value (if it is
- ).
+ If the location is invalid, return a 404.
+ If the location is valid, but not present in a course, ?
+
+ If the location is valid, but in a course the current user isn't registered for, ?
+ TODO -- let the index view deal with it?
'''
- # get coursename if stored
- coursename = multicourse_settings.get_coursename_from_request(request)
-
- # begin by getting course.xml tree
- xml = content_parser.course_file(request.user, coursename)
-
- # look for problem of given name
- pxml = xml.xpath('//problem[@filename="%s"]' % probname)
- if pxml:
- pxml = pxml[0]
-
- # get the parent element
- parent = pxml.getparent()
-
- # figure out chapter and section names
- chapter = None
- section = None
- branch = parent
- for k in range(4): # max depth of recursion
- if branch.tag == 'section':
- section = branch.get('name')
- if branch.tag == 'chapter':
- chapter = branch.get('name')
- branch = branch.getparent()
-
- position = None
- if parent.tag == 'sequential':
- position = parent.index(pxml) + 1 # position in sequence
-
- return index(request,
- course=coursename, chapter=chapter,
- section=section, position=position)
+ # Complain if the location isn't valid
+ try:
+ location = Location(location)
+ except InvalidLocationError:
+ raise Http404("Invalid location")
+ # Complain if there's not data for this location
+ try:
+ item = modulestore().get_item(location)
+ except ItemNotFoundError:
+ raise Http404("No data at this location: {0}".format(location))
+
+ return HttpResponse("O hai")
@ensure_csrf_cookie
def course_info(request, course_id):
diff --git a/lms/urls.py b/lms/urls.py
index 81e1343104..b583b252e2 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -97,7 +97,8 @@ if settings.PERFSTATS:
if settings.COURSEWARE_ENABLED:
urlpatterns += (
url(r'^masquerade/', include('masquerade.urls')),
- url(r'^jumpto/(?P[^/]+)/$', 'courseware.views.jump_to'),
+ url(r'^jumpto/(?P.*)$', 'courseware.views.jump_to'),
+
url(r'^modx/(?P.*?)/(?P[^/]*)$', 'courseware.module_render.modx_dispatch'), #reset_problem'),
url(r'^xqueue/(?P[^/]*)/(?P.*?)/(?P[^/]*)$', 'courseware.module_render.xqueue_callback'),
url(r'^change_setting$', 'student.views.change_setting'),
From 60cba3d95f555ec1bd7bc2208fd414e76a0fe48b Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 19 Jul 2012 18:19:00 -0400
Subject: [PATCH 15/55] Move import_from_xml to xmodule/modulestore
---
cms/djangoapps/contentstore/__init__.py | 34 -----------------
.../management/commands/import.py | 6 ++-
cms/djangoapps/contentstore/tests/tests.py | 4 +-
cms/djangoapps/github_sync/__init__.py | 6 ++-
.../xmodule/modulestore/tests/test_mongo.py | 28 ++++++++++++++
.../xmodule/modulestore/xml_importer.py | 38 +++++++++++++++++++
6 files changed, 76 insertions(+), 40 deletions(-)
create mode 100644 common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
create mode 100644 common/lib/xmodule/xmodule/modulestore/xml_importer.py
diff --git a/cms/djangoapps/contentstore/__init__.py b/cms/djangoapps/contentstore/__init__.py
index ef4e31614e..e69de29bb2 100644
--- a/cms/djangoapps/contentstore/__init__.py
+++ b/cms/djangoapps/contentstore/__init__.py
@@ -1,34 +0,0 @@
-from xmodule.modulestore.django import modulestore
-from xmodule.modulestore.xml import XMLModuleStore
-import logging
-
-log = logging.getLogger(__name__)
-
-
-def import_from_xml(data_dir, course_dirs=None):
- """
- Import the specified xml data_dir into the django defined modulestore,
- using org and course as the location org and course.
- """
- module_store = XMLModuleStore(
- data_dir,
- default_class='xmodule.raw_module.RawDescriptor',
- eager=True,
- course_dirs=course_dirs
- )
- for module in module_store.modules.itervalues():
-
- # TODO (cpennington): This forces import to overrite the same items.
- # This should in the future create new revisions of the items on import
- try:
- modulestore().create_item(module.location)
- except:
- log.exception('Item already exists at %s' % module.location.url())
- pass
- if 'data' in module.definition:
- modulestore().update_item(module.location, module.definition['data'])
- if 'children' in module.definition:
- modulestore().update_children(module.location, module.definition['children'])
- modulestore().update_metadata(module.location, dict(module.metadata))
-
- return module_store
diff --git a/cms/djangoapps/contentstore/management/commands/import.py b/cms/djangoapps/contentstore/management/commands/import.py
index 75d4e2618c..0e4dc5cc89 100644
--- a/cms/djangoapps/contentstore/management/commands/import.py
+++ b/cms/djangoapps/contentstore/management/commands/import.py
@@ -3,7 +3,9 @@
###
from django.core.management.base import BaseCommand, CommandError
-from contentstore import import_from_xml
+from xmodule.modulestore.xml_importer import import_from_xml
+from xmodule.modulestore.django import modulestore
+
unnamed_modules = 0
@@ -21,4 +23,4 @@ class Command(BaseCommand):
course_dirs = args[1:]
else:
course_dirs = None
- import_from_xml(data_dir, course_dirs)
+ import_from_xml(modulestore(), data_dir, course_dirs)
diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py
index 9dfe5d614a..50eba43795 100644
--- a/cms/djangoapps/contentstore/tests/tests.py
+++ b/cms/djangoapps/contentstore/tests/tests.py
@@ -12,7 +12,7 @@ from django.contrib.auth.models import User
from xmodule.modulestore.django import modulestore
import xmodule.modulestore.django
from xmodule.modulestore import Location
-from contentstore import import_from_xml
+from xmodule.modulestore.xml_importer import import_from_xml
import copy
@@ -196,7 +196,7 @@ class EditTestCase(ContentStoreTestCase):
xmodule.modulestore.django.modulestore().collection.drop()
def check_edit_item(self, test_course_name):
- import_from_xml('common/test/data/', [test_course_name])
+ import_from_xml(modulestore(), 'common/test/data/', [test_course_name])
for descriptor in modulestore().get_items(Location(None, None, None, None, None)):
print "Checking ", descriptor.location.url()
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index 149b92670a..1089db7efd 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -5,7 +5,8 @@ from django.conf import settings
from fs.osfs import OSFS
from git import Repo, PushInfo
-from contentstore import import_from_xml
+from xmodule.modulestore.xml_importer import import_from_xml
+from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location
from .exceptions import GithubSyncError
@@ -56,7 +57,8 @@ def import_from_github(repo_settings):
git_repo = setup_repo(repo_settings)
git_repo.head.reset('origin/%s' % repo_settings['branch'], index=True, working_tree=True)
- module_store = import_from_xml(settings.GITHUB_REPO_ROOT, course_dirs=[course_dir])
+ module_store = import_from_xml(modulestore(),
+ settings.GITHUB_REPO_ROOT, course_dirs=[course_dir])
return git_repo.head.commit.hexsha, module_store.courses[course_dir]
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
new file mode 100644
index 0000000000..ffcbe1717d
--- /dev/null
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
@@ -0,0 +1,28 @@
+from nose.tools import assert_equals, assert_raises, assert_not_equals, with_setup
+from xmodule.modulestore import Location
+from xmodule.modulestore.exceptions import InvalidLocationError
+from xmodule.modulestore.mongo import MongoModuleStore
+
+
+host = 'localhost'
+db = 'xmodule'
+collection = 'modulestore'
+fs_root = None # TODO (vshnayder): will need a real fs_root for testing load_item
+default_class = 'xmodule.raw_module.RawDescriptor'
+
+
+
+def setup_func():
+ # connect to the db
+ global store
+ store = MongoModuleStore(host, db, collection, fs_root, default_class=default_class)
+
+def teardown_func():
+ global store
+ store = None
+
+@with_setup(setup_func, teardown_func)
+def test_init():
+ '''Just make sure the db loads'''
+ pass
+
diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
new file mode 100644
index 0000000000..a21777b65f
--- /dev/null
+++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
@@ -0,0 +1,38 @@
+import logging
+
+from .xml import XMLModuleStore
+
+log = logging.getLogger(__name__)
+
+
+def import_from_xml(store, data_dir, course_dirs=None):
+ """
+ Import the specified xml data_dir into the "store" modulestore,
+ using org and course as the location org and course.
+
+ course_dirs: If specified, the list of course_dirs to load. Otherwise, load
+ all course dirs
+
+ """
+ module_store = XMLModuleStore(
+ data_dir,
+ default_class='xmodule.raw_module.RawDescriptor',
+ eager=True,
+ course_dirs=course_dirs
+ )
+ for module in module_store.modules.itervalues():
+
+ # TODO (cpennington): This forces import to overrite the same items.
+ # This should in the future create new revisions of the items on import
+ try:
+ store.create_item(module.location)
+ except:
+ log.exception('Item already exists at %s' % module.location.url())
+ pass
+ if 'data' in module.definition:
+ store.update_item(module.location, module.definition['data'])
+ if 'children' in module.definition:
+ store.update_children(module.location, module.definition['children'])
+ store.update_metadata(module.location, dict(module.metadata))
+
+ return module_store
From f10c4c06b61e3691658c08e274d78a7257acadf6 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 19 Jul 2012 18:21:45 -0400
Subject: [PATCH 16/55] Start adding tests for mongo modulestore
* fix up toy course to match current format
* fix github sync test that referred to toy course
---
.../xmodule/modulestore/tests/test_mongo.py | 45 +++++++-
common/test/data/toy/course.xml | 2 +-
common/test/data/toy/html/Lab2A.html | 105 ------------------
common/test/data/toy/html/toylab.html | 3 +
4 files changed, 43 insertions(+), 112 deletions(-)
delete mode 100644 common/test/data/toy/html/Lab2A.html
create mode 100644 common/test/data/toy/html/toylab.html
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
index ffcbe1717d..55e573677f 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
@@ -1,28 +1,61 @@
+import pymongo
+
from nose.tools import assert_equals, assert_raises, assert_not_equals, with_setup
+from path import path
+
from xmodule.modulestore import Location
from xmodule.modulestore.exceptions import InvalidLocationError
from xmodule.modulestore.mongo import MongoModuleStore
+from xmodule.modulestore.xml_importer import import_from_xml
+
+# from ~/mitx_all/mitx/common/lib/xmodule/xmodule/modulestore/tests/
+# to ~/mitx_all/mitx/common/test
+TEST_DIR = path(__file__).abspath().dirname()
+for i in range(5):
+ TEST_DIR = TEST_DIR.dirname()
+TEST_DIR = TEST_DIR / 'test'
+
+DATA_DIR = TEST_DIR / 'data'
-host = 'localhost'
-db = 'xmodule'
-collection = 'modulestore'
-fs_root = None # TODO (vshnayder): will need a real fs_root for testing load_item
-default_class = 'xmodule.raw_module.RawDescriptor'
+HOST = 'localhost'
+PORT = 27017
+DB = 'test'
+COLLECTION = 'modulestore'
+FS_ROOT = DATA_DIR # TODO (vshnayder): will need a real fs_root for testing load_item
+DEFAULT_CLASS = 'xmodule.raw_module.RawDescriptor'
+connection = None
+
+def setup():
+ global connection
+ connection = pymongo.connection.Connection(HOST, PORT)
+
+
def setup_func():
# connect to the db
global store
- store = MongoModuleStore(host, db, collection, fs_root, default_class=default_class)
+ store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, default_class=DEFAULT_CLASS)
+ print 'data_dir: {0}'.format(DATA_DIR)
+ import_from_xml(store, DATA_DIR)
def teardown_func():
global store
store = None
+ # Destroy the test db.
+ connection.drop_database(DB)
+
@with_setup(setup_func, teardown_func)
def test_init():
'''Just make sure the db loads'''
pass
+@with_setup(setup_func, teardown_func)
+def test_get_courses():
+ '''Make sure the course objects loaded properly'''
+ courses = store.get_courses()
+ print courses
+
diff --git a/common/test/data/toy/course.xml b/common/test/data/toy/course.xml
index ba4b295c2e..391eb68e2b 100644
--- a/common/test/data/toy/course.xml
+++ b/common/test/data/toy/course.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/common/test/data/toy/html/Lab2A.html b/common/test/data/toy/html/Lab2A.html
deleted file mode 100644
index 7fe52cc1be..0000000000
--- a/common/test/data/toy/html/Lab2A.html
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-Lab 2A: Superposition Experiment
-
-Note: This part of the lab is just to develop your intuition about
-superposition. There are no responses that need to be checked.
-
- Circuits with multiple sources can be hard to analyze as-is. For example, what is the voltage
-between the two terminals on the right of Figure 1?
-
-
-
-Figure 1. Example multi-source circuit
-
-
- We can use superposition to make the analysis much easier.
-The circuit in Figure 1 can be decomposed into two separate
-subcircuits: one involving only the voltage source and one involving only the
-current source. We'll analyze each circuit separately and combine the
-results using superposition. Recall that to decompose a circuit for
-analysis, we'll pick each source in turn and set all the other sources
-to zero (i.e., voltage sources become short circuits and current
-sources become open circuits). The circuit above has two sources, so
-the decomposition produces two subcircuits, as shown in Figure 2.
-
-
-
-
-(a) Subcircuit for analyzing contribution of voltage source
-
-
-(b) Subcircuit for analyzing contribution of current source
-
- Figure 2. Decomposition of Figure 1 into subcircuits
-
-
- Let's use the DC analysis capability of the schematic tool to see superposition
-in action. The sliders below control the resistances of R1, R2, R3 and R4 in all
-the diagrams. As you move the sliders, the schematic tool will adjust the appropriate
-resistance, perform a DC analysis and display the node voltages on the diagrams. Here's
-what you want to observe as you play with the sliders:
-
-
-The voltage for a node in Figure 1 is the sum of the voltages for
-that node in Figures 2(a) and 2(b), just as predicted by
-superposition. (Note that due to round-off in the display of the
-voltages, the sum of the displayed voltages in Figure 2 may only be within
-.01 of the voltages displayed in Figure 1.)
-
-
-
-
-
-
-
-
- R1
-
-
-
-
-
- R2
-
-
-
-
-
- R3
-
-
-
-
-
- R4
-
-
-
-
-
-
-
diff --git a/common/test/data/toy/html/toylab.html b/common/test/data/toy/html/toylab.html
new file mode 100644
index 0000000000..81df84bd63
--- /dev/null
+++ b/common/test/data/toy/html/toylab.html
@@ -0,0 +1,3 @@
+Lab 2A: Superposition Experiment
+
+Isn't the toy course great?
From eb5989aa992b646e5335f43d0cd4aa0001218255 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 19 Jul 2012 19:22:03 -0400
Subject: [PATCH 17/55] Ready to implement path_to_location
* Clean up test data for simple, toy courses
* clean up test_mongo.py
* write initial test for path_to_location
* hook up view to use path_to_location
Next: actually implement it :)
---
.../xmodule/xmodule/modulestore/__init__.py | 23 +++++
.../xmodule/xmodule/modulestore/exceptions.py | 3 +
.../lib/xmodule/xmodule/modulestore/mongo.py | 24 +++++-
.../xmodule/modulestore/tests/test_mongo.py | 84 ++++++++++++-------
common/test/data/simple/course.xml | 24 ++++++
common/test/data/simple/html/toylab.html | 3 +
.../data/simple/problems/L1_Problem_1.xml | 43 ++++++++++
.../test/data/simple/problems/ps01-simple.xml | 62 ++++++++++++++
common/test/data/toy/course.xml | 4 +-
lms/djangoapps/courseware/views.py | 11 ++-
10 files changed, 244 insertions(+), 37 deletions(-)
create mode 100644 common/test/data/simple/course.xml
create mode 100644 common/test/data/simple/html/toylab.html
create mode 100644 common/test/data/simple/problems/L1_Problem_1.xml
create mode 100644 common/test/data/simple/problems/ps01-simple.xml
diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py
index 77dfacf372..279782b61a 100644
--- a/common/lib/xmodule/xmodule/modulestore/__init__.py
+++ b/common/lib/xmodule/xmodule/modulestore/__init__.py
@@ -253,3 +253,26 @@ class ModuleStore(object):
in this modulestore.
'''
raise NotImplementedError
+
+ def path_to_location(self, location, course=None, chapter=None, section=None):
+ '''
+ Try to find a course/chapter/section[/position] path to this location.
+
+ raise ItemNotFoundError if the location doesn't exist.
+
+ If course, chapter, section are not None, restrict search to paths with those
+ components as specified.
+
+ raise NoPathToItem if the location exists, but isn't accessible via
+ a path that matches the course/chapter/section restrictions.
+
+ In general, a location may be accessible via many paths. This method may
+ return any valid path.
+
+ Return a tuple (course, chapter, section, position).
+
+ If the section a sequence, position should be the position of this location
+ in that sequence. Otherwise, position should be None.
+ '''
+ raise NotImplementedError
+
diff --git a/common/lib/xmodule/xmodule/modulestore/exceptions.py b/common/lib/xmodule/xmodule/modulestore/exceptions.py
index a6dc99883f..d860a1d263 100644
--- a/common/lib/xmodule/xmodule/modulestore/exceptions.py
+++ b/common/lib/xmodule/xmodule/modulestore/exceptions.py
@@ -13,3 +13,6 @@ class InsufficientSpecificationError(Exception):
class InvalidLocationError(Exception):
pass
+
+class NoPathToItem(Exception):
+ pass
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index 95c882824b..d2b68d03ef 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -251,7 +251,7 @@ class MongoModuleStore(ModuleStore):
def update_metadata(self, location, metadata):
"""
- Set the children for the item specified by the location to
+ Set the metadata for the item specified by the location to
metadata
location: Something that can be passed to Location
@@ -264,3 +264,25 @@ class MongoModuleStore(ModuleStore):
{'_id': Location(location).dict()},
{'$set': {'metadata': metadata}}
)
+
+ def path_to_location(self, location, course=None):
+ '''
+ Try to find a course/chapter/section[/position] path to this location.
+
+ raise ItemNotFoundError if the location doesn't exist.
+
+ If course is not None, restrict search to paths in that course.
+
+ raise NoPathToItem if the location exists, but isn't accessible via
+ a chapter/section path in the course(s) being searched.
+
+ In general, a location may be accessible via many paths. This method may
+ return any valid path.
+
+ Return a tuple (course, chapter, section, position).
+
+ If the section a sequence, position should be the position of this location
+ in that sequence. Otherwise, position should be None.
+ '''
+ raise NotImplementedError
+
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
index 55e573677f..493b8a385d 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
@@ -4,7 +4,7 @@ from nose.tools import assert_equals, assert_raises, assert_not_equals, with_set
from path import path
from xmodule.modulestore import Location
-from xmodule.modulestore.exceptions import InvalidLocationError
+from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
from xmodule.modulestore.mongo import MongoModuleStore
from xmodule.modulestore.xml_importer import import_from_xml
@@ -26,36 +26,60 @@ FS_ROOT = DATA_DIR # TODO (vshnayder): will need a real fs_root for testing loa
DEFAULT_CLASS = 'xmodule.raw_module.RawDescriptor'
-connection = None
+class TestMongoModuleStore(object):
-def setup():
- global connection
- connection = pymongo.connection.Connection(HOST, PORT)
+ @classmethod
+ def setupClass(cls):
+ cls.connection = pymongo.connection.Connection(HOST, PORT)
+ cls.connection.drop_database(DB)
+
+ @classmethod
+ def teardownClass(cls):
+ pass
+
+ def setUp(self):
+ # connect to the db
+ self.store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, default_class=DEFAULT_CLASS)
+ # Explicitly list the courses to load (don't want the big one)
+ courses = ['toy', 'simple']
+ import_from_xml(self.store, DATA_DIR, courses)
+ self.connection = TestMongoModuleStore.connection
+ def tearDown(self):
+ # Destroy the test db.
+ self.connection.drop_database(DB)
+ self.store = None
-
-def setup_func():
- # connect to the db
- global store
- store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, default_class=DEFAULT_CLASS)
- print 'data_dir: {0}'.format(DATA_DIR)
- import_from_xml(store, DATA_DIR)
-
-def teardown_func():
- global store
- store = None
- # Destroy the test db.
- connection.drop_database(DB)
-
-
-@with_setup(setup_func, teardown_func)
-def test_init():
- '''Just make sure the db loads'''
- pass
-
-@with_setup(setup_func, teardown_func)
-def test_get_courses():
- '''Make sure the course objects loaded properly'''
- courses = store.get_courses()
- print courses
+ def test_init(self):
+ '''Just make sure the db loads'''
+ ids = list(self.connection[DB][COLLECTION].find({}, {'_id': True}))
+ print len(ids)
+ def test_get_courses(self):
+ '''Make sure the course objects loaded properly'''
+ courses = self.store.get_courses()
+ assert_equals(len(courses), 2)
+ courses.sort(key=lambda c: c.id)
+ assert_equals(courses[0].id, 'edX/simple/2012_Fall')
+ assert_equals(courses[1].id, 'edX/toy/2012_Fall')
+
+ def Xtest_path_to_location(self):
+ '''Make sure that path_to_location works'''
+ should_work = (
+ ("i4x://edX/toy/video/Welcome", ("toy", "Overview", None, None)),
+ )
+ for location, expected in should_work:
+ assert_equals(self.store.path_to_location(location), expected)
+
+ not_found = (
+ "i4x://edX/toy/video/WelcomeX",
+ )
+ for location in not_found:
+ assert_raises(ItemNotFoundError, self.store.path_to_location, location)
+
+ no_path = (
+ "i4x://edX/toy/video/Lost_Video",
+ )
+ for location in not_found:
+ assert_raises(ItemNotFoundError, self.store.path_to_location, location)
+
diff --git a/common/test/data/simple/course.xml b/common/test/data/simple/course.xml
new file mode 100644
index 0000000000..59a0a0c5bc
--- /dev/null
+++ b/common/test/data/simple/course.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/test/data/simple/html/toylab.html b/common/test/data/simple/html/toylab.html
new file mode 100644
index 0000000000..81df84bd63
--- /dev/null
+++ b/common/test/data/simple/html/toylab.html
@@ -0,0 +1,3 @@
+Lab 2A: Superposition Experiment
+
+Isn't the toy course great?
diff --git a/common/test/data/simple/problems/L1_Problem_1.xml b/common/test/data/simple/problems/L1_Problem_1.xml
new file mode 100644
index 0000000000..2ba0617904
--- /dev/null
+++ b/common/test/data/simple/problems/L1_Problem_1.xml
@@ -0,0 +1,43 @@
+
+
+
+
Finger Exercise 1
+
+
+Here are two definitions:
+
+
+
+Declarative knowledge refers to statements of fact.
+
+
+
+Imperative knowledge refers to 'how to' methods.
+
+
+
+Which of the following choices is correct?
+
+
+
+Statement 1 is true, Statement 2 is false
+
+
+
+Statement 1 is false, Statement 2 is true
+
+
+
+Statement 1 and Statement 2 are both false
+
+
+
+Statement 1 and Statement 2 are both true
+
+
+
+
+
+
+
+
diff --git a/common/test/data/simple/problems/ps01-simple.xml b/common/test/data/simple/problems/ps01-simple.xml
new file mode 100644
index 0000000000..e70d8f2c8d
--- /dev/null
+++ b/common/test/data/simple/problems/ps01-simple.xml
@@ -0,0 +1,62 @@
+
+Paying Off Credit Card Debt
+ Each month, a credit
+ card statement will come with the option for you to pay a
+ minimum amount of your charge, usually 2% of the balance due.
+ However, the credit card company earns money by charging
+ interest on the balance that you don't pay. So even if you
+ pay credit card payments on time, interest is still accruing
+ on the outstanding balance.
+Say you've made a
+ $5,000 purchase on a credit card with 18% annual interest
+ rate and 2% minimum monthly payment rate. After a year, how
+ much is the remaining balance? Use the following
+ equations.
+
+Minimum monthly payment
+= (Minimum monthly payment rate) x (Balance)
+ (Minimum monthly payment gets split into interest paid and
+ principal paid)
+Interest Paid = (Annual interest rate) / (12
+ months) x (Balance)
+Principal paid = (Minimum monthly payment) -
+ (Interest paid)
+Remaining balance = Balance - (Principal
+ paid)
+
+For month 1, compute the minimum monthly payment by taking 2% of the balance.
+
+Minimum monthly payment
+= .02 x $5000 = $100
+We can't simply deduct this from the balance because
+ there is compounding interest. Of this $100 monthly
+ payment, compute how much will go to paying off interest
+ and how much will go to paying off the principal. Remember
+ that it's the annual interest rate that is given, so we
+ need to divide it by 12 to get the monthly interest
+ rate.
+Interest paid = .18/12 x $5000 =
+ $75
+Principal paid = $100 - $75 = $25
+The remaining balance at the end of the first month will
+ be the principal paid this month subtracted from the
+ balance at the start of the month.
+Remaining balance = $5000 - $25 =
+ $4975
+
+For month 2, we
+ repeat the same steps.
+
+Minimum monthly payment
+= .02 x $4975 = $99.50
+Interest Paid = .18/12 x $4975 =
+ $74.63
+Principal Paid = $99.50 - $74.63 =
+ $24.87
+Remaining Balance = $4975 - $24.87 =
+ $4950.13
+
+After 12 months, the
+ total amount paid is $1167.55, leaving an outstanding balance
+ of $4708.10. Pretty depressing!
+
diff --git a/common/test/data/toy/course.xml b/common/test/data/toy/course.xml
index 391eb68e2b..1c080bfe18 100644
--- a/common/test/data/toy/course.xml
+++ b/common/test/data/toy/course.xml
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index ca9aa417d1..7cfe2f5365 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -21,7 +21,7 @@ from models import StudentModuleCache
from student.models import UserProfile
from multicourse import multicourse_settings
from xmodule.modulestore import Location
-from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
+from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
from xmodule.modulestore.django import modulestore
from xmodule.course_module import CourseDescriptor
@@ -228,11 +228,14 @@ def jump_to(request, location):
# Complain if there's not data for this location
try:
- item = modulestore().get_item(location)
+ (course, chapter, section, position) = modulestore().path_to_location(location)
except ItemNotFoundError:
raise Http404("No data at this location: {0}".format(location))
-
- return HttpResponse("O hai")
+ except NoPathToItem:
+ raise Http404("This location is not in any class: {0}".format(location))
+
+
+ return index(course, chapter, section, position)
@ensure_csrf_cookie
def course_info(request, course_id):
From 168f76ce5a5437da966de031c64703883f377935 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Fri, 20 Jul 2012 14:36:22 -0400
Subject: [PATCH 18/55] Add jump_to functionality to lms on mongo
* More tests for mongo modulestore, including tweaks to test files
* add location_to_id method to CourseDescriptors
* Implement path_to_location method in mongo.py
- TODO: does not handle position in sequences yet.
* fix bug in jump_to view.
---
common/lib/xmodule/xmodule/course_module.py | 19 ++-
.../lib/xmodule/xmodule/modulestore/mongo.py | 114 +++++++++++++++---
.../xmodule/modulestore/tests/test_mongo.py | 89 +++++++++++---
common/test/data/simple/course.xml | 2 +-
common/test/data/toy/course.xml | 8 +-
lms/djangoapps/courseware/views.py | 13 +-
6 files changed, 199 insertions(+), 46 deletions(-)
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index 1eda54ea32..dfac1ac9c6 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -28,17 +28,30 @@ class CourseDescriptor(SequenceDescriptor):
def has_started(self):
return time.gmtime() > self.start
- @classmethod
- def id_to_location(cls, course_id):
+ @staticmethod
+ def id_to_location(course_id):
'''Convert the given course_id (org/course/name) to a location object.
Throws ValueError if course_id is of the wrong format.
'''
org, course, name = course_id.split('/')
return Location('i4x', org, course, 'course', name)
+ @staticmethod
+ def location_to_id(location):
+ '''Convert a location of a course to a course_id. If location category
+ is not "course", raise a ValueError.
+
+ location: something that can be passed to Location
+ '''
+ loc = Location(location)
+ if loc.category != "course":
+ raise ValueError("{0} is not a course location".format(loc))
+ return "/".join([loc.org, loc.course, loc.name])
+
+
@property
def id(self):
- return "/".join([self.location.org, self.location.course, self.location.name])
+ return self.location_to_id(self.location)
@property
def start_date_text(self):
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index d2b68d03ef..e706f312f8 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -9,16 +9,18 @@ from importlib import import_module
from xmodule.errorhandlers import strict_error_handler
from xmodule.x_module import XModuleDescriptor
from xmodule.mako_module import MakoDescriptorSystem
+from xmodule.course_module import CourseDescriptor
from mitxmako.shortcuts import render_to_string
from . import ModuleStore, Location
-from .exceptions import ItemNotFoundError, InsufficientSpecificationError
+from .exceptions import ItemNotFoundError, InsufficientSpecificationError, NoPathToItem
# TODO (cpennington): This code currently operates under the assumption that
# there is only one revision for each item. Once we start versioning inside the CMS,
# that assumption will have to change
+
class CachingDescriptorSystem(MakoDescriptorSystem):
"""
A system that has a cache of module json that it will use to load modules
@@ -167,6 +169,14 @@ class MongoModuleStore(ModuleStore):
course_filter = Location("i4x", category="course")
return self.get_items(course_filter)
+ def _find_one(self, location):
+ '''Look for a given location in the collection.
+ If revision isn't specified, returns the latest.'''
+ return self.collection.find_one(
+ location_to_query(location),
+ sort=[('revision', pymongo.ASCENDING)],
+ )
+
def get_item(self, location, depth=0):
"""
Returns an XModuleDescriptor instance for the item at location.
@@ -190,10 +200,7 @@ class MongoModuleStore(ModuleStore):
if key != 'revision' and val is None:
raise InsufficientSpecificationError(location)
- item = self.collection.find_one(
- location_to_query(location),
- sort=[('revision', pymongo.ASCENDING)],
- )
+ item = self._find_one(location)
if item is None:
raise ItemNotFoundError(location)
return self._load_items([item], depth)[0]
@@ -265,24 +272,101 @@ class MongoModuleStore(ModuleStore):
{'$set': {'metadata': metadata}}
)
- def path_to_location(self, location, course=None):
+ def get_parent_locations(self, location):
+ '''Find all locations that are the parents of this location.
+ Mostly intended for use in path_to_location, but exposed for testing
+ and possible other usefulness.
+
+ returns an iterable of things that can be passed to Location.
'''
- Try to find a course/chapter/section[/position] path to this location.
+ location = Location(location)
+ items = self.collection.find({'definition.children': str(location)},
+ {'_id': True})
+ return [i['_id'] for i in items]
+
+
+
+ def path_to_location(self, location, course_name=None):
+ '''
+ Try to find a course_id/chapter/section[/position] path to this location.
+ The courseware insists that the first level in the course is chapter,
+ but any kind of module can be a "section".
+
+ location: something that can be passed to Location
+ course_name: [optional]. If not None, restrict search to paths
+ in that course.
raise ItemNotFoundError if the location doesn't exist.
- If course is not None, restrict search to paths in that course.
-
raise NoPathToItem if the location exists, but isn't accessible via
a chapter/section path in the course(s) being searched.
- In general, a location may be accessible via many paths. This method may
+ Return a tuple (course_id, chapter, section, position) suitable for the
+ courseware index view.
+
+ A location may be accessible via many paths. This method may
return any valid path.
- Return a tuple (course, chapter, section, position).
-
- If the section a sequence, position should be the position of this location
- in that sequence. Otherwise, position should be None.
+ If the section is a sequence, position will be the position
+ of this location in that sequence. Otherwise, position will
+ be None. TODO (vshnayder): Not true yet.
'''
- raise NotImplementedError
+ # Check that location is present at all
+ if self._find_one(location) is None:
+ raise ItemNotFoundError(location)
+
+ def flatten(xs):
+ '''Convert lisp-style (a, (b, (c, ()))) lists into a python list.
+ Not a general flatten function. '''
+ p = []
+ while xs != ():
+ p.append(xs[0])
+ xs = xs[1]
+ return p
+
+ def find_path_to_course(location, course_name=None):
+ '''Find a path up the location graph to a node with the
+ specified category. If no path exists, return None. If a
+ path exists, return it as a list with target location
+ first, and the starting location last.
+ '''
+ # Standard DFS
+
+ # To keep track of where we came from, the work queue has
+ # tuples (location, path-so-far). To avoid lots of
+ # copying, the path-so-far is stored as a lisp-style
+ # list--nested hd::tl tuples, and flattened at the end.
+ queue = [(location, ())]
+ while len(queue) > 0:
+ (loc, path) = queue.pop() # Takes from the end
+ loc = Location(loc)
+ print 'Processing loc={0}, path={1}'.format(loc, path)
+ if loc.category == "course":
+ if course_name is None or course_name == loc.name:
+ # Found it!
+ path = (loc, path)
+ return flatten(path)
+
+ # otherwise, add parent locations at the end
+ newpath = (loc, path)
+ parents = self.get_parent_locations(loc)
+ queue.extend(zip(parents, repeat(newpath)))
+
+ # If we're here, there is no path
+ return None
+
+ path = find_path_to_course(location, course_name)
+ if path is None:
+ raise(NoPathToItem(location))
+
+
+ n = len(path)
+ course_id = CourseDescriptor.location_to_id(path[0])
+ chapter = path[1].name if n > 1 else None
+ section = path[2].name if n > 2 else None
+
+ # TODO (vshnayder): not handling position at all yet...
+ position = None
+
+ return (course_id, chapter, section, position)
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
index 493b8a385d..cb2bc6e20c 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
@@ -2,9 +2,10 @@ import pymongo
from nose.tools import assert_equals, assert_raises, assert_not_equals, with_setup
from path import path
+from pprint import pprint
from xmodule.modulestore import Location
-from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
+from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
from xmodule.modulestore.mongo import MongoModuleStore
from xmodule.modulestore.xml_importer import import_from_xml
@@ -33,28 +34,44 @@ class TestMongoModuleStore(object):
cls.connection = pymongo.connection.Connection(HOST, PORT)
cls.connection.drop_database(DB)
+ # NOTE: Creating a single db for all the tests to save time. This
+ # is ok only as long as none of the tests modify the db.
+ # If (when!) that changes, need to either reload the db, or load
+ # once and copy over to a tmp db for each test.
+ cls.store = cls.initdb()
+
@classmethod
def teardownClass(cls):
pass
- def setUp(self):
+ @staticmethod
+ def initdb():
# connect to the db
- self.store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, default_class=DEFAULT_CLASS)
+ store = MongoModuleStore(HOST, DB, COLLECTION, FS_ROOT, default_class=DEFAULT_CLASS)
# Explicitly list the courses to load (don't want the big one)
courses = ['toy', 'simple']
- import_from_xml(self.store, DATA_DIR, courses)
- self.connection = TestMongoModuleStore.connection
-
- def tearDown(self):
+ import_from_xml(store, DATA_DIR, courses)
+ return store
+
+ @staticmethod
+ def destroy_db(connection):
# Destroy the test db.
- self.connection.drop_database(DB)
- self.store = None
+ connection.drop_database(DB)
+
+ def setUp(self):
+ # make a copy for convenience
+ self.connection = TestMongoModuleStore.connection
+
+ def tearDown(self):
+ pass
def test_init(self):
- '''Just make sure the db loads'''
+ '''Make sure the db loads, and print all the locations in the db.
+ Call this directly from failing tests to see what's loaded'''
ids = list(self.connection[DB][COLLECTION].find({}, {'_id': True}))
- print len(ids)
-
+
+ pprint([Location(i['_id']).url() for i in ids])
+
def test_get_courses(self):
'''Make sure the course objects loaded properly'''
courses = self.store.get_courses()
@@ -63,10 +80,41 @@ class TestMongoModuleStore(object):
assert_equals(courses[0].id, 'edX/simple/2012_Fall')
assert_equals(courses[1].id, 'edX/toy/2012_Fall')
- def Xtest_path_to_location(self):
+ def test_loads(self):
+ assert_not_equals(
+ self.store.get_item("i4x://edX/toy/course/2012_Fall"),
+ None)
+
+ assert_not_equals(
+ self.store.get_item("i4x://edX/simple/course/2012_Fall"),
+ None)
+
+ assert_not_equals(
+ self.store.get_item("i4x://edX/toy/video/Welcome"),
+ None)
+
+
+
+ def test_find_one(self):
+ assert_not_equals(
+ self.store._find_one(Location("i4x://edX/toy/course/2012_Fall")),
+ None)
+
+ assert_not_equals(
+ self.store._find_one(Location("i4x://edX/simple/course/2012_Fall")),
+ None)
+
+ assert_not_equals(
+ self.store._find_one(Location("i4x://edX/toy/video/Welcome")),
+ None)
+
+ def test_path_to_location(self):
'''Make sure that path_to_location works'''
should_work = (
- ("i4x://edX/toy/video/Welcome", ("toy", "Overview", None, None)),
+ ("i4x://edX/toy/video/Welcome",
+ ("edX/toy/2012_Fall", "Overview", "Welcome", None)),
+ ("i4x://edX/toy/html/toylab",
+ ("edX/toy/2012_Fall", "Overview", "Toy_Videos", None)),
)
for location, expected in should_work:
assert_equals(self.store.path_to_location(location), expected)
@@ -76,10 +124,13 @@ class TestMongoModuleStore(object):
)
for location in not_found:
assert_raises(ItemNotFoundError, self.store.path_to_location, location)
-
+
+ # Since our test files are valid, there shouldn't be any
+ # elements with no path to them. But we can look for them in
+ # another course.
no_path = (
- "i4x://edX/toy/video/Lost_Video",
+ "i4x://edX/simple/video/Lost_Video",
)
- for location in not_found:
- assert_raises(ItemNotFoundError, self.store.path_to_location, location)
-
+ for location in no_path:
+ assert_raises(NoPathToItem, self.store.path_to_location, location, "toy")
+
diff --git a/common/test/data/simple/course.xml b/common/test/data/simple/course.xml
index 59a0a0c5bc..b92158cdb7 100644
--- a/common/test/data/simple/course.xml
+++ b/common/test/data/simple/course.xml
@@ -18,7 +18,7 @@
+
-
diff --git a/common/test/data/toy/course.xml b/common/test/data/toy/course.xml
index 1c080bfe18..270a1eb27f 100644
--- a/common/test/data/toy/course.xml
+++ b/common/test/data/toy/course.xml
@@ -1,9 +1,9 @@
-
-
-
-
+
+
+
+
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index 7cfe2f5365..51a82a4079 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -208,7 +208,7 @@ def index(request, course_id, chapter=None, section=None,
result = render_to_response('courseware.html', context)
return result
-
+@ensure_csrf_cookie
def jump_to(request, location):
'''
Show the page that contains a specific location.
@@ -228,17 +228,22 @@ def jump_to(request, location):
# Complain if there's not data for this location
try:
- (course, chapter, section, position) = modulestore().path_to_location(location)
+ (course_id, chapter, section, position) = modulestore().path_to_location(location)
except ItemNotFoundError:
raise Http404("No data at this location: {0}".format(location))
except NoPathToItem:
raise Http404("This location is not in any class: {0}".format(location))
-
- return index(course, chapter, section, position)
+
+ return index(request, course_id, chapter, section, position)
@ensure_csrf_cookie
def course_info(request, course_id):
+ '''
+ Display the course's info.html, or 404 if there is no such course.
+
+ Assumes the course_id is in a valid format.
+ '''
course = check_course(course_id)
return render_to_response('info.html', {'course': course})
From 128d11e20e9dba69fa0e3658456b8a7bbbee5320 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Wed, 25 Jul 2012 19:59:48 -0400
Subject: [PATCH 19/55] line length fixes
---
common/lib/xmodule/xmodule/modulestore/mongo.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index e706f312f8..b4b8710e71 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -13,7 +13,8 @@ from xmodule.course_module import CourseDescriptor
from mitxmako.shortcuts import render_to_string
from . import ModuleStore, Location
-from .exceptions import ItemNotFoundError, InsufficientSpecificationError, NoPathToItem
+from .exceptions import (ItemNotFoundError, InsufficientSpecificationError,
+ NoPathToItem)
# TODO (cpennington): This code currently operates under the assumption that
# there is only one revision for each item. Once we start versioning inside the CMS,
@@ -155,7 +156,8 @@ class MongoModuleStore(ModuleStore):
def _load_items(self, items, depth=0):
"""
- Load a list of xmodules from the data in items, with children cached up to specified depth
+ Load a list of xmodules from the data in items, with children cached up
+ to specified depth
"""
data_cache = self._cache_children(items, depth)
@@ -369,4 +371,3 @@ class MongoModuleStore(ModuleStore):
position = None
return (course_id, chapter, section, position)
-
From da29d88d04782ec3966607a3bcf6c328d12ea7db Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 26 Jul 2012 16:17:17 -0400
Subject: [PATCH 20/55] Add import-export round-trip check.
* add fix for the file export code--remove tag tail and text,
not just the children.
---
common/lib/xmodule/xmodule/xml_module.py | 5 ++
.../management/commands/clean_xml.py | 82 +++++++++++++------
2 files changed, 60 insertions(+), 27 deletions(-)
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index ee0b541de5..2c3fa62f6e 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -257,6 +257,11 @@ class XmlDescriptor(XModuleDescriptor):
# ...and remove all of its children here
for child in xml_object:
xml_object.remove(child)
+ # also need to remove the text of this object.
+ xml_object.text = ''
+ # and the tail for good measure...
+ xml_object.tail = ''
+
xml_object.set('filename', self.name)
diff --git a/lms/djangoapps/courseware/management/commands/clean_xml.py b/lms/djangoapps/courseware/management/commands/clean_xml.py
index 1803553ba3..bd0c2b21bb 100644
--- a/lms/djangoapps/courseware/management/commands/clean_xml.py
+++ b/lms/djangoapps/courseware/management/commands/clean_xml.py
@@ -1,6 +1,8 @@
+import os
import sys
import traceback
+from filecmp import dircmp
from fs.osfs import OSFS
from path import path
from lxml import etree
@@ -10,28 +12,6 @@ from django.core.management.base import BaseCommand
from xmodule.modulestore.xml import XMLModuleStore
-def export(course, export_dir):
- """Export the specified course to course_dir. Creates dir if it doesn't exist.
- Overwrites files, does not clean out dir beforehand.
- """
- fs = OSFS(export_dir, create=True)
- if not fs.isdirempty('.'):
- print ('WARNING: Directory {dir} not-empty.'
- ' May clobber/confuse things'.format(dir=export_dir))
-
- try:
- xml = course.export_to_xml(fs)
- with fs.open('course.xml', mode='w') as f:
- f.write(xml)
-
- return True
- except:
- print 'Export failed!'
- traceback.print_exc()
-
- return False
-
-
def traverse_tree(course):
'''Load every descriptor in course. Return bool success value.'''
queue = [course]
@@ -61,7 +41,30 @@ def make_logging_error_handler():
return (error_handler, errors)
-def clean_xml(course_dir, export_dir, verbose=True):
+
+def export(course, export_dir):
+ """Export the specified course to course_dir. Creates dir if it doesn't exist.
+ Overwrites files, does not clean out dir beforehand.
+ """
+ fs = OSFS(export_dir, create=True)
+ if not fs.isdirempty('.'):
+ print ('WARNING: Directory {dir} not-empty.'
+ ' May clobber/confuse things'.format(dir=export_dir))
+
+ try:
+ xml = course.export_to_xml(fs)
+ with fs.open('course.xml', mode='w') as f:
+ f.write(xml)
+
+ return True
+ except:
+ print 'Export failed!'
+ traceback.print_exc()
+
+ return False
+
+
+def import_with_checks(course_dir, verbose=True):
all_ok = True
print "Attempting to load '{0}'".format(course_dir)
@@ -105,7 +108,7 @@ def clean_xml(course_dir, export_dir, verbose=True):
course = courses[0]
- print course
+ #print course
validators = (
traverse_tree,
)
@@ -120,10 +123,36 @@ def clean_xml(course_dir, export_dir, verbose=True):
if all_ok:
print 'Course passes all checks!'
- export(course, export_dir)
-
else:
print "Course fails some checks. See above for errors."
+ return all_ok, course
+
+
+def check_roundtrip(course_dir):
+ '''Check that import->export leaves the course the same'''
+
+ print "====== Roundtrip import ======="
+ (ok, course) = import_with_checks(course_dir)
+ if not ok:
+ raise Exception("Roundtrip import failed!")
+
+ print "====== Roundtrip export ======="
+ export_dir = course_dir + ".rt"
+ export(course, export_dir)
+
+ # dircmp doesn't do recursive diffs.
+ # diff = dircmp(course_dir, export_dir, ignore=[], hide=[])
+ print "======== Roundtrip diff: ========="
+ os.system("diff -r {0} {1}".format(course_dir, export_dir))
+ print "======== ideally there is no diff above this ======="
+
+
+def clean_xml(course_dir, export_dir):
+ (ok, course) = import_with_checks(course_dir)
+ if ok:
+ export(course, export_dir)
+ check_roundtrip(export_dir)
+ else:
print "Did NOT export"
@@ -134,7 +163,6 @@ class Command(BaseCommand):
Usage: clean_xml PATH-TO-COURSE-DIR PATH-TO-OUTPUT-DIR
"""
-
def handle(self, *args, **options):
if len(args) != 2:
print Command.help
From 3c3bbd114e605a437ef2aa6689363c4742d0489d Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 26 Jul 2012 21:00:29 -0400
Subject: [PATCH 21/55] minor formatting tweaks
---
cms/djangoapps/contentstore/tests/tests.py | 4 ++--
common/lib/xmodule/xmodule/html_module.py | 6 ++++--
common/lib/xmodule/xmodule/x_module.py | 4 ++--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py
index 50eba43795..429774c91e 100644
--- a/cms/djangoapps/contentstore/tests/tests.py
+++ b/cms/djangoapps/contentstore/tests/tests.py
@@ -74,7 +74,7 @@ class ContentStoreTestCase(TestCase):
return resp
def _activate_user(self, email):
- '''look up the user's activation key in the db, then hit the activate view.
+ '''Look up the activation key for the user, then hit the activate view.
No error checking'''
activation_key = registration(email).activation_key
@@ -102,7 +102,7 @@ class AuthTestCase(ContentStoreTestCase):
resp = self.client.get(url)
self.assertEqual(resp.status_code, expected)
return resp
-
+
def test_public_pages_load(self):
"""Make sure pages that don't require login load without error."""
pages = (
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index ce18a05a8a..b9bc34aed6 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -12,8 +12,10 @@ class HtmlModule(XModule):
def get_html(self):
return self.html
- def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
- XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
+ def __init__(self, system, location, definition,
+ instance_state=None, shared_state=None, **kwargs):
+ XModule.__init__(self, system, location, definition,
+ instance_state, shared_state, **kwargs)
self.html = self.definition['data']
diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py
index caeabb5ff5..3406bcb99c 100644
--- a/common/lib/xmodule/xmodule/x_module.py
+++ b/common/lib/xmodule/xmodule/x_module.py
@@ -450,8 +450,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
default_class
)
# leave next line, commented out - useful for low-level debugging
- log.debug('[XModuleDescriptor.load_from_xml] tag=%s, class_=%s' % (
- etree.fromstring(xml_data).tag,class_))
+ # log.debug('[XModuleDescriptor.load_from_xml] tag=%s, class_=%s' % (
+ # etree.fromstring(xml_data).tag,class_))
return class_.from_xml(xml_data, system, org, course)
@classmethod
From 1251686359174f5d262ea1e6d5b62d6911fcc335 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 26 Jul 2012 21:03:26 -0400
Subject: [PATCH 22/55] xml format cleanups
* rename slug->url_name
* rename name->display_name
* docstring cleanups
* comments :)
---
common/lib/xmodule/xmodule/modulestore/xml.py | 11 ++--
common/lib/xmodule/xmodule/xml_module.py | 55 +++++++++++++++----
2 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 23b812baae..047e91e084 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -50,24 +50,25 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
log.exception("Unable to parse xml: {xml}".format(xml=xml))
raise
- # TODO (vshnayder): is the slug munging permanent, or also intended
- # to be taken out?
- if xml_data.get('slug') is None:
+ # VS[compat]. Take this out once course conversion is done
+ if xml_data.get('slug') is None and xml_data.get('url_name') is None:
if xml_data.get('name'):
slug = Location.clean(xml_data.get('name'))
+ elif xml_data.get('display_name'):
+ slug = Location.clean(xml_data.get('display_name'))
else:
self.unnamed_modules += 1
slug = '{tag}_{count}'.format(tag=xml_data.tag,
count=self.unnamed_modules)
- if slug in self.used_slugs:
+ while slug in self.used_slugs:
self.unnamed_modules += 1
slug = '{slug}_{count}'.format(slug=slug,
count=self.unnamed_modules)
self.used_slugs.add(slug)
# log.debug('-> slug=%s' % slug)
- xml_data.set('slug', slug)
+ xml_data.set('url_name', slug)
module = XModuleDescriptor.load_from_xml(
etree.tostring(xml_data), self, org,
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 2c3fa62f6e..8327a3ddec 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -9,7 +9,6 @@ import os
log = logging.getLogger(__name__)
-
# TODO (cpennington): This was implemented in an attempt to improve performance,
# but the actual improvement wasn't measured (and it was implemented late at night).
# We should check if it hurts, and whether there's a better way of doing lazy loading
@@ -76,8 +75,13 @@ _AttrMapBase = namedtuple('_AttrMap', 'metadata_key to_metadata from_metadata')
class AttrMap(_AttrMapBase):
"""
- A class that specifies a metadata_key, a function to transform an xml
- attribute to be placed in that key, and to transform that key value
+ A class that specifies a metadata_key, and two functions:
+
+ to_metadata: convert value from the xml representation into
+ an internal python representation
+
+ from_metadata: convert the internal python representation into
+ the value to store in the xml.
"""
def __new__(_cls, metadata_key,
to_metadata=lambda x: x,
@@ -96,17 +100,35 @@ class XmlDescriptor(XModuleDescriptor):
# The attributes will be removed from the definition xml passed
# to definition_from_xml, and from the xml returned by definition_to_xml
metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize',
- 'start', 'due', 'graded', 'name', 'slug', 'hide_from_toc')
+ 'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc',
+ # VS[compat] Remove once unused.
+ 'name', 'slug')
- # A dictionary mapping xml attribute names to functions of the value
- # that return the metadata key and value
+
+ # A dictionary mapping xml attribute names AttrMaps that describe how
+ # to import and export them
xml_attribute_map = {
+ # type conversion: want True/False in python, "true"/"false" in xml
'graded': AttrMap('graded',
lambda val: val == 'true',
lambda val: str(val).lower()),
- 'name': AttrMap('display_name'),
}
+
+ # VS[compat]. Backwards compatibility code that can go away after
+ # importing 2012 courses.
+ # A set of metadata key conversions that we want to make
+ metadata_translations = {
+ 'slug' : 'url_name',
+ 'name' : 'display_name',
+ }
+
+ @classmethod
+ def _translate(cls, key):
+ 'VS[compat]'
+ return cls.metadata_translations.get(key, key)
+
+
@classmethod
def definition_from_xml(cls, xml_object, system):
"""
@@ -157,9 +179,11 @@ class XmlDescriptor(XModuleDescriptor):
for attr in cls.metadata_attributes:
val = xml_object.get(attr)
if val is not None:
+ # VS[compat]. Remove after all key translations done
+ attr = cls._translate(attr)
+
attr_map = cls.xml_attribute_map.get(attr, AttrMap(attr))
metadata[attr_map.metadata_key] = attr_map.to_metadata(val)
-
return metadata
def definition_loader():
@@ -182,7 +206,6 @@ class XmlDescriptor(XModuleDescriptor):
filepath = candidate
break
- log.debug('filepath=%s, resources_fs=%s' % (filepath, system.resources_fs))
try:
with system.resources_fs.open(filepath) as file:
definition_xml = cls.file_to_xml(file)
@@ -190,12 +213,14 @@ class XmlDescriptor(XModuleDescriptor):
msg = 'Unable to load file contents at path %s' % filepath
log.exception(msg)
system.error_handler(msg)
- # if error_handler didn't reraise, work around it.
+ # if error_handler didn't reraise, work around problem.
return {'data': 'Error loading file contents at path %s' % filepath}
cls.clean_metadata_from_xml(definition_xml)
return cls.definition_from_xml(definition_xml, system)
+ # VS[compat] -- just have the url_name lookup once translation is done
+ slug = xml_object.get('url_name', xml_object.get('slug'))
return cls(
system,
LazyLoadingDict(definition_loader),
@@ -203,7 +228,7 @@ class XmlDescriptor(XModuleDescriptor):
org,
course,
xml_object.tag,
- xml_object.get('slug')],
+ slug],
metadata=LazyLoadingDict(metadata_loader),
)
@@ -242,12 +267,15 @@ class XmlDescriptor(XModuleDescriptor):
resource_fs is a pyfilesystem object (from the fs package)
"""
+
+ # Get the definition
xml_object = self.definition_to_xml(resource_fs)
self.__class__.clean_metadata_from_xml(xml_object)
+ # Set the tag first, so it's right if writing to a file
xml_object.tag = self.category
- xml_object.set('slug', self.name)
+ # Write it to a file if necessary
if self.split_to_file(xml_object):
# Put this object in it's own file
filepath = self.__class__._format_filepath(self.category, self.name)
@@ -265,6 +293,8 @@ class XmlDescriptor(XModuleDescriptor):
xml_object.set('filename', self.name)
+ # Add the metadata
+ xml_object.set('url_name', self.name)
for attr in self.metadata_attributes:
attr_map = self.xml_attribute_map.get(attr, AttrMap(attr))
metadata_key = attr_map.metadata_key
@@ -276,6 +306,7 @@ class XmlDescriptor(XModuleDescriptor):
val = attr_map.from_metadata(self.metadata[metadata_key])
xml_object.set(attr, val)
+ # Now we just have to make it beautiful
return etree.tostring(xml_object, pretty_print=True)
def definition_to_xml(self, resource_fs):
From 73b38268200235bb328e10e3a760d10003c066dd Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 26 Jul 2012 21:10:31 -0400
Subject: [PATCH 23/55] Initial integration tests!
* new env file to run integration tests with mongo backend
- needs askbot to get db in the right state
- needs wiki to load pages successfully
- not using migrations to make it run faster
* import test courses, check that each page loads without erroring.
* fix NonePointerException in index view to make tests pass
* misc formatting cleanups
---
.../lib/xmodule/xmodule/modulestore/mongo.py | 2 +-
.../xmodule/modulestore/xml_importer.py | 9 +-
lms/djangoapps/courseware/tests/__init__.py | 1 +
lms/djangoapps/courseware/tests/tests.py | 144 ++++++++++++++++++
lms/djangoapps/courseware/views.py | 17 ++-
lms/envs/test.py | 14 +-
lms/envs/test_mongo.py | 113 ++++++++++++++
lms/urls.py | 98 ++++++------
8 files changed, 334 insertions(+), 64 deletions(-)
create mode 100644 lms/djangoapps/courseware/tests/__init__.py
create mode 100644 lms/djangoapps/courseware/tests/tests.py
create mode 100644 lms/envs/test_mongo.py
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index b4b8710e71..b6b71f61fb 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -342,7 +342,7 @@ class MongoModuleStore(ModuleStore):
while len(queue) > 0:
(loc, path) = queue.pop() # Takes from the end
loc = Location(loc)
- print 'Processing loc={0}, path={1}'.format(loc, path)
+ # print 'Processing loc={0}, path={1}'.format(loc, path)
if loc.category == "course":
if course_name is None or course_name == loc.name:
# Found it!
diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
index a21777b65f..b315e0625a 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
@@ -5,19 +5,20 @@ from .xml import XMLModuleStore
log = logging.getLogger(__name__)
-def import_from_xml(store, data_dir, course_dirs=None):
+def import_from_xml(store, data_dir, course_dirs=None, eager=True,
+ default_class='xmodule.raw_module.RawDescriptor'):
"""
Import the specified xml data_dir into the "store" modulestore,
using org and course as the location org and course.
course_dirs: If specified, the list of course_dirs to load. Otherwise, load
all course dirs
-
+
"""
module_store = XMLModuleStore(
data_dir,
- default_class='xmodule.raw_module.RawDescriptor',
- eager=True,
+ default_class=default_class,
+ eager=eager,
course_dirs=course_dirs
)
for module in module_store.modules.itervalues():
diff --git a/lms/djangoapps/courseware/tests/__init__.py b/lms/djangoapps/courseware/tests/__init__.py
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/lms/djangoapps/courseware/tests/__init__.py
@@ -0,0 +1 @@
+
diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py
new file mode 100644
index 0000000000..24cc9eac00
--- /dev/null
+++ b/lms/djangoapps/courseware/tests/tests.py
@@ -0,0 +1,144 @@
+import json
+from django.test import TestCase
+from django.test.client import Client
+from mock import patch, Mock
+from override_settings import override_settings
+from django.conf import settings
+from django.core.urlresolvers import reverse
+from path import path
+
+from student.models import Registration
+from django.contrib.auth.models import User
+
+from xmodule.modulestore.django import modulestore
+import xmodule.modulestore.django
+from xmodule.modulestore import Location
+from xmodule.modulestore.xml_importer import import_from_xml
+import copy
+
+
+def parse_json(response):
+ """Parse response, which is assumed to be json"""
+ return json.loads(response.content)
+
+
+def user(email):
+ '''look up a user by email'''
+ return User.objects.get(email=email)
+
+
+def registration(email):
+ '''look up registration object by email'''
+ return Registration.objects.get(user__email=email)
+
+
+TEST_DATA_MODULESTORE = copy.deepcopy(settings.MODULESTORE)
+# TODO (vshnayder): test the real courses
+TEST_DATA_DIR = 'common/test/data'
+TEST_DATA_MODULESTORE['default']['OPTIONS']['fs_root'] = path(TEST_DATA_DIR)
+
+@override_settings(MODULESTORE=TEST_DATA_MODULESTORE)
+class IntegrationTestCase(TestCase):
+ '''Check that all objects in all accessible courses will load properly'''
+
+ def setUp(self):
+ email = 'view@test.com'
+ password = 'foo'
+ self.create_account('viewtest', email, password)
+ self.activate_user(email)
+ self.login(email, password)
+ xmodule.modulestore.django._MODULESTORES = {}
+ xmodule.modulestore.django.modulestore().collection.drop()
+
+
+ # ============ User creation and login ==============
+
+ def _login(self, email, pw):
+ '''Login. View should always return 200. The success/fail is in the
+ returned json'''
+ resp = self.client.post(reverse('login'),
+ {'email': email, 'password': pw})
+ self.assertEqual(resp.status_code, 200)
+ return resp
+
+ def login(self, email, pw):
+ '''Login, check that it worked.'''
+ resp = self._login(email, pw)
+ data = parse_json(resp)
+ self.assertTrue(data['success'])
+ return resp
+
+ def _create_account(self, username, email, pw):
+ '''Try to create an account. No error checking'''
+ resp = self.client.post('/create_account', {
+ 'username': username,
+ 'email': email,
+ 'password': pw,
+ 'name': 'Fred Weasley',
+ 'terms_of_service': 'true',
+ 'honor_code': 'true',
+ })
+ return resp
+
+ def create_account(self, username, email, pw):
+ '''Create the account and check that it worked'''
+ resp = self._create_account(username, email, pw)
+ self.assertEqual(resp.status_code, 200)
+ data = parse_json(resp)
+ self.assertEqual(data['success'], True)
+
+ # Check both that the user is created, and inactive
+ self.assertFalse(user(email).is_active)
+
+ return resp
+
+ def _activate_user(self, email):
+ '''Look up the activation key for the user, then hit the activate view.
+ No error checking'''
+ activation_key = registration(email).activation_key
+
+ # and now we try to activate
+ resp = self.client.get(reverse('activate', kwargs={'key': activation_key}))
+ return resp
+
+ def activate_user(self, email):
+ resp = self._activate_user(email)
+ self.assertEqual(resp.status_code, 200)
+ # Now make sure that the user is now actually activated
+ self.assertTrue(user(email).is_active)
+
+ # ============ Page loading ==============
+
+ def check_pages_load(self, test_course_name):
+ import_from_xml(modulestore(), TEST_DATA_DIR, [test_course_name])
+
+ n = 0
+ num_bad = 0
+ all_ok = True
+ for descriptor in modulestore().get_items(
+ Location(None, None, None, None, None)):
+ n += 1
+ print "Checking ", descriptor.location.url()
+ #print descriptor.__class__, descriptor.location
+ resp = self.client.get(reverse('jump_to',
+ kwargs={'location': descriptor.location.url()}))
+ msg = str(resp.status_code)
+
+ if resp.status_code != 200:
+ msg = "ERROR " + msg
+ all_ok = False
+ num_bad += 1
+ print msg
+ self.assertTrue(all_ok)
+
+ print "{0}/{1} good".format(n - num_bad, n)
+
+
+ def test_toy_course_loads(self):
+ self.check_pages_load('toy')
+
+ def test_full_course_loads(self):
+ self.check_pages_load('full')
+
+
+ # ========= TODO: check ajax interaction here too?
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index 51a82a4079..00fde8a84c 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -200,10 +200,19 @@ def index(request, course_id, chapter=None, section=None,
if look_for_module:
# TODO (cpennington): Pass the right course in here
- section = get_section(course, chapter, section)
- student_module_cache = StudentModuleCache(request.user, section)
- module, _, _, _ = get_module(request.user, request, section.location, student_module_cache)
- context['content'] = module.get_html()
+ section_descriptor = get_section(course, chapter, section)
+ if section_descriptor is not None:
+ student_module_cache = StudentModuleCache(request.user,
+ section_descriptor)
+ module, _, _, _ = get_module(request.user, request,
+ section_descriptor.location,
+ student_module_cache)
+ context['content'] = module.get_html()
+ else:
+ log.warning("Couldn't find a section descriptor for course_id '{0}',"
+ "chapter '{1}', section '{2}'".format(
+ course_id, chapter, section))
+
result = render_to_response('courseware.html', context)
return result
diff --git a/lms/envs/test.py b/lms/envs/test.py
index fdfbfb20c4..ef63063b51 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -22,7 +22,8 @@ INSTALLED_APPS = [
# Nose Test Runner
INSTALLED_APPS += ['django_nose']
NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
- '--cover-inclusive', '--cover-html-dir', os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
+ '--cover-inclusive', '--cover-html-dir',
+ os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
NOSE_ARGS += ['--cover-package', app]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
@@ -30,25 +31,26 @@ TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
# Local Directories
TEST_ROOT = path("test_root")
# Want static files in the same dir for running on jenkins.
-STATIC_ROOT = TEST_ROOT / "staticfiles"
+STATIC_ROOT = TEST_ROOT / "staticfiles"
COURSES_ROOT = TEST_ROOT / "data"
DATA_DIR = COURSES_ROOT
MAKO_TEMPLATES['course'] = [DATA_DIR]
MAKO_TEMPLATES['sections'] = [DATA_DIR / 'sections']
MAKO_TEMPLATES['custom_tags'] = [DATA_DIR / 'custom_tags']
-MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
+MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
DATA_DIR / 'info',
DATA_DIR / 'problems']
-LOGGING = get_logger_config(TEST_ROOT / "log",
+LOGGING = get_logger_config(TEST_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
debug=True)
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
-# TODO (cpennington): We need to figure out how envs/test.py can inject things into common.py so that we don't have to repeat this sort of thing
+# TODO (cpennington): We need to figure out how envs/test.py can inject things
+# into common.py so that we don't have to repeat this sort of thing
STATICFILES_DIRS = [
COMMON_ROOT / "static",
PROJECT_ROOT / "static",
@@ -67,7 +69,7 @@ DATABASES = {
}
CACHES = {
- # This is the cache used for most things. Askbot will not work without a
+ # 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': {
diff --git a/lms/envs/test_mongo.py b/lms/envs/test_mongo.py
new file mode 100644
index 0000000000..cbf9209c96
--- /dev/null
+++ b/lms/envs/test_mongo.py
@@ -0,0 +1,113 @@
+"""
+This config file runs the test environment, but with mongo as the datastore
+"""
+from .common import *
+
+from .logsettings import get_logger_config
+import os
+from path import path
+
+# can't testing start dates with this True, but on the other hand,
+# can test everything else :)
+MITX_FEATURES['DISABLE_START_DATES'] = True
+
+WIKI_ENABLED = True
+
+GITHUB_REPO_ROOT = ENV_ROOT / "data"
+
+MODULESTORE = {
+ 'default': {
+ 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
+ 'OPTIONS': {
+ 'default_class': 'xmodule.raw_module.RawDescriptor',
+ 'host': 'localhost',
+ 'db': 'xmodule',
+ 'collection': 'modulestore',
+ 'fs_root': GITHUB_REPO_ROOT,
+ }
+ }
+}
+
+
+# Nose Test Runner
+INSTALLED_APPS += ('django_nose',)
+NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
+ '--cover-inclusive', '--cover-html-dir',
+ os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
+for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
+ NOSE_ARGS += ['--cover-package', app]
+TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
+
+
+TEST_ROOT = path("test_root")
+# Want static files in the same dir for running on jenkins.
+STATIC_ROOT = TEST_ROOT / "staticfiles"
+
+
+
+LOGGING = get_logger_config(TEST_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',
+ 'KEY_FUNCTION': 'util.memcache.safe_key',
+ },
+
+ # 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,
+ 'KEY_FUNCTION': 'util.memcache.safe_key',
+ }
+}
+
+# Dummy secret key for dev
+SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
+
+# Makes the tests run much faster...
+SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead
+
+############################ FILE UPLOADS (ASKBOT) #############################
+DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
+MEDIA_ROOT = TEST_ROOT / "uploads"
+MEDIA_URL = "/static/uploads/"
+STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
+
+new_staticfiles_dirs = []
+# Strip out any static files that aren't in the repository root
+# so that the tests can run with only the mitx directory checked out
+for static_dir in STATICFILES_DIRS:
+ # Handle both tuples and non-tuple directory definitions
+ try:
+ _, data_dir = static_dir
+ except ValueError:
+ data_dir = static_dir
+
+ if data_dir.startswith(REPO_ROOT):
+ new_staticfiles_dirs.append(static_dir)
+STATICFILES_DIRS = new_staticfiles_dirs
+
+FILE_UPLOAD_TEMP_DIR = PROJECT_ROOT / "uploads"
+FILE_UPLOAD_HANDLERS = (
+ 'django.core.files.uploadhandler.MemoryFileUploadHandler',
+ 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
+)
diff --git a/lms/urls.py b/lms/urls.py
index b583b252e2..1c4a065e2b 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -13,23 +13,23 @@ if settings.DEBUG:
urlpatterns = ('',
url(r'^$', 'student.views.index', name="root"), # Main marketing page, or redirect to courseware
url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
-
+
url(r'^change_email$', 'student.views.change_email_request'),
url(r'^email_confirm/(?P[^/]*)$', 'student.views.confirm_email_change'),
url(r'^change_name$', 'student.views.change_name_request'),
url(r'^accept_name_change$', 'student.views.accept_name_change'),
url(r'^reject_name_change$', 'student.views.reject_name_change'),
url(r'^pending_name_changes$', 'student.views.pending_name_changes'),
-
+
url(r'^event$', 'track.views.user_track'),
url(r'^t/(?P[^/]*)$', 'static_template_view.views.index'), # TODO: Is this used anymore? What is STATIC_GRAB?
-
- url(r'^login$', 'student.views.login_user'),
+
+ url(r'^login$', 'student.views.login_user', name="login"),
url(r'^login/(?P[^/]*)$', 'student.views.login_user'),
url(r'^logout$', 'student.views.logout_user', name='logout'),
url(r'^create_account$', 'student.views.create_account'),
- url(r'^activate/(?P[^/]*)$', 'student.views.activate_account'),
-
+ url(r'^activate/(?P[^/]*)$', 'student.views.activate_account', name="activate"),
+
url(r'^password_reset/$', 'student.views.password_reset', name='password_reset'),
## Obsolete Django views for password resets
## TODO: Replace with Mako-ized views
@@ -44,48 +44,48 @@ urlpatterns = ('',
name='auth_password_reset_complete'),
url(r'^password_reset_done/$', django.contrib.auth.views.password_reset_done,
name='auth_password_reset_done'),
-
+
url(r'^heartbeat$', include('heartbeat.urls')),
-
+
url(r'^university_profile/(?P[^/]+)$', 'courseware.views.university_profile', name="university_profile"),
-
+
#Semi-static views (these need to be rendered and have the login bar, but don't change)
- url(r'^404$', 'static_template_view.views.render',
+ url(r'^404$', 'static_template_view.views.render',
{'template': '404.html'}, name="404"),
- url(r'^about$', 'static_template_view.views.render',
+ url(r'^about$', 'static_template_view.views.render',
{'template': 'about.html'}, name="about_edx"),
- url(r'^jobs$', 'static_template_view.views.render',
+ url(r'^jobs$', 'static_template_view.views.render',
{'template': 'jobs.html'}, name="jobs"),
- url(r'^contact$', 'static_template_view.views.render',
+ url(r'^contact$', 'static_template_view.views.render',
{'template': 'contact.html'}, name="contact"),
url(r'^press$', 'student.views.press', name="press"),
- url(r'^faq$', 'static_template_view.views.render',
+ url(r'^faq$', 'static_template_view.views.render',
{'template': 'faq.html'}, name="faq_edx"),
- url(r'^help$', 'static_template_view.views.render',
+ url(r'^help$', 'static_template_view.views.render',
{'template': 'help.html'}, name="help_edx"),
- url(r'^tos$', 'static_template_view.views.render',
+ url(r'^tos$', 'static_template_view.views.render',
{'template': 'tos.html'}, name="tos"),
- url(r'^privacy$', 'static_template_view.views.render',
+ url(r'^privacy$', 'static_template_view.views.render',
{'template': 'privacy.html'}, name="privacy_edx"),
# TODO: (bridger) The copyright has been removed until it is updated for edX
- # url(r'^copyright$', 'static_template_view.views.render',
+ # url(r'^copyright$', 'static_template_view.views.render',
# {'template': 'copyright.html'}, name="copyright"),
- url(r'^honor$', 'static_template_view.views.render',
+ url(r'^honor$', 'static_template_view.views.render',
{'template': 'honor.html'}, name="honor"),
-
- #Press releases
- url(r'^press/mit-and-harvard-announce-edx$', 'static_template_view.views.render',
+
+ #Press releases
+ url(r'^press/mit-and-harvard-announce-edx$', 'static_template_view.views.render',
{'template': 'press_releases/MIT_and_Harvard_announce_edX.html'}, name="press/mit-and-harvard-announce-edx"),
- url(r'^press/uc-berkeley-joins-edx$', 'static_template_view.views.render',
+ url(r'^press/uc-berkeley-joins-edx$', 'static_template_view.views.render',
{'template': 'press_releases/UC_Berkeley_joins_edX.html'}, name="press/uc-berkeley-joins-edx"),
# Should this always update to point to the latest press release?
- (r'^pressrelease$', 'django.views.generic.simple.redirect_to', {'url': '/press/uc-berkeley-joins-edx'}),
-
-
-
+ (r'^pressrelease$', 'django.views.generic.simple.redirect_to', {'url': '/press/uc-berkeley-joins-edx'}),
+
+
+
(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),
-
+
# TODO: These urls no longer work. They need to be updated before they are re-enabled
# url(r'^send_feedback$', 'util.views.send_feedback'),
# url(r'^reactivate/(?P[^/]*)$', 'student.views.reactivation_email'),
@@ -97,46 +97,46 @@ if settings.PERFSTATS:
if settings.COURSEWARE_ENABLED:
urlpatterns += (
url(r'^masquerade/', include('masquerade.urls')),
- url(r'^jumpto/(?P.*)$', 'courseware.views.jump_to'),
-
+ url(r'^jump_to/(?P.*)$', 'courseware.views.jump_to', name="jump_to"),
+
url(r'^modx/(?P.*?)/(?P[^/]*)$', 'courseware.module_render.modx_dispatch'), #reset_problem'),
url(r'^xqueue/(?P[^/]*)/(?P.*?)/(?P[^/]*)$', 'courseware.module_render.xqueue_callback'),
url(r'^change_setting$', 'student.views.change_setting'),
-
+
# TODO: These views need to be updated before they work
# url(r'^calculate$', 'util.views.calculate'),
# url(r'^gradebook$', 'courseware.views.gradebook'),
# TODO: We should probably remove the circuit package. I believe it was only used in the old way of saving wiki circuits for the wiki
# url(r'^edit_circuit/(?P[^/]*)$', 'circuit.views.edit_circuit'),
# url(r'^save_circuit/(?P[^/]*)$', 'circuit.views.save_circuit'),
-
- url(r'^courses/?$', 'courseware.views.courses', name="courses"),
- url(r'^change_enrollment$',
+
+ url(r'^courses/?$', 'courseware.views.courses', name="courses"),
+ url(r'^change_enrollment$',
'student.views.change_enrollment_view', name="change_enrollment"),
-
+
#About the course
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/about$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/about$',
'courseware.views.course_about', name="about_course"),
-
+
#Inside the course
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/info$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/info$',
'courseware.views.course_info', name="info"),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book$',
'staticbook.views.index', name="book"),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book/(?P[^/]*)$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book/(?P[^/]*)$',
'staticbook.views.index'),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book-shifted/(?P[^/]*)$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book-shifted/(?P[^/]*)$',
'staticbook.views.index_shifted'),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/courseware/?$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/courseware/?$',
'courseware.views.index', name="courseware"),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/courseware/(?P[^/]*)/(?P[^/]*)/$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/courseware/(?P[^/]*)/(?P[^/]*)/$',
'courseware.views.index', name="courseware_section"),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/profile$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/profile$',
'courseware.views.profile', name="profile"),
- url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/profile/(?P[^/]*)/$',
+ url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/profile/(?P[^/]*)/$',
'courseware.views.profile'),
)
-
+
# Multicourse wiki
if settings.WIKI_ENABLED:
urlpatterns += (
@@ -164,9 +164,9 @@ urlpatterns = patterns(*urlpatterns)
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
-
-
-#Custom error pages
+
+
+#Custom error pages
handler404 = 'static_template_view.views.render_404'
handler500 = 'static_template_view.views.render_500'
From 9c92aef6695b628e08d2918680366370ddbca3e5 Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Thu, 26 Jul 2012 21:11:43 -0400
Subject: [PATCH 24/55] Tweaks to test data for full course
* Add extra nested html file
* add a start date
---
common/test/data/full/chapter/Overview.xml | 1 +
common/test/data/full/course.xml | 2 +-
common/test/data/full/html/html_5555.html | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 common/test/data/full/html/html_5555.html
diff --git a/common/test/data/full/chapter/Overview.xml b/common/test/data/full/chapter/Overview.xml
index 8a0d3ef7ec..89917d20da 100644
--- a/common/test/data/full/chapter/Overview.xml
+++ b/common/test/data/full/chapter/Overview.xml
@@ -3,6 +3,7 @@
See the Lab Introduction or Interactive Lab Usage Handout for information on how to do the lab
+
diff --git a/common/test/data/full/course.xml b/common/test/data/full/course.xml
index 52d4753a1a..607d22672c 100644
--- a/common/test/data/full/course.xml
+++ b/common/test/data/full/course.xml
@@ -1 +1 @@
-
+
diff --git a/common/test/data/full/html/html_5555.html b/common/test/data/full/html/html_5555.html
new file mode 100644
index 0000000000..44a015faa1
--- /dev/null
+++ b/common/test/data/full/html/html_5555.html
@@ -0,0 +1 @@
+ Lab Introduction or Interactive Lab Usage Handout for information on how to do the lab
From a8afe5ed17ca49cf68b25932a73ca628552ddd6c Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Fri, 27 Jul 2012 15:58:55 -0400
Subject: [PATCH 25/55] Change modulestore to use a logging error handler
* log errors, but don't fail
---
common/lib/xmodule/xmodule/errorhandlers.py | 24 +++++++++++++++++--
common/lib/xmodule/xmodule/modulestore/xml.py | 4 ++--
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/common/lib/xmodule/xmodule/errorhandlers.py b/common/lib/xmodule/xmodule/errorhandlers.py
index 6840d9ff74..0f97377b2a 100644
--- a/common/lib/xmodule/xmodule/errorhandlers.py
+++ b/common/lib/xmodule/xmodule/errorhandlers.py
@@ -1,5 +1,12 @@
+import logging
import sys
+log = logging.getLogger(__name__)
+
+def in_exception_handler():
+ '''Is there an active exception?'''
+ return sys.exc_info() != (None, None, None)
+
def strict_error_handler(msg, exc_info=None):
'''
Do not let errors pass. If exc_info is not None, ignore msg, and just
@@ -11,13 +18,26 @@ def strict_error_handler(msg, exc_info=None):
if exc_info is not None:
raise exc_info[0], exc_info[1], exc_info[2]
- # Check if there is an exception being handled somewhere up the stack
- if sys.exc_info() != (None, None, None):
+ if in_exception_handler():
raise
raise Exception(msg)
+def logging_error_handler(msg, exc_info=None):
+ '''Log all errors, but otherwise let them pass, relying on the caller to
+ workaround.'''
+ if exc_info is not None:
+ log.exception(msg, exc_info=exc_info)
+ return
+
+ if in_exception_handler():
+ log.exception(msg)
+ return
+
+ log.error(msg)
+
+
def ignore_errors_handler(msg, exc_info=None):
'''Ignore all errors, relying on the caller to workaround.
Meant for use in the LMS, where an error in one part of the course
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 047e91e084..cfeac97780 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -3,7 +3,7 @@ from fs.osfs import OSFS
from importlib import import_module
from lxml import etree
from path import path
-from xmodule.errorhandlers import strict_error_handler
+from xmodule.errorhandlers import logging_error_handler
from xmodule.x_module import XModuleDescriptor, XMLParsingSystem
from xmodule.mako_module import MakoDescriptorSystem
from cStringIO import StringIO
@@ -100,7 +100,7 @@ class XMLModuleStore(ModuleStore):
"""
def __init__(self, data_dir, default_class=None, eager=False,
course_dirs=None,
- error_handler=strict_error_handler):
+ error_handler=logging_error_handler):
"""
Initialize an XMLModuleStore from data_dir
From cb3085075955caac7539a3a1ad1a85eded07617d Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Fri, 27 Jul 2012 16:04:02 -0400
Subject: [PATCH 26/55] Config for integration tests
* move askbot repo into mitx as a submodule
* set settings as in 85865f7221
* remove test_mongo env.
* Refactor tests to use new config structure.
* Add real integration tests--not working due to bugs in course xml. Turned off.
---
.gitmodules | 3 +
askbot | 1 +
lms/djangoapps/courseware/tests/tests.py | 100 ++++++++++++++++----
lms/envs/common.py | 2 +-
lms/envs/test.py | 26 +++---
lms/envs/test_mongo.py | 113 -----------------------
6 files changed, 100 insertions(+), 145 deletions(-)
create mode 100644 .gitmodules
create mode 160000 askbot
delete mode 100644 lms/envs/test_mongo.py
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..72ec77d0e2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "askbot"]
+ path = askbot
+ url = git@github.com:MITx/askbot-devel.git
diff --git a/askbot b/askbot
new file mode 160000
index 0000000000..1c3381046c
--- /dev/null
+++ b/askbot
@@ -0,0 +1 @@
+Subproject commit 1c3381046c78e055439ba1c78e0df48410fcc13e
diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py
index 24cc9eac00..8e9d13f8d5 100644
--- a/lms/djangoapps/courseware/tests/tests.py
+++ b/lms/djangoapps/courseware/tests/tests.py
@@ -1,4 +1,9 @@
+import copy
import json
+import os
+
+from pprint import pprint
+
from django.test import TestCase
from django.test.client import Client
from mock import patch, Mock
@@ -14,7 +19,6 @@ from xmodule.modulestore.django import modulestore
import xmodule.modulestore.django
from xmodule.modulestore import Location
from xmodule.modulestore.xml_importer import import_from_xml
-import copy
def parse_json(response):
@@ -32,14 +36,32 @@ def registration(email):
return Registration.objects.get(user__email=email)
-TEST_DATA_MODULESTORE = copy.deepcopy(settings.MODULESTORE)
-# TODO (vshnayder): test the real courses
-TEST_DATA_DIR = 'common/test/data'
-TEST_DATA_MODULESTORE['default']['OPTIONS']['fs_root'] = path(TEST_DATA_DIR)
+# A bit of a hack--want mongo modulestore for these tests, until
+# jump_to works with the xmlmodulestore or we have an even better solution
+# NOTE: this means this test requires mongo to be running.
-@override_settings(MODULESTORE=TEST_DATA_MODULESTORE)
-class IntegrationTestCase(TestCase):
- '''Check that all objects in all accessible courses will load properly'''
+def mongo_store_config(data_dir):
+ return {
+ 'default': {
+ 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
+ 'OPTIONS': {
+ 'default_class': 'xmodule.raw_module.RawDescriptor',
+ 'host': 'localhost',
+ 'db': 'xmodule',
+ 'collection': 'modulestore',
+ 'fs_root': data_dir,
+ }
+ }
+}
+
+TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
+TEST_DATA_MODULESTORE = mongo_store_config(TEST_DATA_DIR)
+
+REAL_DATA_DIR = settings.GITHUB_REPO_ROOT
+REAL_DATA_MODULESTORE = mongo_store_config(REAL_DATA_DIR)
+
+class ActivateLoginTestCase(TestCase):
+ '''Check that we can activate and log in'''
def setUp(self):
email = 'view@test.com'
@@ -47,9 +69,6 @@ class IntegrationTestCase(TestCase):
self.create_account('viewtest', email, password)
self.activate_user(email)
self.login(email, password)
- xmodule.modulestore.django._MODULESTORES = {}
- xmodule.modulestore.django.modulestore().collection.drop()
-
# ============ User creation and login ==============
@@ -107,15 +126,22 @@ class IntegrationTestCase(TestCase):
# Now make sure that the user is now actually activated
self.assertTrue(user(email).is_active)
- # ============ Page loading ==============
+ def test_activate_login(self):
+ '''The setup function does all the work'''
+ pass
- def check_pages_load(self, test_course_name):
- import_from_xml(modulestore(), TEST_DATA_DIR, [test_course_name])
+
+class PageLoader(ActivateLoginTestCase):
+ ''' Base class that adds a function to load all pages in a modulestore '''
+
+ def check_pages_load(self, course_name, data_dir, modstore):
+ print "Checking course {0} in {1}".format(course_name, data_dir)
+ import_from_xml(modstore, data_dir, [course_name])
n = 0
num_bad = 0
all_ok = True
- for descriptor in modulestore().get_items(
+ for descriptor in modstore.get_items(
Location(None, None, None, None, None)):
n += 1
print "Checking ", descriptor.location.url()
@@ -129,16 +155,54 @@ class IntegrationTestCase(TestCase):
all_ok = False
num_bad += 1
print msg
- self.assertTrue(all_ok)
+ self.assertTrue(all_ok) # fail fast
print "{0}/{1} good".format(n - num_bad, n)
+ self.assertTrue(all_ok)
+@override_settings(MODULESTORE=TEST_DATA_MODULESTORE)
+class TestCoursesLoadTestCase(PageLoader):
+ '''Check that all pages in test courses load properly'''
+
+ def setUp(self):
+ ActivateLoginTestCase.setUp(self)
+ xmodule.modulestore.django._MODULESTORES = {}
+ xmodule.modulestore.django.modulestore().collection.drop()
+
def test_toy_course_loads(self):
- self.check_pages_load('toy')
+ self.check_pages_load('toy', TEST_DATA_DIR, modulestore())
def test_full_course_loads(self):
- self.check_pages_load('full')
+ self.check_pages_load('full', TEST_DATA_DIR, modulestore())
+
+
+ # ========= TODO: check ajax interaction here too?
+
+
+@override_settings(MODULESTORE=REAL_DATA_MODULESTORE)
+class RealCoursesLoadTestCase(PageLoader):
+ '''Check that all pages in real courses load properly'''
+
+ def setUp(self):
+ ActivateLoginTestCase.setUp(self)
+ xmodule.modulestore.django._MODULESTORES = {}
+ xmodule.modulestore.django.modulestore().collection.drop()
+
+ # TODO: Disabled test for now.. Fix once things are cleaned up.
+ def Xtest_real_courses_loads(self):
+ '''See if any real courses are available at the REAL_DATA_DIR.
+ If they are, check them.'''
+
+ # TODO: adjust staticfiles_dirs
+ if not os.path.isdir(REAL_DATA_DIR):
+ # No data present. Just pass.
+ return
+
+ courses = [course_dir for course_dir in os.listdir(REAL_DATA_DIR)
+ if os.path.isdir(REAL_DATA_DIR / course_dir)]
+ for course in courses:
+ self.check_pages_load(course, REAL_DATA_DIR, modulestore())
# ========= TODO: check ajax interaction here too?
diff --git a/lms/envs/common.py b/lms/envs/common.py
index c9b44bca40..c071e61bb4 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -61,7 +61,7 @@ PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitx/lms
REPO_ROOT = PROJECT_ROOT.dirname()
COMMON_ROOT = REPO_ROOT / "common"
ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /mitx is in
-ASKBOT_ROOT = ENV_ROOT / "askbot-devel"
+ASKBOT_ROOT = REPO_ROOT / "askbot"
COURSES_ROOT = ENV_ROOT / "data"
# FIXME: To support multiple courses, we should walk the courses dir at startup
diff --git a/lms/envs/test.py b/lms/envs/test.py
index ef63063b51..e6fedcb373 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -12,15 +12,18 @@ from .logsettings import get_logger_config
import os
from path import path
-INSTALLED_APPS = [
- app
- for app
- in INSTALLED_APPS
- if not app.startswith('askbot')
-]
+# can't test start dates with this True, but on the other hand,
+# can test everything else :)
+MITX_FEATURES['DISABLE_START_DATES'] = True
+
+# Need wiki for courseware views to work. TODO (vshnayder): shouldn't need it.
+WIKI_ENABLED = True
+
+# Makes the tests run much faster...
+SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead
# Nose Test Runner
-INSTALLED_APPS += ['django_nose']
+INSTALLED_APPS += ('django_nose',)
NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
'--cover-inclusive', '--cover-html-dir',
os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
@@ -35,12 +38,6 @@ STATIC_ROOT = TEST_ROOT / "staticfiles"
COURSES_ROOT = TEST_ROOT / "data"
DATA_DIR = COURSES_ROOT
-MAKO_TEMPLATES['course'] = [DATA_DIR]
-MAKO_TEMPLATES['sections'] = [DATA_DIR / 'sections']
-MAKO_TEMPLATES['custom_tags'] = [DATA_DIR / 'custom_tags']
-MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
- DATA_DIR / 'info',
- DATA_DIR / 'problems']
LOGGING = get_logger_config(TEST_ROOT / "log",
logging_env="dev",
@@ -48,6 +45,9 @@ LOGGING = get_logger_config(TEST_ROOT / "log",
debug=True)
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
+# Where the content data is checked out. This may not exist on jenkins.
+GITHUB_REPO_ROOT = ENV_ROOT / "data"
+
# TODO (cpennington): We need to figure out how envs/test.py can inject things
# into common.py so that we don't have to repeat this sort of thing
diff --git a/lms/envs/test_mongo.py b/lms/envs/test_mongo.py
deleted file mode 100644
index cbf9209c96..0000000000
--- a/lms/envs/test_mongo.py
+++ /dev/null
@@ -1,113 +0,0 @@
-"""
-This config file runs the test environment, but with mongo as the datastore
-"""
-from .common import *
-
-from .logsettings import get_logger_config
-import os
-from path import path
-
-# can't testing start dates with this True, but on the other hand,
-# can test everything else :)
-MITX_FEATURES['DISABLE_START_DATES'] = True
-
-WIKI_ENABLED = True
-
-GITHUB_REPO_ROOT = ENV_ROOT / "data"
-
-MODULESTORE = {
- 'default': {
- 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
- 'OPTIONS': {
- 'default_class': 'xmodule.raw_module.RawDescriptor',
- 'host': 'localhost',
- 'db': 'xmodule',
- 'collection': 'modulestore',
- 'fs_root': GITHUB_REPO_ROOT,
- }
- }
-}
-
-
-# Nose Test Runner
-INSTALLED_APPS += ('django_nose',)
-NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
- '--cover-inclusive', '--cover-html-dir',
- os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
-for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
- NOSE_ARGS += ['--cover-package', app]
-TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
-
-
-TEST_ROOT = path("test_root")
-# Want static files in the same dir for running on jenkins.
-STATIC_ROOT = TEST_ROOT / "staticfiles"
-
-
-
-LOGGING = get_logger_config(TEST_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',
- 'KEY_FUNCTION': 'util.memcache.safe_key',
- },
-
- # 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,
- 'KEY_FUNCTION': 'util.memcache.safe_key',
- }
-}
-
-# Dummy secret key for dev
-SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
-
-# Makes the tests run much faster...
-SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead
-
-############################ FILE UPLOADS (ASKBOT) #############################
-DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
-MEDIA_ROOT = TEST_ROOT / "uploads"
-MEDIA_URL = "/static/uploads/"
-STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
-
-new_staticfiles_dirs = []
-# Strip out any static files that aren't in the repository root
-# so that the tests can run with only the mitx directory checked out
-for static_dir in STATICFILES_DIRS:
- # Handle both tuples and non-tuple directory definitions
- try:
- _, data_dir = static_dir
- except ValueError:
- data_dir = static_dir
-
- if data_dir.startswith(REPO_ROOT):
- new_staticfiles_dirs.append(static_dir)
-STATICFILES_DIRS = new_staticfiles_dirs
-
-FILE_UPLOAD_TEMP_DIR = PROJECT_ROOT / "uploads"
-FILE_UPLOAD_HANDLERS = (
- 'django.core.files.uploadhandler.MemoryFileUploadHandler',
- 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
-)
From 59defd33b687d73da933aabdca6b7b34e6d75a8b Mon Sep 17 00:00:00 2001
From: Victor Shnayder
Date: Fri, 27 Jul 2012 16:06:00 -0400
Subject: [PATCH 27/55] Formatting and little bugfixes
* add course and org to full/course.xml
* fix error path in clean_xml script
* commit rakefile change needed by c5334f150c
---
common/lib/xmodule/xmodule/capa_module.py | 6 +++--
common/lib/xmodule/xmodule/modulestore/xml.py | 14 +++++-----
common/lib/xmodule/xmodule/video_module.py | 2 +-
common/test/data/full/course.xml | 2 +-
.../management/commands/clean_xml.py | 2 +-
lms/djangoapps/courseware/module_render.py | 14 ++++++----
lms/envs/common.py | 26 +++++++++----------
rakefile | 5 ++--
8 files changed, 40 insertions(+), 31 deletions(-)
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 735f664b0a..02987822db 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -530,11 +530,13 @@ class CapaModule(XModule):
self.lcp.do_reset()
if self.rerandomize == "always":
- # reset random number generator seed (note the self.lcp.get_state() in next line)
+ # reset random number generator seed (note the self.lcp.get_state()
+ # in next line)
self.lcp.seed = None
self.lcp = LoncapaProblem(self.definition['data'],
- self.location.html_id(), self.lcp.get_state(), system=self.system)
+ self.location.html_id(), self.lcp.get_state(),
+ system=self.system)
event_info['new_state'] = self.lcp.get_state()
self.system.track_function('reset_problem', event_info)
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index cfeac97780..7dd6868f78 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -74,7 +74,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
etree.tostring(xml_data), self, org,
course, xmlstore.default_class)
- log.debug('==> importing module location %s' % repr(module.location))
+ #log.debug('==> importing module location %s' % repr(module.location))
module.metadata['data_dir'] = course_dir
xmlstore.modules[module.location] = module
@@ -130,13 +130,14 @@ class XMLModuleStore(ModuleStore):
self.default_class = None
else:
module_path, _, class_name = default_class.rpartition('.')
- log.debug('module_path = %s' % module_path)
+ #log.debug('module_path = %s' % module_path)
class_ = getattr(import_module(module_path), class_name)
self.default_class = class_
- # TODO (cpennington): We need a better way of selecting specific sets of debug messages to enable. These were drowning out important messages
- log.debug('XMLModuleStore: eager=%s, data_dir = %s' % (eager, self.data_dir))
- log.debug('default_class = %s' % self.default_class)
+ # TODO (cpennington): We need a better way of selecting specific sets of
+ # debug messages to enable. These were drowning out important messages
+ #log.debug('XMLModuleStore: eager=%s, data_dir = %s' % (eager, self.data_dir))
+ #log.debug('default_class = %s' % self.default_class)
# If we are specifically asked for missing courses, that should
# be an error. If we are asked for "all" courses, find the ones
@@ -162,6 +163,7 @@ class XMLModuleStore(ModuleStore):
returns a CourseDescriptor for the course
"""
+ log.debug('========> Starting course import from {0}'.format(course_dir))
with open(self.data_dir / course_dir / "course.xml") as course_file:
@@ -192,7 +194,7 @@ class XMLModuleStore(ModuleStore):
self.error_handler)
course_descriptor = system.process_xml(etree.tostring(course_data))
- log.debug('========> Done with course import')
+ log.debug('========> Done with course import from {0}'.format(course_dir))
return course_descriptor
def get_item(self, location, depth=0):
diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py
index a8f6db9c27..da10e4bc91 100644
--- a/common/lib/xmodule/xmodule/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module.py
@@ -60,7 +60,7 @@ class VideoModule(XModule):
return None
def get_instance_state(self):
- log.debug(u"STATE POSITION {0}".format(self.position))
+ #log.debug(u"STATE POSITION {0}".format(self.position))
return json.dumps({'position': self.position})
def video_list(self):
diff --git a/common/test/data/full/course.xml b/common/test/data/full/course.xml
index 607d22672c..c365e68cc1 100644
--- a/common/test/data/full/course.xml
+++ b/common/test/data/full/course.xml
@@ -1 +1 @@
-
+
diff --git a/lms/djangoapps/courseware/management/commands/clean_xml.py b/lms/djangoapps/courseware/management/commands/clean_xml.py
index bd0c2b21bb..7523fd8373 100644
--- a/lms/djangoapps/courseware/management/commands/clean_xml.py
+++ b/lms/djangoapps/courseware/management/commands/clean_xml.py
@@ -104,7 +104,7 @@ def import_with_checks(course_dir, verbose=True):
if n != 1:
print 'ERROR: Expect exactly 1 course. Loaded {n}: {lst}'.format(
n=n, lst=courses)
- return
+ return (False, None)
course = courses[0]
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index 01e46b8def..bf7d1f4c51 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -119,16 +119,18 @@ def get_module(user, request, location, student_module_cache, position=None):
instance_module is a StudentModule specific to this module for this student,
or None if this is an anonymous user
shared_module is a StudentModule specific to all modules with the same
- 'shared_state_key' attribute, or None if the module doesn't elect to
+ 'shared_state_key' attribute, or None if the module does not elect to
share state
'''
descriptor = modulestore().get_item(location)
- instance_module = student_module_cache.lookup(descriptor.category, descriptor.location.url())
+ instance_module = student_module_cache.lookup(descriptor.category,
+ descriptor.location.url())
shared_state_key = getattr(descriptor, 'shared_state_key', None)
if shared_state_key is not None:
- shared_module = student_module_cache.lookup(descriptor.category, shared_state_key)
+ shared_module = student_module_cache.lookup(descriptor.category,
+ shared_state_key)
else:
shared_module = None
@@ -138,10 +140,12 @@ def get_module(user, request, location, student_module_cache, position=None):
# TODO (vshnayder): fix hardcoded urls (use reverse)
# Setup system context for module instance
ajax_url = settings.MITX_ROOT_URL + '/modx/' + descriptor.location.url() + '/'
- xqueue_callback_url = settings.MITX_ROOT_URL + '/xqueue/' + str(user.id) + '/' + descriptor.location.url() + '/'
+ xqueue_callback_url = (settings.MITX_ROOT_URL + '/xqueue/' +
+ str(user.id) + '/' + descriptor.location.url() + '/')
def _get_module(location):
- (module, _, _, _) = get_module(user, request, location, student_module_cache, position)
+ (module, _, _, _) = get_module(user, request, location,
+ student_module_cache, position)
return module
# TODO (cpennington): When modules are shared between courses, the static
diff --git a/lms/envs/common.py b/lms/envs/common.py
index c071e61bb4..6d46f1cf9d 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -6,16 +6,16 @@ MITX_FEATURES[...]. Modules that extend this one can change the feature
configuration in an environment specific config file and re-calculate those
values.
-We should make a method that calls all these config methods so that you just
+We should make a method that calls all these config methods so that you just
make one call at the end of your site-specific dev file to reset all the
dependent variables (like INSTALLED_APPS) for you.
Longer TODO:
-1. Right now our treatment of static content in general and in particular
+1. Right now our treatment of static content in general and in particular
course-specific static content is haphazard.
2. We should have a more disciplined approach to feature flagging, even if it
just means that we stick them in a dict called MITX_FEATURES.
-3. We need to handle configuration for multiple courses. This could be as
+3. We need to handle configuration for multiple courses. This could be as
multiple sites, but we do need a way to map their data assets.
"""
import sys
@@ -42,7 +42,7 @@ MITX_FEATURES = {
'SAMPLE' : False,
'USE_DJANGO_PIPELINE' : True,
'DISPLAY_HISTOGRAMS_TO_STAFF' : True,
- 'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
+ 'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
'DEBUG_LEVEL' : 0, # 0 = lowest level, least verbose, 255 = max level, most verbose
## DO NOT SET TO True IN THIS FILE
@@ -85,7 +85,7 @@ MAKO_TEMPLATES['main'] = [PROJECT_ROOT / 'templates',
COMMON_ROOT / 'lib' / 'capa' / 'capa' / 'templates',
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates']
-# This is where Django Template lookup is defined. There are a few of these
+# This is where Django Template lookup is defined. There are a few of these
# still left lying around.
TEMPLATE_DIRS = (
PROJECT_ROOT / "templates",
@@ -103,8 +103,8 @@ TEMPLATE_CONTEXT_PROCESSORS = (
)
-# FIXME:
-# We should have separate S3 staged URLs in case we need to make changes to
+# FIXME:
+# We should have separate S3 staged URLs in case we need to make changes to
# these assets and test them.
LIB_URL = '/static/js/'
@@ -120,7 +120,7 @@ STATIC_GRAB = False
DEV_CONTENT = True
# FIXME: Should we be doing this truncation?
-TRACK_MAX_EVENT = 10000
+TRACK_MAX_EVENT = 10000
DEBUG_TRACK_LOG = False
MITX_ROOT_URL = ''
@@ -129,7 +129,7 @@ COURSE_NAME = "6.002_Spring_2012"
COURSE_NUMBER = "6.002x"
COURSE_TITLE = "Circuits and Electronics"
-### Dark code. Should be enabled in local settings for devel.
+### Dark code. Should be enabled in local settings for devel.
ENABLE_MULTICOURSE = False # set to False to disable multicourse display (see lib.util.views.mitxhome)
QUICKEDIT = False
@@ -211,9 +211,9 @@ USE_L10N = True
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
#################################### AWS #######################################
-# S3BotoStorage insists on a timeout for uploaded assets. We should make it
+# S3BotoStorage insists on a timeout for uploaded assets. We should make it
# permanent instead, but rather than trying to figure out exactly where that
-# setting is, I'm just bumping the expiration time to something absurd (100
+# setting is, I'm just bumping the expiration time to something absurd (100
# years). This is only used if DEFAULT_FILE_STORAGE is overriden to use S3
# in the global settings.py
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
@@ -279,7 +279,7 @@ MIDDLEWARE_CLASSES = (
# Instead of AuthenticationMiddleware, we use a cached backed version
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
-
+
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
'mitxmako.middleware.MakoMiddleware',
@@ -502,7 +502,7 @@ INSTALLED_APPS = (
# For testing
'django_jasmine',
- # For Askbot
+ # For Askbot
'django.contrib.sitemaps',
'django.contrib.admin',
'django_countries',
diff --git a/rakefile b/rakefile
index fd23b9643a..d69f7329bb 100644
--- a/rakefile
+++ b/rakefile
@@ -51,6 +51,7 @@ default_options = {
task :predjango do
sh("find . -type f -name *.pyc -delete")
sh('pip install -e common/lib/xmodule')
+ sh('git submodule update --init')
end
[:lms, :cms, :common].each do |system|
@@ -150,14 +151,14 @@ end
task :package do
FileUtils.mkdir_p(BUILD_DIR)
-
+
Dir.chdir(BUILD_DIR) do
afterremove = Tempfile.new('afterremove')
afterremove.write <<-AFTERREMOVE.gsub(/^\s*/, '')
#! /bin/bash
set -e
set -x
-
+
# to be a little safer this rm is executed
# as the makeitso user
From d94fd1542d792bbf6393eed69a1fe1f8854ac7ec Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Tue, 10 Jul 2012 16:33:36 -0400
Subject: [PATCH 28/55] Added Gemfile.lock to ignore
---
lms/static/.gitignore | 2 +-
lms/static/sass/course.css | 5253 ++++++++++++++++++++++++++++++++++++
2 files changed, 5254 insertions(+), 1 deletion(-)
create mode 100644 lms/static/sass/course.css
diff --git a/lms/static/.gitignore b/lms/static/.gitignore
index 03f1cdabff..cec91505bb 100644
--- a/lms/static/.gitignore
+++ b/lms/static/.gitignore
@@ -5,4 +5,4 @@
*.orig
*.DS_Store
application.css
-ie.css
\ No newline at end of file
+ie.css
diff --git a/lms/static/sass/course.css b/lms/static/sass/course.css
new file mode 100644
index 0000000000..78c7421f5b
--- /dev/null
+++ b/lms/static/sass/course.css
@@ -0,0 +1,5253 @@
+@charset "UTF-8";
+/* HTML5 Boilerplate */
+article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
+ display: block; }
+
+audio, canvas, video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1; }
+
+audio:not([controls]) {
+ display: none; }
+
+[hidden] {
+ display: none; }
+
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%; }
+
+html, button, input, select, textarea {
+ font-family: sans-serif;
+ color: #222; }
+
+body {
+ margin: 0;
+ font-size: 1em;
+ line-height: 1.4; }
+
+::-moz-selection {
+ background: #fe57a1;
+ color: #fff;
+ text-shadow: none; }
+
+::selection {
+ background: #fe57a1;
+ color: #fff;
+ text-shadow: none; }
+
+a {
+ color: #00e; }
+
+a:visited {
+ color: #551a8b; }
+
+a:hover {
+ color: #06e; }
+
+a:focus {
+ outline: thin dotted; }
+
+a:hover, a:active {
+ outline: 0; }
+
+abbr[title] {
+ border-bottom: 1px dotted; }
+
+b, strong {
+ font-weight: bold; }
+
+blockquote {
+ margin: 1em 40px; }
+
+dfn {
+ font-style: italic; }
+
+hr {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0; }
+
+ins {
+ background: #ff9;
+ color: #000;
+ text-decoration: none; }
+
+mark {
+ background: #ff0;
+ color: #000;
+ font-style: italic;
+ font-weight: bold; }
+
+pre, code, kbd, samp {
+ font-family: monospace, serif;
+ _font-family: 'courier new', monospace;
+ font-size: 1em; }
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word; }
+
+q {
+ quotes: none; }
+
+q:before, q:after {
+ content: "";
+ content: none; }
+
+small {
+ font-size: 85%; }
+
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline; }
+
+sup {
+ top: -0.5em; }
+
+sub {
+ bottom: -0.25em; }
+
+ul, ol {
+ margin: 1em 0;
+ padding: 0 0 0 40px; }
+
+dd {
+ margin: 0 0 0 40px; }
+
+nav ul, nav ol {
+ list-style: none;
+ list-style-image: none;
+ margin: 0;
+ padding: 0; }
+
+img {
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+ vertical-align: middle; }
+
+svg:not(:root) {
+ overflow: hidden; }
+
+figure {
+ margin: 0; }
+
+form {
+ margin: 0; }
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0; }
+
+label {
+ cursor: pointer; }
+
+legend {
+ border: 0;
+ *margin-left: -7px;
+ padding: 0;
+ white-space: normal; }
+
+button, input, select, textarea {
+ font-size: 100%;
+ margin: 0;
+ vertical-align: baseline;
+ *vertical-align: middle; }
+
+button, input {
+ line-height: normal; }
+
+button, input[type="button"], input[type="reset"], input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+ *overflow: visible; }
+
+button[disabled], input[disabled] {
+ cursor: default; }
+
+input[type="checkbox"], input[type="radio"] {
+ box-sizing: border-box;
+ padding: 0;
+ *width: 13px;
+ *height: 13px; }
+
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box; }
+
+input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+button::-moz-focus-inner, input::-moz-focus-inner {
+ border: 0;
+ padding: 0; }
+
+textarea {
+ overflow: auto;
+ vertical-align: top;
+ resize: vertical; }
+
+input:invalid, textarea:invalid {
+ background-color: #f0dddd; }
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0; }
+
+td {
+ vertical-align: top; }
+
+.chromeframe {
+ margin: 0.2em 0;
+ background: #ccc;
+ color: black;
+ padding: 0.2em 0; }
+
+.ir {
+ display: block;
+ border: 0;
+ text-indent: -999em;
+ overflow: hidden;
+ background-color: transparent;
+ background-repeat: no-repeat;
+ text-align: left;
+ direction: ltr;
+ *line-height: 0; }
+
+.ir br {
+ display: none; }
+
+.hidden {
+ display: none !important;
+ visibility: hidden; }
+
+.visuallyhidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px; }
+
+.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ width: auto; }
+
+.invisible {
+ visibility: hidden; }
+
+.clearfix:before, .topbar:before, nav.sequence-nav:before, div.book-wrapper section.book nav:before, div.course-wrapper section.course-content .problem-set:before, div.course-wrapper section.course-content section.problems-wrapper:before, div.course-wrapper section.course-content div#seq_content:before, div.course-wrapper section.course-content ol.vert-mod > li:before, section.course-content nav.sequence-bottom ul:before, section.course-content div.video article.video-wrapper section.video-controls:before, section.course-content div.video article.video-wrapper section.video-controls div.slider:before, section.tool-wrapper:before, section.tool-wrapper div#controlls-container:before, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:before, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:before, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:before, section.problem-set:before, section.problems-wrapper:before, div.info-wrapper section.updates > ol > li:before, div.info-wrapper section.handouts ol li:before, div.book-wrapper section.book nav ul:before, .clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
+ content: "";
+ display: table; }
+
+.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
+ clear: both; }
+
+.clearfix, .topbar, nav.sequence-nav, div.book-wrapper section.book nav, div.course-wrapper section.course-content .problem-set, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content, div.course-wrapper section.course-content ol.vert-mod > li, section.course-content nav.sequence-bottom ul, section.course-content div.video article.video-wrapper section.video-controls, section.course-content div.video article.video-wrapper section.video-controls div.slider, section.tool-wrapper, section.tool-wrapper div#controlls-container, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders, section.problem-set, section.problems-wrapper, div.info-wrapper section.updates > ol > li, div.info-wrapper section.handouts ol li, div.book-wrapper section.book nav ul {
+ *zoom: 1; }
+
+@media print {
+ * {
+ background: transparent !important;
+ color: black !important;
+ box-shadow: none !important;
+ text-shadow: none !important;
+ filter: none !important;
+ -ms-filter: none !important; }
+
+ a, a:visited {
+ text-decoration: underline; }
+
+ a[href]:after {
+ content: " (" attr(href) ")"; }
+
+ abbr[title]:after {
+ content: " (" attr(title) ")"; }
+
+ .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
+ content: ""; }
+
+ pre, blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid; }
+
+ thead {
+ display: table-header-group; }
+
+ tr, img {
+ page-break-inside: avoid; }
+
+ img {
+ max-width: 100% !important; }
+
+ @page {
+ margin: 0.5cm; }
+
+ p, h2, h3 {
+ orphans: 3;
+ widows: 3; }
+
+ h2, h3 {
+ page-break-after: avoid; } }
+/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-Light-webfont.eot");
+ src: url("../fonts/OpenSans-Light-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Light-webfont.woff") format("woff"), url("../fonts/OpenSans-Light-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Light-webfont.svg#OpenSansLight") format("svg");
+ font-weight: 300;
+ font-style: normal; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-LightItalic-webfont.eot");
+ src: url("../fonts/OpenSans-LightItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-LightItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-LightItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic") format("svg");
+ font-weight: 300;
+ font-style: italic; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-Regular-webfont.eot");
+ src: url("../fonts/OpenSans-Regular-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Regular-webfont.woff") format("woff"), url("../fonts/OpenSans-Regular-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular") format("svg");
+ font-weight: 400;
+ font-style: normal; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-Italic-webfont.eot");
+ src: url("../fonts/OpenSans-Italic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Italic-webfont.woff") format("woff"), url("../fonts/OpenSans-Italic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic") format("svg");
+ font-weight: 400;
+ font-style: italic; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-Bold-webfont.eot");
+ src: url("../fonts/OpenSans-Bold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Bold-webfont.woff") format("woff"), url("../fonts/OpenSans-Bold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Bold-webfont.svg#OpenSansBold") format("svg");
+ font-weight: 700;
+ font-style: normal; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-BoldItalic-webfont.eot");
+ src: url("../fonts/OpenSans-BoldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-BoldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-BoldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic") format("svg");
+ font-weight: 700;
+ font-style: italic; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-ExtraBold-webfont.eot");
+ src: url("../fonts/OpenSans-ExtraBold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-ExtraBold-webfont.woff") format("woff"), url("../fonts/OpenSans-ExtraBold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold") format("svg");
+ font-weight: 800;
+ font-style: normal; }
+
+@font-face {
+ font-family: 'Open Sans';
+ src: url("../fonts/OpenSans-ExtraBoldItalic-webfont.eot");
+ src: url("../fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic") format("svg");
+ font-weight: 800;
+ font-style: italic; }
+
+html, body {
+ background: #fafafa;
+ font-family: "Open Sans", Verdana, Geneva, sans-serif;
+ font-size: 1em;
+ line-height: 1em; }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #3c3c3c;
+ font: normal 1.2em/1.2em Georgia, Cambria, "Times New Roman", Times, serif;
+ margin: 0px; }
+
+h1 {
+ color: #3c3c3c;
+ font: normal 2em/1.4em "Open Sans", Verdana, Geneva, sans-serif;
+ letter-spacing: 1px;
+ margin-bottom: 30px;
+ text-align: center; }
+
+h2 {
+ color: #a0a0a0;
+ font: normal 1.2em/1.2em Georgia, Cambria, "Times New Roman", Times, serif;
+ letter-spacing: 1px;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+ -webkit-font-smoothing: antialiased; }
+
+p + h2, ul + h2, ol + h2 {
+ margin-top: 40px; }
+
+p {
+ color: #3c3c3c;
+ font: normal 1em/1.6em Georgia, Cambria, "Times New Roman", Times, serif;
+ margin: 0px; }
+
+span {
+ font: normal 1em/1.6em "Open Sans", Verdana, Geneva, sans-serif; }
+
+p + p, ul + p, ol + p {
+ margin-top: 20px; }
+
+p a:link, p a:visited {
+ color: #1d9dd9;
+ font: normal 1em/1em Georgia, Cambria, "Times New Roman", Times, serif;
+ text-decoration: none;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.1s;
+ -moz-transition-duration: 0.1s;
+ -ms-transition-duration: 0.1s;
+ -o-transition-duration: 0.1s;
+ transition-duration: 0.1s;
+ -webkit-transition-timing-function: linear;
+ -moz-transition-timing-function: linear;
+ -ms-transition-timing-function: linear;
+ -o-transition-timing-function: linear;
+ transition-timing-function: linear;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ p a:link:hover, p a:visited:hover {
+ color: #1d9dd9;
+ text-decoration: underline; }
+
+a:link, a:visited {
+ color: #1d9dd9;
+ font: normal 1em/1em "Open Sans", Verdana, Geneva, sans-serif;
+ text-decoration: none;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.1s;
+ -moz-transition-duration: 0.1s;
+ -ms-transition-duration: 0.1s;
+ -o-transition-duration: 0.1s;
+ transition-duration: 0.1s;
+ -webkit-transition-timing-function: linear;
+ -moz-transition-timing-function: linear;
+ -ms-transition-timing-function: linear;
+ -o-transition-timing-function: linear;
+ transition-timing-function: linear;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ a:link:hover, a:visited:hover {
+ text-decoration: underline; }
+
+.content-wrapper {
+ background: white;
+ margin: 0 auto 0;
+ width: 100%; }
+
+.container {
+ zoom: 1;
+ margin: 0 auto 0;
+ padding: 0px 30px;
+ max-width: 1180px;
+ min-width: 760px; }
+ .container:before, .container:after {
+ content: "";
+ display: table; }
+ .container:after {
+ clear: both; }
+
+span.edx {
+ text-transform: none;
+ font: inherit; }
+
+.static-container {
+ zoom: 1;
+ margin: 0 auto 0;
+ max-width: 1200px;
+ padding: 60px 0px 120px;
+ width: 100%; }
+ .static-container:before, .static-container:after {
+ content: "";
+ display: table; }
+ .static-container:after {
+ clear: both; }
+ .static-container .inner-wrapper {
+ margin: 0 auto 0;
+ width: 83.051%; }
+ .static-container ol, .static-container ul {
+ list-style: disc; }
+ .static-container ol li, .static-container ul li {
+ color: #3c3c3c;
+ font: normal 1em/1.4em Georgia, Cambria, "Times New Roman", Times, serif;
+ margin: 0px; }
+ .static-container h1 {
+ margin-bottom: 30px; }
+ .static-container h1 + hr {
+ margin-bottom: 60px; }
+ .static-container p + h2, .static-container ul + h2, .static-container ol + h2 {
+ margin-top: 40px; }
+ .static-container ul + p, .static-container ol + p {
+ margin-top: 20px; }
+
+.faded-hr-divider, .horizontal-divider {
+ background-image: -webkit-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -moz-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -ms-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -o-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ height: 1px;
+ width: 100%; }
+
+.faded-hr-divider-medium {
+ background-image: -webkit-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
+ background-image: -moz-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
+ background-image: -ms-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
+ background-image: -o-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
+ background-image: linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
+ height: 1px;
+ width: 100%; }
+
+.faded-hr-divider-light, .horizontal-divider::after {
+ background-image: -webkit-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
+ background-image: -moz-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
+ background-image: -ms-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
+ background-image: -o-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
+ background-image: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
+ height: 1px;
+ width: 100%; }
+
+.faded-vertical-divider, .vertical-divider {
+ background-image: -webkit-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -moz-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -ms-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: -o-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ background-image: linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
+ height: 100%;
+ width: 1px; }
+
+.faded-vertical-divider-light, .vertical-divider::after {
+ background-image: -webkit-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
+ background-image: -moz-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
+ background-image: -ms-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
+ background-image: -o-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
+ background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
+ height: 100%;
+ width: 1px; }
+
+.vertical-divider {
+ position: relative; }
+ .vertical-divider::after {
+ content: "";
+ display: block;
+ position: absolute;
+ left: 1px; }
+
+.horizontal-divider {
+ border: none;
+ position: relative; }
+ .horizontal-divider::after {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 1px; }
+
+.fade-right-hr-divider {
+ background-image: -webkit-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
+ background-image: -moz-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
+ background-image: -ms-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
+ background-image: -o-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
+ background-image: linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
+ border: none; }
+
+.fade-left-hr-divider {
+ background-image: -webkit-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
+ background-image: -moz-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
+ background-image: -ms-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
+ background-image: -o-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
+ background-image: linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
+ border: none; }
+
+.error-message-colors {
+ background: #fd5757;
+ border: 1px solid #ca1111;
+ color: #8f0e0e; }
+
+.success-message-colors {
+ background: #63ec89;
+ border: 1px solid #11ca36;
+ color: #238f0e; }
+
+.animation-home-header-pop-up {
+ -webkit-animation: home-header-pop-up 1.15s ease-in-out;
+ -moz-animation: home-header-pop-up 1.15s ease-in-out;
+ animation: home-header-pop-up 1.15s ease-in-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 1s;
+ -moz-animation-delay: 1s;
+ animation-delay: 1s; }
+
+@-webkit-keyframes home-header-pop-up {
+ 0% {
+ opacity: 0;
+ top: 300px; }
+
+ 45% {
+ opacity: 1; }
+
+ 65% {
+ top: -40px; }
+
+ 85% {
+ top: 10px; }
+
+ 100% {
+ top: 0px; } }
+
+@-moz-keyframes home-header-pop-up {
+ 0% {
+ opacity: 0;
+ top: 300px; }
+
+ 45% {
+ opacity: 1; }
+
+ 65% {
+ top: -40px; }
+
+ 85% {
+ top: 10px; }
+
+ 100% {
+ top: 0px; } }
+
+@keyframes home-header-pop-up {
+ 0% {
+ opacity: 0;
+ top: 300px; }
+
+ 45% {
+ opacity: 1; }
+
+ 65% {
+ top: -40px; }
+
+ 85% {
+ top: 10px; }
+
+ 100% {
+ top: 0px; } }
+
+.animation-title-appear {
+ -webkit-animation: title-appear 4.65s ease-out;
+ -moz-animation: title-appear 4.65s ease-out;
+ animation: title-appear 4.65s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 1s;
+ -moz-animation-delay: 1s;
+ animation-delay: 1s; }
+
+@-webkit-keyframes title-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 27% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 90% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ top: 0px; } }
+
+@-moz-keyframes title-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 27% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 90% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ top: 0px; } }
+
+@keyframes title-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 27% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 90% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ top: 0px; } }
+
+.animation-home-appear {
+ -webkit-animation: home-appear 4.25s ease-out;
+ -moz-animation: home-appear 4.25s ease-out;
+ animation: home-appear 4.25s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 1s;
+ -moz-animation-delay: 1s;
+ animation-delay: 1s; }
+
+@-webkit-keyframes home-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 30% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 80% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.7);
+ -moz-transform: scale(0.7);
+ -ms-transform: scale(0.7);
+ -o-transform: scale(0.7);
+ transform: scale(0.7); } }
+
+@-moz-keyframes home-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 30% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 80% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.7);
+ -moz-transform: scale(0.7);
+ -ms-transform: scale(0.7);
+ -o-transform: scale(0.7);
+ transform: scale(0.7); } }
+
+@keyframes home-appear {
+ 0% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.9);
+ -moz-transform: scale(0.9);
+ -ms-transform: scale(0.9);
+ -o-transform: scale(0.9);
+ transform: scale(0.9); }
+
+ 20% {
+ opacity: 1; }
+
+ 30% {
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 80% {
+ opacity: 1;
+ top: 40px;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1); }
+
+ 100% {
+ opacity: 0;
+ top: 60px;
+ -webkit-transform: scale(0.7);
+ -moz-transform: scale(0.7);
+ -ms-transform: scale(0.7);
+ -o-transform: scale(0.7);
+ transform: scale(0.7); } }
+
+.animation-edx-appear {
+ -webkit-animation: edx-appear 1.25s ease-in;
+ -moz-animation: edx-appear 1.25s ease-in;
+ animation: edx-appear 1.25s ease-in;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 2.15s;
+ -moz-animation-delay: 2.15s;
+ animation-delay: 2.15s; }
+
+@-webkit-keyframes edx-appear {
+ 0% {
+ opacity: 0; }
+
+ 100% {
+ opacity: 1; } }
+
+@-moz-keyframes edx-appear {
+ 0% {
+ opacity: 0; }
+
+ 100% {
+ opacity: 1; } }
+
+@keyframes edx-appear {
+ 0% {
+ opacity: 0; }
+
+ 100% {
+ opacity: 1; } }
+
+.animation-mit-slide {
+ -webkit-animation: mit-slide 1.15s ease-out;
+ -moz-animation: mit-slide 1.15s ease-out;
+ animation: mit-slide 1.15s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 2s;
+ -moz-animation-delay: 2s;
+ animation-delay: 2s; }
+
+@-webkit-keyframes mit-slide {
+ 0% {
+ left: 80px; }
+
+ 100% {
+ left: 0px; } }
+
+@-moz-keyframes mit-slide {
+ 0% {
+ left: 80px; }
+
+ 100% {
+ left: 0px; } }
+
+@keyframes mit-slide {
+ 0% {
+ left: 80px; }
+
+ 100% {
+ left: 0px; } }
+
+.animation-harvard-slide {
+ -webkit-animation: harvard-slide 1.15s ease-out;
+ -moz-animation: harvard-slide 1.15s ease-out;
+ animation: harvard-slide 1.15s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 2s;
+ -moz-animation-delay: 2s;
+ animation-delay: 2s; }
+
+@-webkit-keyframes harvard-slide {
+ 0% {
+ right: 80px; }
+
+ 100% {
+ right: 0px; } }
+
+@-moz-keyframes harvard-slide {
+ 0% {
+ right: 80px; }
+
+ 100% {
+ right: 0px; } }
+
+@keyframes harvard-slide {
+ 0% {
+ right: 80px; }
+
+ 100% {
+ right: 0px; } }
+
+.animation-divider-left-slide {
+ -webkit-animation: divider-left-slide 1.1s ease-out;
+ -moz-animation: divider-left-slide 1.1s ease-out;
+ animation: divider-left-slide 1.1s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 2s;
+ -moz-animation-delay: 2s;
+ animation-delay: 2s; }
+
+@-webkit-keyframes divider-left-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 200px; } }
+
+@-moz-keyframes divider-left-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 200px; } }
+
+@keyframes divider-left-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 200px; } }
+
+.animation-divider-right-slide {
+ -webkit-animation: divider-right-slide 1.1s ease-out;
+ -moz-animation: divider-right-slide 1.1s ease-out;
+ animation: divider-right-slide 1.1s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 2s;
+ -moz-animation-delay: 2s;
+ animation-delay: 2s; }
+
+@-webkit-keyframes divider-right-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 480px; } }
+
+@-moz-keyframes divider-right-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 480px; } }
+
+@keyframes divider-right-slide {
+ 0% {
+ left: 340px; }
+
+ 100% {
+ left: 480px; } }
+
+.animation-video-appear {
+ -webkit-animation: video-appear 1.25s ease-out;
+ -moz-animation: video-appear 1.25s ease-out;
+ animation: video-appear 1.25s ease-out;
+ -webkit-animation-fill-mode: both;
+ -moz-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-delay: 4.4s;
+ -moz-animation-delay: 4.4s;
+ animation-delay: 4.4s; }
+
+@-webkit-keyframes video-appear {
+ 0% {
+ bottom: -270px;
+ opacity: 0.9; }
+
+ 80% {
+ opacity: 1; }
+
+ 100% {
+ bottom: 0px; } }
+
+@-moz-keyframes video-appear {
+ 0% {
+ bottom: -270px;
+ opacity: 0.9; }
+
+ 80% {
+ opacity: 1; }
+
+ 100% {
+ bottom: 0px; } }
+
+@keyframes video-appear {
+ 0% {
+ bottom: -270px;
+ opacity: 0.9; }
+
+ 80% {
+ opacity: 1; }
+
+ 100% {
+ bottom: 0px; } }
+
+nav.course-material {
+ background: #d2d2d2;
+ zoom: 1;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
+ border-bottom: 1px solid #bebebe;
+ margin: 0px auto 0px;
+ padding: 0px;
+ width: 100%; }
+ nav.course-material:before, nav.course-material:after {
+ content: "";
+ display: table; }
+ nav.course-material:after {
+ clear: both; }
+ nav.course-material .inner-wrapper {
+ margin: 0 auto;
+ max-width: 1200px;
+ width: 100%; }
+ nav.course-material ol.course-tabs {
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ -ms-border-top-left-radius: 4px;
+ -o-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -ms-border-top-right-radius: 4px;
+ -o-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ zoom: 1;
+ padding: 10px 0 0 0; }
+ nav.course-material ol.course-tabs:before, nav.course-material ol.course-tabs:after {
+ content: "";
+ display: table; }
+ nav.course-material ol.course-tabs:after {
+ clear: both; }
+ nav.course-material ol.course-tabs li {
+ float: left;
+ list-style: none; }
+ nav.course-material ol.course-tabs li a {
+ color: #a0a0a0;
+ display: block;
+ text-align: center;
+ padding: 5px 13px;
+ text-decoration: none;
+ text-shadow: 0 1px rgba(255, 255, 255, 0.4); }
+ nav.course-material ol.course-tabs li a:hover {
+ color: #3c3c3c; }
+ nav.course-material ol.course-tabs li a.active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_video_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_video_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_other_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_other_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_vertical_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_vertical_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_problem_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_problem_active {
+ background: white;
+ border: 1px solid #c8c8c8;
+ border-bottom: 0px;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ -ms-border-top-left-radius: 4px;
+ -o-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -ms-border-top-right-radius: 4px;
+ -o-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -webkit-box-shadow: 0 2px 0 0 white;
+ -moz-box-shadow: 0 2px 0 0 white;
+ box-shadow: 0 2px 0 0 white;
+ color: #3c3c3c; }
+
+.course-content {
+ margin-top: 30px; }
+ .course-content .courseware {
+ min-height: 300px; }
+
+.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
+ clear: both;
+ content: ".";
+ display: block;
+ height: 0;
+ visibility: hidden; }
+
+.wrapper {
+ margin: 0 auto;
+ max-width: 1400px;
+ min-width: 810px;
+ text-align: left;
+ width: 100%; }
+ .wrapper div.table-wrapper, .wrapper div.course-wrapper, .wrapper div.info-wrapper, .wrapper div.book-wrapper {
+ display: table;
+ width: 100%;
+ overflow: hidden; }
+ @media screen and (min-width: 1400px) {
+ .wrapper div.table-wrapper, .wrapper div.course-wrapper, .wrapper div.info-wrapper, .wrapper div.book-wrapper {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -ms-border-radius: 4px;
+ -o-border-radius: 4px;
+ border-radius: 4px; } }
+
+h1.top-header, div.course-wrapper section.course-content ol.vert-mod > li header, div.info-wrapper section.updates > h1 {
+ background: #f3f3f3;
+ border-bottom: 1px solid #e3e3e3;
+ margin: -lh() -lh() lh();
+ padding: lh(); }
+
+.button {
+ border: 1px solid #6f6f6f;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
+ -moz-box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
+ box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
+ color: #fff;
+ cursor: pointer;
+ font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ background-color: #959595;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #959595), color-stop(100%, #7b7b7b));
+ background-image: -webkit-linear-gradient(top, #959595, #7b7b7b);
+ background-image: -moz-linear-gradient(top, #959595, #7b7b7b);
+ background-image: -ms-linear-gradient(top, #959595, #7b7b7b);
+ background-image: -o-linear-gradient(top, #959595, #7b7b7b);
+ background-image: linear-gradient(top, #959595, #7b7b7b);
+ padding: 4px 8px;
+ text-decoration: none;
+ text-shadow: none;
+ -webkit-font-smoothing: antialiased; }
+ .button:hover, .button:focus {
+ border: 1px solid #555555;
+ -webkit-box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
+ -moz-box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
+ box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
+ background-color: #a2a2a2;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a2a2a2), color-stop(100%, #7b7b7b));
+ background-image: -webkit-linear-gradient(top, #a2a2a2, #7b7b7b);
+ background-image: -moz-linear-gradient(top, #a2a2a2, #7b7b7b);
+ background-image: -ms-linear-gradient(top, #a2a2a2, #7b7b7b);
+ background-image: -o-linear-gradient(top, #a2a2a2, #7b7b7b);
+ background-image: linear-gradient(top, #a2a2a2, #7b7b7b); }
+
+.light-button, a.light-button {
+ border: 1px solid #ccc;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 white;
+ -moz-box-shadow: inset 0 1px 0 white;
+ box-shadow: inset 0 1px 0 white;
+ color: #666;
+ cursor: pointer;
+ font: normal 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ background-color: white;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #eeeeee));
+ background-image: -webkit-linear-gradient(top, white, #eeeeee);
+ background-image: -moz-linear-gradient(top, white, #eeeeee);
+ background-image: -ms-linear-gradient(top, white, #eeeeee);
+ background-image: -o-linear-gradient(top, white, #eeeeee);
+ background-image: linear-gradient(top, white, #eeeeee);
+ padding: 4px 8px;
+ text-decoration: none;
+ -webkit-font-smoothing: antialiased; }
+ .light-button:hover, .light-button:focus, a.light-button:hover, a.light-button:focus {
+ border: 1px solid #ccc;
+ background-color: white;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #e6e6e6));
+ background-image: -webkit-linear-gradient(top, white, #e6e6e6);
+ background-image: -moz-linear-gradient(top, white, #e6e6e6);
+ background-image: -ms-linear-gradient(top, white, #e6e6e6);
+ background-image: -o-linear-gradient(top, white, #e6e6e6);
+ background-image: linear-gradient(top, white, #e6e6e6);
+ text-decoration: none; }
+
+.action-link a {
+ color: #993333; }
+ .action-link a:hover {
+ color: #4d1919;
+ text-decoration: none; }
+
+.content, div.course-wrapper section.course-content, div.info-wrapper section.updates, div.book-wrapper section.book {
+ -webkit-box-shadow: inset 0 0 2px 3px #f3f3f3;
+ -moz-box-shadow: inset 0 0 2px 3px #f3f3f3;
+ box-shadow: inset 0 0 2px 3px #f3f3f3;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ padding: lh();
+ vertical-align: top;
+ width: 76.518%;
+ overflow: hidden; }
+ @media print {
+ .content, div.course-wrapper section.course-content, div.info-wrapper section.updates, div.book-wrapper section.book {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none; } }
+
+.sidebar, section.course-index, div.info-wrapper section.handouts, div.book-wrapper section.book-sidebar {
+ background: #e3e3e3;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ -ms-border-radius: 4px 0 0 4px;
+ -o-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+ border-right: 1px solid #d3d3d3;
+ -webkit-box-shadow: inset 0 0 0 1px #f6f6f6;
+ -moz-box-shadow: inset 0 0 0 1px #f6f6f6;
+ box-shadow: inset 0 0 0 1px #f6f6f6;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ position: relative;
+ text-shadow: 0 1px 0 #f1f1f1;
+ vertical-align: top;
+ width: 23.482%; }
+ .sidebar h1, section.course-index h1, div.info-wrapper section.handouts h1, div.book-wrapper section.book-sidebar h1, .sidebar h2, section.course-index h2, div.info-wrapper section.handouts h2, div.book-wrapper section.book-sidebar h2 {
+ font-size: 18px;
+ font-weight: bold;
+ letter-spacing: 0;
+ text-transform: none; }
+ .sidebar a, section.course-index a, div.info-wrapper section.handouts a, div.book-wrapper section.book-sidebar a {
+ border: none;
+ font-style: normal; }
+ .sidebar .bottom-border, section.course-index .bottom-border, div.info-wrapper section.handouts .bottom-border, div.book-wrapper section.book-sidebar .bottom-border, .sidebar div.info-wrapper section.handouts header, div.info-wrapper section.handouts .sidebar header, section.course-index div.info-wrapper section.handouts header, div.info-wrapper section.handouts section.course-index header, div.info-wrapper section.handouts header, div.book-wrapper section.book-sidebar div.info-wrapper section.handouts header, div.info-wrapper section.handouts div.book-wrapper section.book-sidebar header {
+ border-bottom: 1px solid #d3d3d3;
+ -webkit-box-shadow: 0 1px 0 #eeeeee;
+ -moz-box-shadow: 0 1px 0 #eeeeee;
+ box-shadow: 0 1px 0 #eeeeee; }
+ @media print {
+ .sidebar, section.course-index, div.info-wrapper section.handouts, div.book-wrapper section.book-sidebar {
+ display: none; } }
+ .sidebar h3, section.course-index h3, div.info-wrapper section.handouts h3, div.book-wrapper section.book-sidebar h3 {
+ background: none;
+ border: none;
+ color: #000;
+ font-weight: normal;
+ margin: 0;
+ overflow: hidden; }
+ .sidebar h3 a, section.course-index h3 a, div.info-wrapper section.handouts h3 a, div.book-wrapper section.book-sidebar h3 a {
+ color: #4d4d4d;
+ display: block;
+ font-size: 14px;
+ padding: 7px 7px 7px 30px;
+ text-decoration: none;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ .sidebar h3 span.ui-icon, section.course-index h3 span.ui-icon, div.info-wrapper section.handouts h3 span.ui-icon, div.book-wrapper section.book-sidebar h3 span.ui-icon {
+ background-image: url(../images/ui-icons_454545_256x240.png); }
+ .sidebar h3.active, section.course-index h3.active, div.info-wrapper section.handouts h3.active, div.book-wrapper section.book-sidebar h3.active, .sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion .sidebar h3.ui-accordion-header.ui-state-active, section.course-index div#accordion h3.ui-accordion-header.ui-state-active, div.info-wrapper section.handouts section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion div.info-wrapper section.handouts h3.ui-accordion-header.ui-state-active, div.book-wrapper section.book-sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion div.book-wrapper section.book-sidebar h3.ui-accordion-header.ui-state-active {
+ background: none;
+ background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ border-bottom: 1px solid #d3d3d3;
+ -webkit-box-shadow: inset 0 1px 0 0 #eeeeee;
+ -moz-box-shadow: inset 0 1px 0 0 #eeeeee;
+ box-shadow: inset 0 1px 0 0 #eeeeee;
+ color: #000;
+ font-weight: bold; }
+ .sidebar h3.active a, section.course-index h3.active a, div.info-wrapper section.handouts h3.active a, div.book-wrapper section.book-sidebar h3.active a, .sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion .sidebar h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, div.info-wrapper section.handouts section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion div.info-wrapper section.handouts h3.ui-accordion-header.ui-state-active a, div.book-wrapper section.book-sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion div.book-wrapper section.book-sidebar h3.ui-accordion-header.ui-state-active a {
+ color: #000; }
+ .sidebar header#open_close_accordion, section.course-index header#open_close_accordion, div.info-wrapper section.handouts header#open_close_accordion, div.book-wrapper section.book-sidebar header#open_close_accordion {
+ border-bottom: 1px solid #d3d3d3;
+ -webkit-box-shadow: 0 1px 0 #eeeeee;
+ -moz-box-shadow: 0 1px 0 #eeeeee;
+ box-shadow: 0 1px 0 #eeeeee;
+ padding: lh(0.5) lh();
+ position: relative; }
+ .sidebar header#open_close_accordion h2, section.course-index header#open_close_accordion h2, div.info-wrapper section.handouts header#open_close_accordion h2, div.book-wrapper section.book-sidebar header#open_close_accordion h2 {
+ margin: 0;
+ padding-right: 20px; }
+ .sidebar header#open_close_accordion a, section.course-index header#open_close_accordion a, div.info-wrapper section.handouts header#open_close_accordion a, div.book-wrapper section.book-sidebar header#open_close_accordion a {
+ background: #eeeeee url("../images/slide-left-icon.png") center center no-repeat;
+ border: 1px solid #D3D3D3;
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ -ms-border-radius: 3px 0 0 3px;
+ -o-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+ height: 16px;
+ padding: 8px;
+ position: absolute;
+ right: -1px;
+ text-indent: -9999px;
+ top: 6px;
+ width: 16px; }
+ .sidebar header#open_close_accordion a:hover, section.course-index header#open_close_accordion a:hover, div.info-wrapper section.handouts header#open_close_accordion a:hover, div.book-wrapper section.book-sidebar header#open_close_accordion a:hover {
+ background-color: white; }
+ .sidebar a.button, section.course-index a.button, div.info-wrapper section.handouts a.button, div.book-wrapper section.book-sidebar a.button {
+ text-decoration: none; }
+
+.topbar, nav.sequence-nav, div.book-wrapper section.book nav {
+ background: #f6efd4;
+ border-bottom: 1px solid #eddfaa;
+ border-top: 1px solid #fff;
+ font-size: 12px;
+ line-height: 46px;
+ text-shadow: 0 1px 0 #fff; }
+ @media print {
+ .topbar, nav.sequence-nav, div.book-wrapper section.book nav {
+ display: none; } }
+ .topbar a, nav.sequence-nav a, div.book-wrapper section.book nav a {
+ line-height: 46px;
+ border-bottom: 0;
+ color: #292309; }
+ .topbar a:hover, nav.sequence-nav a:hover, div.book-wrapper section.book nav a:hover {
+ color: #7e691a;
+ text-decoration: none; }
+ .topbar a.block-link, nav.sequence-nav a.block-link, div.book-wrapper section.book nav a.block-link, .topbar nav.sequence-nav ol a, nav.sequence-nav ol .topbar a, nav.sequence-nav ol a, div.book-wrapper section.book nav.sequence-nav ol a, .topbar div.book-wrapper section.book nav a, div.book-wrapper section.book nav .topbar a, div.book-wrapper section.book nav.sequence-nav a, div.book-wrapper section.book nav a {
+ border-left: 1px solid #e4d080;
+ -webkit-box-shadow: inset 1px 0 0 #faf7e9;
+ -moz-box-shadow: inset 1px 0 0 #faf7e9;
+ box-shadow: inset 1px 0 0 #faf7e9;
+ display: block;
+ text-transform: uppercase; }
+ .topbar a.block-link:hover, nav.sequence-nav a.block-link:hover, div.book-wrapper section.book nav a.block-link:hover, .topbar nav.sequence-nav ol a:hover, nav.sequence-nav ol .topbar a:hover, nav.sequence-nav ol a:hover, div.book-wrapper section.book nav.sequence-nav ol a:hover, .topbar div.book-wrapper section.book nav a:hover, div.book-wrapper section.book nav .topbar a:hover, div.book-wrapper section.book nav.sequence-nav a:hover, div.book-wrapper section.book nav a:hover {
+ background: none; }
+
+.tran, section.course-index, div.book-wrapper section.book-sidebar {
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ -ms-transition-duration: 0.2s;
+ -o-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+
+p.ie-warning {
+ background: yellow;
+ display: block !important;
+ line-height: 1.3em;
+ margin-bottom: 0;
+ padding: lh();
+ text-align: left; }
+
+html {
+ height: 100%;
+ max-height: 100%; }
+
+body.courseware {
+ height: 100%;
+ max-height: 100%; }
+ body.courseware .container {
+ margin-bottom: 40px;
+ margin-top: 20px; }
+ body.courseware footer.fixed-bottom {
+ Position: static; }
+
+div.course-wrapper ul, div.course-wrapper ol {
+ list-style: none; }
+div.course-wrapper section.course-content {
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ -ms-border-radius: 0 4px 4px 0;
+ -o-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0; }
+ div.course-wrapper section.course-content h1 {
+ margin: 0 0 22.652px; }
+ div.course-wrapper section.course-content p {
+ margin-bottom: 22.652px; }
+ div.course-wrapper section.course-content p:empty {
+ display: none;
+ margin-bottom: 0; }
+ div.course-wrapper section.course-content ul li {
+ margin-bottom: 11.326px; }
+ div.course-wrapper section.course-content .problem-set, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content, div.course-wrapper section.course-content ol.vert-mod > li, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content {
+ position: relative; }
+ div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
+ margin-top: 0;
+ margin-bottom: 15px;
+ width: 20.109%;
+ padding-right: 2.717%;
+ border-right: 1px dashed #ddd;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ vertical-align: top; }
+ div.course-wrapper section.course-content .problem-set h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, div.course-wrapper section.course-content div#seq_content h2.problem-header section.staff, div.course-wrapper section.course-content ol.vert-mod > li h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, div.course-wrapper section.course-content div#seq_content h2.problem-header section.staff {
+ margin-top: 30px;
+ font-size: 80%; }
+ @media screen and (max-width:1120px) {
+ div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
+ display: block;
+ width: auto;
+ border-right: 0; } }
+ @media print {
+ div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
+ display: block;
+ width: auto;
+ border-right: 0; } }
+ div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
+ display: table-cell;
+ width: 77.174%;
+ padding-left: 2.717%; }
+ @media screen and (max-width:1120px) {
+ div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
+ display: block;
+ width: auto;
+ padding: 0; } }
+ @media print {
+ div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
+ display: block;
+ width: auto;
+ padding: 0; }
+ div.course-wrapper section.course-content .problem-set section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, div.course-wrapper section.course-content div#seq_content section.problem canvas, div.course-wrapper section.course-content ol.vert-mod > li section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, div.course-wrapper section.course-content div#seq_content section.problem canvas, div.course-wrapper section.course-content .problem-set section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, div.course-wrapper section.course-content div#seq_content section.problem img, div.course-wrapper section.course-content ol.vert-mod > li section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, div.course-wrapper section.course-content div#seq_content section.problem img {
+ page-break-inside: avoid; } }
+ div.course-wrapper section.course-content .problem-set section.problem span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem span.unanswered, div.course-wrapper section.course-content div#seq_content section.problem span.unanswered, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem span.unanswered, div.course-wrapper section.course-content div#seq_content section.problem span.unanswered, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-bullet, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-bullet, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-bullet, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-bullet {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/unanswered-icon.png") center center no-repeat;
+ height: 14px;
+ position: relative;
+ top: 4px;
+ width: 14px; }
+ div.course-wrapper section.course-content .problem-set section.problem span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem span.correct, div.course-wrapper section.course-content div#seq_content section.problem span.correct, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem span.correct, div.course-wrapper section.course-content div#seq_content section.problem span.correct, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-check, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-check, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-check, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-check {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/correct-icon.png") center center no-repeat;
+ height: 20px;
+ position: relative;
+ top: 6px;
+ width: 25px; }
+ div.course-wrapper section.course-content .problem-set section.problem span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem span.incorrect, div.course-wrapper section.course-content div#seq_content section.problem span.incorrect, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem span.incorrect, div.course-wrapper section.course-content div#seq_content section.problem span.incorrect, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-close, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-close, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-close, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-close {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/incorrect-icon.png") center center no-repeat;
+ height: 20px;
+ width: 20px;
+ position: relative;
+ top: 6px; }
+ div.course-wrapper section.course-content .problem-set div > span, div.course-wrapper section.course-content section.problems-wrapper div > span, div.course-wrapper section.course-content div#seq_content div > span, div.course-wrapper section.course-content ol.vert-mod > li div > span, div.course-wrapper section.course-content section.problems-wrapper div > span, div.course-wrapper section.course-content div#seq_content div > span {
+ display: block;
+ margin-bottom: 11.326px; }
+ div.course-wrapper section.course-content .problem-set div > span[answer], div.course-wrapper section.course-content section.problems-wrapper div > span[answer], div.course-wrapper section.course-content div#seq_content div > span[answer], div.course-wrapper section.course-content ol.vert-mod > li div > span[answer], div.course-wrapper section.course-content section.problems-wrapper div > span[answer], div.course-wrapper section.course-content div#seq_content div > span[answer] {
+ border-top: 1px solid #ededed;
+ border-bottom: 1px solid #ededed;
+ background: #f3f3f3;
+ margin: 0 -22.652px;
+ padding: 11.326px 22.652px; }
+ div.course-wrapper section.course-content .problem-set input[type="text"], div.course-wrapper section.course-content section.problems-wrapper input[type="text"], div.course-wrapper section.course-content div#seq_content input[type="text"], div.course-wrapper section.course-content ol.vert-mod > li input[type="text"], div.course-wrapper section.course-content section.problems-wrapper input[type="text"], div.course-wrapper section.course-content div#seq_content input[type="text"] {
+ display: inline-block;
+ width: 50%; }
+ div.course-wrapper section.course-content .problem-set center, div.course-wrapper section.course-content section.problems-wrapper center, div.course-wrapper section.course-content div#seq_content center, div.course-wrapper section.course-content ol.vert-mod > li center, div.course-wrapper section.course-content section.problems-wrapper center, div.course-wrapper section.course-content div#seq_content center {
+ display: block;
+ margin: 22.652px 0;
+ border: 1px solid #ccc;
+ padding: 22.652px; }
+ div.course-wrapper section.course-content .problem-set section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, div.course-wrapper section.course-content div#seq_content section.action, div.course-wrapper section.course-content ol.vert-mod > li section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, div.course-wrapper section.course-content div#seq_content section.action {
+ margin-top: 22.652px; }
+ div.course-wrapper section.course-content .problem-set section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], div.course-wrapper section.course-content div#seq_content section.action input[type="button"], div.course-wrapper section.course-content ol.vert-mod > li section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], div.course-wrapper section.course-content div#seq_content section.action input[type="button"] {
+ padding: 9.061px 22.652px;
+ text-shadow: 0 -1px 0 #666666; }
+ div.course-wrapper section.course-content section.problems-wrapper {
+ display: table;
+ width: 100%; }
+ @media screen and (max-width:1120px) {
+ div.course-wrapper section.course-content section.problems-wrapper {
+ display: block;
+ width: auto; } }
+ div.course-wrapper section.course-content div#seq_content h1 {
+ background: none;
+ margin-bottom: 22.652px;
+ padding-bottom: 0;
+ border-bottom: none; }
+ div.course-wrapper section.course-content ol.vert-mod > li {
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 15px;
+ padding: 0 0 15px; }
+ div.course-wrapper section.course-content ol.vert-mod > li header {
+ -webkit-border-radius: 0 4px 0 0;
+ -moz-border-radius: 0 4px 0 0;
+ -ms-border-radius: 0 4px 0 0;
+ -o-border-radius: 0 4px 0 0;
+ border-radius: 0 4px 0 0;
+ margin-bottom: -16px; }
+ div.course-wrapper section.course-content ol.vert-mod > li header h1 {
+ margin: 0; }
+ div.course-wrapper section.course-content ol.vert-mod > li header h2 {
+ float: right;
+ margin-right: 0;
+ margin-top: 8px;
+ text-align: right;
+ padding-right: 0;
+ border-right: 0; }
+ div.course-wrapper section.course-content ol.vert-mod > li:last-child {
+ border-bottom: none;
+ margin-bottom: 0;
+ padding-bottom: 0; }
+ div.course-wrapper section.course-content ol.vert-mod > li .histogram {
+ width: 200px;
+ height: 150px; }
+ div.course-wrapper section.course-content ol.vert-mod > li ul {
+ list-style: disc outside none;
+ padding-left: 1em; }
+ div.course-wrapper section.course-content ol.vert-mod > li nav.sequence-bottom ul {
+ list-style: none;
+ padding: 0; }
+ div.course-wrapper section.course-content section.tutorials h2 {
+ margin-bottom: 22.652px; }
+ div.course-wrapper section.course-content section.tutorials ul {
+ margin: 0;
+ zoom: 1; }
+ div.course-wrapper section.course-content section.tutorials ul:before, div.course-wrapper section.course-content section.tutorials ul:after {
+ content: "";
+ display: table; }
+ div.course-wrapper section.course-content section.tutorials ul:after {
+ clear: both; }
+ div.course-wrapper section.course-content section.tutorials ul li {
+ width: 31.522%;
+ float: left;
+ margin-right: 2.717%;
+ margin-bottom: 22.652px; }
+ div.course-wrapper section.course-content section.tutorials ul li:nth-child(3n) {
+ margin-right: 0; }
+ div.course-wrapper section.course-content section.tutorials ul li:nth-child(3n+1) {
+ clear: both; }
+ div.course-wrapper section.course-content section.tutorials ul li a {
+ font-weight: bold; }
+ div.course-wrapper section.course-content div.staff_info {
+ zoom: 1;
+ white-space: pre-wrap;
+ border-top: 1px solid #ccc;
+ padding-top: 22.652px;
+ margin-top: 22.652px;
+ line-height: 22.652px;
+ font-family: Consolas, "Lucida Console", Monaco, "Courier New", Courier, monospace; }
+ div.course-wrapper section.course-content div.staff_info:before, div.course-wrapper section.course-content div.staff_info:after {
+ content: "";
+ display: table; }
+ div.course-wrapper section.course-content div.staff_info:after {
+ clear: both; }
+ div.course-wrapper section.course-content div.ui-slider {
+ border: 1px solid #aaa;
+ background: #ddd;
+ -webkit-box-shadow: inset 0 1px 0 #eeeeee;
+ -moz-box-shadow: inset 0 1px 0 #eeeeee;
+ box-shadow: inset 0 1px 0 #eeeeee;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0; }
+ div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle {
+ -webkit-box-shadow: inset 0 1px 0 #bf4040;
+ -moz-box-shadow: inset 0 1px 0 #bf4040;
+ box-shadow: inset 0 1px 0 #bf4040;
+ background: #993333 url(../images/slider-bars.png) center center no-repeat;
+ border: 1px solid #4d1919;
+ cursor: pointer; }
+ div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle:hover, div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle:focus {
+ background-color: #bf4040;
+ outline: none; }
+ div.course-wrapper section.course-content div.ui-tabs {
+ border: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ margin: 0;
+ padding: 0; }
+ div.course-wrapper section.course-content div.ui-tabs .ui-tabs-nav {
+ background: none;
+ border: 0;
+ margin-bottom: 11.326px; }
+ div.course-wrapper section.course-content div.ui-tabs .ui-tabs-panel {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ padding: 0; }
+div.course-wrapper.closed section.course-index {
+ width: 3.077%;
+ overflow: hidden; }
+ div.course-wrapper.closed section.course-index header#open_close_accordion {
+ padding: 0;
+ min-height: 47px; }
+ div.course-wrapper.closed section.course-index header#open_close_accordion a {
+ background-image: url("../images/slide-right-icon.png"); }
+ div.course-wrapper.closed section.course-index header#open_close_accordion h2 {
+ visibility: hidden;
+ width: 10px; }
+ div.course-wrapper.closed section.course-index div#accordion {
+ visibility: hidden;
+ width: 10px;
+ padding: 0; }
+ div.course-wrapper.closed section.course-index div#accordion nav {
+ white-space: pre;
+ overflow: hidden; }
+ div.course-wrapper.closed section.course-index div#accordion nav ul {
+ overflow: hidden;
+ white-space: nowrap; }
+div.course-wrapper.closed section.course-content {
+ width: 97.773%; }
+
+nav.sequence-nav {
+ border-bottom: 1px solid #e4d080;
+ margin-bottom: 22.652px;
+ position: relative;
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -ms-border-top-right-radius: 4px;
+ -o-border-top-right-radius: 4px;
+ border-top-right-radius: 4px; }
+ nav.sequence-nav ol {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table;
+ height: 100%;
+ padding-right: 8.696%;
+ width: 100%; }
+ nav.sequence-nav ol li {
+ border-left: 1px solid #e4d080;
+ display: table-cell;
+ min-width: 20px; }
+ nav.sequence-nav ol li:first-child {
+ border-left: none; }
+ nav.sequence-nav ol li .inactive, nav.sequence-nav ol li a.seq_video_inactive, nav.sequence-nav ol li a.seq_other_inactive, nav.sequence-nav ol li a.seq_vertical_inactive, nav.sequence-nav ol li a.seq_problem_inactive {
+ background-repeat: no-repeat; }
+ nav.sequence-nav ol li .inactive:hover, nav.sequence-nav ol li a.seq_video_inactive:hover, nav.sequence-nav ol li a.seq_other_inactive:hover, nav.sequence-nav ol li a.seq_vertical_inactive:hover, nav.sequence-nav ol li a.seq_problem_inactive:hover {
+ background-color: #f9f4e1; }
+ nav.sequence-nav ol li .visited, nav.sequence-nav ol li a.seq_video_visited, nav.sequence-nav ol li a.seq_other_visited, nav.sequence-nav ol li a.seq_vertical_visited, nav.sequence-nav ol li a.seq_problem_visited {
+ background-color: #DCCDA2;
+ background-repeat: no-repeat;
+ -webkit-box-shadow: inset 0 0 3px #ceb97d;
+ -moz-box-shadow: inset 0 0 3px #ceb97d;
+ box-shadow: inset 0 0 3px #ceb97d; }
+ nav.sequence-nav ol li .visited:hover, nav.sequence-nav ol li a.seq_video_visited:hover, nav.sequence-nav ol li a.seq_other_visited:hover, nav.sequence-nav ol li a.seq_vertical_visited:hover, nav.sequence-nav ol li a.seq_problem_visited:hover {
+ background-color: #f6efd4;
+ background-position: center center; }
+ nav.sequence-nav ol li .active, nav.sequence-nav ol li a.seq_video_active, nav.sequence-nav ol li a.seq_other_active, nav.sequence-nav ol li a.seq_vertical_active, nav.sequence-nav ol li a.seq_problem_active, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active {
+ background-color: #fff;
+ background-repeat: no-repeat;
+ -webkit-box-shadow: 0 1px 0 white;
+ -moz-box-shadow: 0 1px 0 white;
+ box-shadow: 0 1px 0 white; }
+ nav.sequence-nav ol li .active:hover, nav.sequence-nav ol li a.seq_video_active:hover, nav.sequence-nav ol li a.seq_other_active:hover, nav.sequence-nav ol li a.seq_vertical_active:hover, nav.sequence-nav ol li a.seq_problem_active:hover, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active:hover, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active:hover {
+ background-color: #fff;
+ background-position: center; }
+ nav.sequence-nav ol li a {
+ background-position: center center;
+ border: none;
+ cursor: pointer;
+ display: block;
+ height: 17px;
+ padding: 15px 0 14px;
+ position: relative;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.4s;
+ -moz-transition-duration: 0.4s;
+ -ms-transition-duration: 0.4s;
+ -o-transition-duration: 0.4s;
+ transition-duration: 0.4s;
+ -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 100%; }
+ nav.sequence-nav ol li a.progress, nav.sequence-nav ol li a.progress-none, nav.sequence-nav ol li a.progress-some, nav.sequence-nav ol li a.progress-done {
+ border-bottom-style: solid;
+ border-bottom-width: 4px; }
+ nav.sequence-nav ol li a.progress-none {
+ border-bottom-color: red; }
+ nav.sequence-nav ol li a.progress-some {
+ border-bottom-color: yellow; }
+ nav.sequence-nav ol li a.progress-done {
+ border-bottom-color: green; }
+ nav.sequence-nav ol li a.seq_video_inactive {
+ background-image: url("../images/sequence-nav/video-icon-normal.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_video_visited {
+ background-image: url("../images/sequence-nav/video-icon-visited.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_video_active {
+ background-image: url("../images/sequence-nav/video-icon-current.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_other_inactive {
+ background-image: url("../images/sequence-nav/document-icon-normal.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_other_visited {
+ background-image: url("../images/sequence-nav/document-icon-visited.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_other_active {
+ background-image: url("../images/sequence-nav/document-icon-current.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_vertical_inactive, nav.sequence-nav ol li a.seq_problem_inactive {
+ background-image: url("../images/sequence-nav/list-icon-normal.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_vertical_visited, nav.sequence-nav ol li a.seq_problem_visited {
+ background-image: url("../images/sequence-nav/list-icon-visited.png");
+ background-position: center; }
+ nav.sequence-nav ol li a.seq_vertical_active, nav.sequence-nav ol li a.seq_problem_active {
+ background-image: url("../images/sequence-nav/list-icon-current.png");
+ background-position: center; }
+ nav.sequence-nav ol li a p {
+ background: #333;
+ color: #fff;
+ display: none;
+ line-height: 22.652px;
+ left: 0px;
+ opacity: 0;
+ padding: 6px;
+ position: absolute;
+ top: 48px;
+ text-shadow: 0 -1px 0 black;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.1s;
+ -moz-transition-duration: 0.1s;
+ -ms-transition-duration: 0.1s;
+ -o-transition-duration: 0.1s;
+ transition-duration: 0.1s;
+ -webkit-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
+ -moz-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
+ -ms-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
+ -o-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
+ transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ white-space: pre;
+ z-index: 99; }
+ nav.sequence-nav ol li a p:empty {
+ background: none; }
+ nav.sequence-nav ol li a p:empty::after {
+ display: none; }
+ nav.sequence-nav ol li a p::after {
+ background: #333;
+ content: " ";
+ display: block;
+ height: 10px;
+ left: 18px;
+ position: absolute;
+ top: -5px;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+ width: 10px; }
+ nav.sequence-nav ol li a:hover p {
+ display: block;
+ margin-top: 4px;
+ opacity: 1; }
+ nav.sequence-nav ul {
+ list-style: none;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 8.696%; }
+ nav.sequence-nav ul li {
+ float: left;
+ width: 50%; }
+ nav.sequence-nav ul li.prev a, nav.sequence-nav ul li.next a {
+ background-color: #f2e7bf;
+ background-position: center center;
+ background-repeat: no-repeat;
+ border-left: 1px solid #e4d080;
+ -webkit-box-shadow: inset 1px 0 0 #faf7e9;
+ -moz-box-shadow: inset 1px 0 0 #faf7e9;
+ box-shadow: inset 1px 0 0 #faf7e9;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ text-indent: -9999px;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ -ms-transition-duration: 0.2s;
+ -o-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ nav.sequence-nav ul li.prev a:hover, nav.sequence-nav ul li.next a:hover {
+ opacity: .5; }
+ nav.sequence-nav ul li.prev a.disabled, nav.sequence-nav ul li.next a.disabled {
+ cursor: normal;
+ opacity: .4; }
+ nav.sequence-nav ul li.prev a {
+ background-image: url("../images/sequence-nav/previous-icon.png"); }
+ nav.sequence-nav ul li.prev a:hover {
+ background-color: #f6efd4; }
+ nav.sequence-nav ul li.next a {
+ background-image: url("../images/sequence-nav/next-icon.png"); }
+ nav.sequence-nav ul li.next a:hover {
+ background-color: #f6efd4; }
+ body.touch-based-device nav.sequence-nav ol li a:hover p {
+ display: none; }
+
+section.course-content {
+ position: relative; }
+ section.course-content ol.vert-mod nav.sequence-nav {
+ margin-top: -15px;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0; }
+ section.course-content nav.sequence-bottom {
+ margin: 45.304px 0 0;
+ text-align: center; }
+ section.course-content nav.sequence-bottom ul {
+ background-color: #f2e7bf;
+ background-color: #f2e7bf;
+ border: 1px solid #e4d080;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 0 0 1px #faf7e9;
+ -moz-box-shadow: inset 0 0 0 1px #faf7e9;
+ box-shadow: inset 0 0 0 1px #faf7e9;
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto; }
+ section.course-content nav.sequence-bottom ul li {
+ float: left; }
+ section.course-content nav.sequence-bottom ul li.prev, section.course-content nav.sequence-bottom ul li.next {
+ margin-bottom: 0; }
+ section.course-content nav.sequence-bottom ul li.prev a, section.course-content nav.sequence-bottom ul li.next a {
+ background-position: center center;
+ background-repeat: no-repeat;
+ border-bottom: none;
+ display: block;
+ padding: 11.326px 4px;
+ text-indent: -9999px;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ -ms-transition-duration: 0.2s;
+ -o-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 45px; }
+ section.course-content nav.sequence-bottom ul li.prev a:hover, section.course-content nav.sequence-bottom ul li.next a:hover {
+ background-color: #f6efd4;
+ color: #7e691a;
+ opacity: .5;
+ text-decoration: none; }
+ section.course-content nav.sequence-bottom ul li.prev a.disabled, section.course-content nav.sequence-bottom ul li.next a.disabled {
+ background-color: #fffffe;
+ opacity: .4; }
+ section.course-content nav.sequence-bottom ul li.prev a {
+ background-image: url("../images/sequence-nav/previous-icon.png");
+ border-right: 1px solid #e4d080; }
+ section.course-content nav.sequence-bottom ul li.prev a:hover {
+ background-color: none; }
+ section.course-content nav.sequence-bottom ul li.next a {
+ background-image: url("../images/sequence-nav/next-icon.png"); }
+ section.course-content nav.sequence-bottom ul li.next a:hover {
+ background-color: none; }
+
+section.course-index header {
+ max-height: 47px; }
+ section.course-index header h2 {
+ white-space: nowrap; }
+section.course-index div#accordion h3 {
+ -webkit-box-shadow: inset 0 1px 0 0 #eeeeee;
+ -moz-box-shadow: inset 0 1px 0 0 #eeeeee;
+ box-shadow: inset 0 1px 0 0 #eeeeee;
+ border-top: 1px solid #d3d3d3;
+ overflow: hidden;
+ margin: 0; }
+ section.course-index div#accordion h3:first-child {
+ border: none; }
+ section.course-index div#accordion h3:hover {
+ background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1); }
+ section.course-index div#accordion h3.ui-accordion-header {
+ color: #000; }
+ section.course-index div#accordion h3.ui-accordion-header a {
+ font-size: 14px;
+ color: #4d4d4d; }
+ section.course-index div#accordion h3.ui-accordion-header.ui-state-active {
+ background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1);
+ border-bottom: 1px solid #d3d3d3; }
+section.course-index div#accordion ul.ui-accordion-content {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: inset -1px 0 0 #e6e6e6;
+ -moz-box-shadow: inset -1px 0 0 #e6e6e6;
+ box-shadow: inset -1px 0 0 #e6e6e6;
+ background: #dadada;
+ border: none;
+ font-size: 12px;
+ margin: 0;
+ padding: 1em 1.5em; }
+ section.course-index div#accordion ul.ui-accordion-content li {
+ margin-bottom: 11.326px; }
+ section.course-index div#accordion ul.ui-accordion-content li a {
+ border: 1px solid transparent;
+ background: transparent;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -ms-border-radius: 4px;
+ -o-border-radius: 4px;
+ border-radius: 4px;
+ position: relative;
+ padding: 5px 36px 5px 10px;
+ text-decoration: none;
+ display: block;
+ color: #666; }
+ section.course-index div#accordion ul.ui-accordion-content li a p {
+ font-weight: bold;
+ margin-bottom: 0; }
+ section.course-index div#accordion ul.ui-accordion-content li a p span.subtitle {
+ color: #666;
+ font-weight: normal;
+ display: block; }
+ section.course-index div#accordion ul.ui-accordion-content li a:after {
+ background: transparent;
+ border-top: 1px solid #b4b4b4;
+ border-right: 1px solid #b4b4b4;
+ content: "";
+ display: block;
+ height: 12px;
+ margin-top: -6px;
+ opacity: 0;
+ position: absolute;
+ top: 50%;
+ right: 30px;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+ width: 12px; }
+ section.course-index div#accordion ul.ui-accordion-content li a:hover {
+ background-image: -webkit-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
+ background-image: -moz-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
+ background-image: -ms-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
+ background-image: -o-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
+ background-image: linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
+ border-color: #c8c8c8; }
+ section.course-index div#accordion ul.ui-accordion-content li a:hover:after {
+ opacity: 1;
+ right: 15px;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ -ms-transition-duration: 0.2s;
+ -o-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ -webkit-transition-timing-function: linear;
+ -moz-transition-timing-function: linear;
+ -ms-transition-timing-function: linear;
+ -o-transition-timing-function: linear;
+ transition-timing-function: linear;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ section.course-index div#accordion ul.ui-accordion-content li a:hover > a p {
+ color: #333; }
+ section.course-index div#accordion ul.ui-accordion-content li a:active {
+ -webkit-box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1); }
+ section.course-index div#accordion ul.ui-accordion-content li a:active:after {
+ opacity: 1;
+ right: 15px; }
+ section.course-index div#accordion ul.ui-accordion-content li.active {
+ font-weight: bold; }
+ section.course-index div#accordion ul.ui-accordion-content li.active > a {
+ background: #f0f0f0;
+ background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
+ background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
+ background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
+ background-image: -o-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
+ background-image: linear-gradient(-90deg, #f5f5f5, #e6e6e6);
+ border-color: #c8c8c8; }
+ section.course-index div#accordion ul.ui-accordion-content li.active > a:after {
+ opacity: 1;
+ right: 15px; }
+ section.course-index div#accordion ul.ui-accordion-content li.active > a p {
+ color: #333; }
+ section.course-index div#accordion ul.ui-accordion-content li.active span.subtitle {
+ font-weight: normal; }
+
+@-moz-document url-prefix() {
+ a.add-fullscreen {
+ display: none !important; } }
+
+section.course-content .dullify, section.course-content div.video article.video-wrapper section.video-controls ul.vcr, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls {
+ opacity: .4;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ section.course-content .dullify:hover, section.course-content div.video article.video-wrapper section.video-controls ul.vcr:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls:hover {
+ opacity: 1; }
+section.course-content div.video {
+ zoom: 1;
+ background: #f3f3f3;
+ border-bottom: 1px solid #e1e1e1;
+ border-top: 1px solid #e1e1e1;
+ display: block;
+ margin: 0 -22.652px;
+ padding: 6px 22.652px; }
+ section.course-content div.video:before, section.course-content div.video:after {
+ content: "";
+ display: table; }
+ section.course-content div.video:after {
+ clear: both; }
+ section.course-content div.video article.video-wrapper {
+ float: left;
+ margin-right: 2.717%;
+ width: 65.761%; }
+ section.course-content div.video article.video-wrapper section.video-player {
+ height: 0;
+ overflow: hidden;
+ padding-bottom: 56.25%;
+ padding-top: 30px;
+ position: relative; }
+ section.course-content div.video article.video-wrapper section.video-player object, section.course-content div.video article.video-wrapper section.video-player iframe {
+ border: none;
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%; }
+ section.course-content div.video article.video-wrapper section.video-controls {
+ background: #333;
+ border: 1px solid #000;
+ border-top: 0;
+ color: #ccc;
+ position: relative; }
+ section.course-content div.video article.video-wrapper section.video-controls:hover ul, section.course-content div.video article.video-wrapper section.video-controls:hover div {
+ opacity: 1; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider {
+ background: #c2c2c2;
+ border: none;
+ border-bottom: 1px solid #000;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ border-top: 1px solid #000;
+ -webkit-box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
+ -moz-box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
+ box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
+ height: 7px;
+ -webkit-transition-property: height, 2s, ease-in-out;
+ -moz-transition-property: height, 2s, ease-in-out;
+ -ms-transition-property: height, 2s, ease-in-out;
+ -o-transition-property: height, 2s, ease-in-out;
+ transition-property: height, 2s, ease-in-out;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider div.ui-widget-header {
+ background: #777;
+ -webkit-box-shadow: inset 0 1px 0 #999999;
+ -moz-box-shadow: inset 0 1px 0 #999999;
+ box-shadow: inset 0 1px 0 #999999; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider .ui-tooltip.qtip .ui-tooltip-content {
+ background: #993333;
+ border: 1px solid #4d1919;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ -ms-border-radius: 2px;
+ -o-border-radius: 2px;
+ border-radius: 2px;
+ -webkit-box-shadow: inset 0 1px 0 #bf4040;
+ -moz-box-shadow: inset 0 1px 0 #bf4040;
+ box-shadow: inset 0 1px 0 #bf4040;
+ color: #fff;
+ font: bold 12px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ margin-bottom: 6px;
+ margin-right: 0;
+ overflow: visible;
+ padding: 4px;
+ text-align: center;
+ text-shadow: 0 -1px 0 #732626;
+ -webkit-font-smoothing: antialiased; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider .ui-tooltip.qtip .ui-tooltip-content::after {
+ background: #993333;
+ border-bottom: 1px solid #4d1919;
+ border-right: 1px solid #4d1919;
+ bottom: -5px;
+ content: " ";
+ display: block;
+ height: 7px;
+ left: 50%;
+ margin-left: -3px;
+ position: absolute;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+ width: 7px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle {
+ background: #993333 url(../images/slider-handle.png) center center no-repeat;
+ -webkit-background-size: 50%;
+ -moz-background-size: 50%;
+ -ms-background-size: 50%;
+ -o-background-size: 50%;
+ background-size: 50%;
+ border: 1px solid #4d1919;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ -ms-border-radius: 15px;
+ -o-border-radius: 15px;
+ border-radius: 15px;
+ -webkit-box-shadow: inset 0 1px 0 #bf4040;
+ -moz-box-shadow: inset 0 1px 0 #bf4040;
+ box-shadow: inset 0 1px 0 #bf4040;
+ cursor: pointer;
+ height: 15px;
+ margin-left: -7px;
+ top: -4px;
+ -webkit-transition-property: height, 2s, ease-in-out;
+ -moz-transition-property: height, 2s, ease-in-out;
+ -ms-transition-property: height, 2s, ease-in-out;
+ -o-transition-property: height, 2s, ease-in-out;
+ transition-property: height, 2s, ease-in-out;
+ -webkit-transition-duration: width, 2s, ease-in-out;
+ -moz-transition-duration: width, 2s, ease-in-out;
+ -ms-transition-duration: width, 2s, ease-in-out;
+ -o-transition-duration: width, 2s, ease-in-out;
+ transition-duration: width, 2s, ease-in-out;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 15px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle:focus, section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle:hover {
+ background-color: #bf4040;
+ outline: none; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr {
+ float: left;
+ list-style: none;
+ margin-right: 22.652px;
+ padding: 0; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li {
+ float: left;
+ margin-bottom: 0; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a {
+ border-bottom: none;
+ border-right: 1px solid #000;
+ -webkit-box-shadow: 1px 0 0 #555555;
+ -moz-box-shadow: 1px 0 0 #555555;
+ box-shadow: 1px 0 0 #555555;
+ cursor: pointer;
+ display: block;
+ line-height: 46px;
+ padding: 0 16.989px;
+ text-indent: -9999px;
+ -webkit-transition-property: background-color;
+ -moz-transition-property: background-color;
+ -ms-transition-property: background-color;
+ -o-transition-property: background-color;
+ transition-property: background-color;
+ -webkit-transition-duration: opacity;
+ -moz-transition-duration: opacity;
+ -ms-transition-duration: opacity;
+ -o-transition-duration: opacity;
+ transition-duration: opacity;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 14px;
+ background: url("../images/vcr.png") 15px 15px no-repeat; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a:empty {
+ height: 46px;
+ background: url("../images/vcr.png") 15px 15px no-repeat; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.play {
+ background-position: 17px -114px; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.play:hover {
+ background-color: #444; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.pause {
+ background-position: 16px -50px; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.pause:hover {
+ background-color: #444; }
+ section.course-content div.video article.video-wrapper section.video-controls ul.vcr li div.vidtime {
+ padding-left: 16.989px;
+ font-weight: bold;
+ line-height: 46px;
+ padding-left: 16.989px;
+ -webkit-font-smoothing: antialiased; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls {
+ float: right; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds {
+ float: left;
+ position: relative; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds.open > a {
+ background: url("../images/open-arrow.png") 10px center no-repeat; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds.open ol.video_speeds {
+ display: block;
+ opacity: 1; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a {
+ background: url("../images/closed-arrow.png") 10px center no-repeat;
+ border-left: 1px solid #000;
+ border-right: 1px solid #000;
+ -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ zoom: 1;
+ color: #fff;
+ cursor: pointer;
+ display: block;
+ line-height: 46px;
+ margin-right: 0;
+ padding-left: 15px;
+ position: relative;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ -webkit-font-smoothing: antialiased;
+ width: 110px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:before, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:after {
+ content: "";
+ display: table; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:after {
+ clear: both; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a h3 {
+ color: #999;
+ float: left;
+ font-size: 12px;
+ font-weight: normal;
+ letter-spacing: 1px;
+ padding: 0 5.663px 0 11.326px;
+ text-transform: uppercase; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a p.active {
+ float: left;
+ font-weight: bold;
+ margin-bottom: 0;
+ padding: 0 11.326px 0 0; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:active, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:focus {
+ opacity: 1;
+ background-color: #444; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds {
+ -webkit-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ -moz-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ background-color: #444;
+ border: 1px solid #000;
+ bottom: 46px;
+ display: none;
+ opacity: 0;
+ position: absolute;
+ width: 125px;
+ z-index: 10; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li {
+ -webkit-box-shadow: 0 1px 0 #555555;
+ -moz-box-shadow: 0 1px 0 #555555;
+ box-shadow: 0 1px 0 #555555;
+ border-bottom: 1px solid #000;
+ color: #fff;
+ cursor: pointer; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li a {
+ border: 0;
+ color: #fff;
+ display: block;
+ padding: 11.326px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li a:hover {
+ background-color: #666;
+ color: #aaa; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li.active {
+ font-weight: bold; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li:last-child {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ border-bottom: 0;
+ margin-top: 0; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume {
+ float: left;
+ position: relative; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume.open .volume-slider-container {
+ display: block;
+ opacity: 1; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume.muted > a {
+ background: url("../images/mute.png") 10px center no-repeat; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a {
+ background: url("../images/volume.png") 10px center no-repeat;
+ border-right: 1px solid #000;
+ -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ zoom: 1;
+ color: #fff;
+ cursor: pointer;
+ display: block;
+ height: 46px;
+ margin-right: 0;
+ padding-left: 15px;
+ position: relative;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ -webkit-font-smoothing: antialiased;
+ width: 30px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:before, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:after {
+ content: "";
+ display: table; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:after {
+ clear: both; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:active, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:focus {
+ background-color: #444; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container {
+ -webkit-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ -moz-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ background-color: #444;
+ border: 1px solid #000;
+ bottom: 46px;
+ display: none;
+ opacity: 0;
+ position: absolute;
+ width: 45px;
+ height: 125px;
+ margin-left: -1px;
+ z-index: 10; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider {
+ height: 100px;
+ border: 0;
+ width: 5px;
+ margin: 14px auto;
+ background: #666;
+ border: 1px solid #000;
+ -webkit-box-shadow: 0 1px 0 #333333;
+ -moz-box-shadow: 0 1px 0 #333333;
+ box-shadow: 0 1px 0 #333333; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider a.ui-slider-handle {
+ background: #993333 url(../images/slider-handle.png) center center no-repeat;
+ -webkit-background-size: 50%;
+ -moz-background-size: 50%;
+ -ms-background-size: 50%;
+ -o-background-size: 50%;
+ background-size: 50%;
+ border: 1px solid #4d1919;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ -ms-border-radius: 15px;
+ -o-border-radius: 15px;
+ border-radius: 15px;
+ -webkit-box-shadow: inset 0 1px 0 #bf4040;
+ -moz-box-shadow: inset 0 1px 0 #bf4040;
+ box-shadow: inset 0 1px 0 #bf4040;
+ cursor: pointer;
+ height: 15px;
+ left: -6px;
+ -webkit-transition-property: height, 2s, ease-in-out;
+ -moz-transition-property: height, 2s, ease-in-out;
+ -ms-transition-property: height, 2s, ease-in-out;
+ -o-transition-property: height, 2s, ease-in-out;
+ transition-property: height, 2s, ease-in-out;
+ -webkit-transition-duration: width, 2s, ease-in-out;
+ -moz-transition-duration: width, 2s, ease-in-out;
+ -ms-transition-duration: width, 2s, ease-in-out;
+ -o-transition-duration: width, 2s, ease-in-out;
+ transition-duration: width, 2s, ease-in-out;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 15px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider .ui-slider-range {
+ background: #ddd; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.add-fullscreen {
+ background: url(../images/fullscreen.png) center no-repeat;
+ border-right: 1px solid #000;
+ -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
+ color: #797979;
+ display: block;
+ float: left;
+ line-height: 46px;
+ margin-left: 0;
+ padding: 0 11.326px;
+ text-indent: -9999px;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ width: 30px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.add-fullscreen:hover {
+ background-color: #444;
+ color: #fff;
+ text-decoration: none; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles {
+ background: url("../images/cc.png") center no-repeat;
+ color: #797979;
+ display: block;
+ float: left;
+ font-weight: 800;
+ line-height: 46px;
+ margin-left: 0;
+ opacity: 1;
+ padding: 0 11.326px;
+ position: relative;
+ text-indent: -9999px;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0;
+ -webkit-font-smoothing: antialiased;
+ width: 30px; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles:hover {
+ background-color: #444;
+ color: #fff;
+ text-decoration: none; }
+ section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles.off {
+ opacity: .7; }
+ section.course-content div.video article.video-wrapper:hover section.video-controls ul, section.course-content div.video article.video-wrapper:hover section.video-controls div {
+ opacity: 1; }
+ section.course-content div.video article.video-wrapper:hover section.video-controls div.slider {
+ height: 14px;
+ margin-top: -7px; }
+ section.course-content div.video article.video-wrapper:hover section.video-controls div.slider a.ui-slider-handle {
+ -webkit-border-radius: 20px;
+ -moz-border-radius: 20px;
+ -ms-border-radius: 20px;
+ -o-border-radius: 20px;
+ border-radius: 20px;
+ height: 20px;
+ margin-left: -10px;
+ top: -4px;
+ width: 20px; }
+ section.course-content div.video ol.subtitles {
+ float: left;
+ max-height: 460px;
+ overflow: auto;
+ width: 31.522%; }
+ section.course-content div.video ol.subtitles li {
+ border: 0;
+ color: #666;
+ cursor: pointer;
+ margin-bottom: 8px;
+ padding: 0; }
+ section.course-content div.video ol.subtitles li.current {
+ color: #333;
+ font-weight: 700; }
+ section.course-content div.video ol.subtitles li:hover {
+ color: #993333; }
+ section.course-content div.video ol.subtitles li:empty {
+ margin-bottom: 0px; }
+ section.course-content div.video.closed article.video-wrapper {
+ width: 100%; }
+ section.course-content div.video.closed ol.subtitles {
+ width: 0px; }
+ section.course-content div.video.fullscreen {
+ background: rgba(0, 0, 0, 0.95);
+ border: 0;
+ bottom: 0;
+ height: 100%;
+ left: 0;
+ margin: 0;
+ max-height: 100%;
+ overflow: hidden;
+ padding: 0;
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index: 999; }
+ section.course-content div.video.fullscreen.closed ol.subtitles {
+ right: -31.984%;
+ width: auto; }
+ section.course-content div.video.fullscreen a.exit {
+ color: #aaa;
+ display: none;
+ font-style: 12px;
+ left: 20px;
+ letter-spacing: 1px;
+ position: absolute;
+ text-transform: uppercase;
+ top: 20px; }
+ section.course-content div.video.fullscreen a.exit::after {
+ content: "✖";
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ padding-left: 6px; }
+ section.course-content div.video.fullscreen a.exit:hover {
+ color: #993333; }
+ section.course-content div.video.fullscreen div.tc-wrapper article.video-wrapper {
+ width: 100%; }
+ section.course-content div.video.fullscreen div.tc-wrapper object, section.course-content div.video.fullscreen div.tc-wrapper iframe {
+ bottom: 0;
+ height: 100%;
+ left: 0;
+ overflow: hidden;
+ position: fixed;
+ top: 0; }
+ section.course-content div.video.fullscreen div.tc-wrapper section.video-controls {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ width: 100%;
+ z-index: 9999; }
+ section.course-content div.video.fullscreen ol.subtitles {
+ background: rgba(0, 0, 0, 0.8);
+ bottom: 0;
+ height: 100%;
+ max-height: 100%;
+ max-width: 23.482%;
+ padding: 22.652px;
+ position: fixed;
+ right: 0;
+ top: 0;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ section.course-content div.video.fullscreen ol.subtitles li {
+ color: #aaa; }
+ section.course-content div.video.fullscreen ol.subtitles li.current {
+ color: #fff; }
+
+div.course-wrapper.closed section.course-content div.video ol.subtitles {
+ max-height: 577px; }
+
+section.tool-wrapper {
+ background: #073642;
+ border-bottom: 1px solid #000203;
+ border-top: 1px solid #000203;
+ -webkit-box-shadow: inset 0 0 0 4px #084150;
+ -moz-box-shadow: inset 0 0 0 4px #084150;
+ box-shadow: inset 0 0 0 4px #084150;
+ color: #839496;
+ display: table;
+ margin: 22.652px -22.652px 0; }
+ section.tool-wrapper div#graph-container {
+ background: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ padding: 22.652px;
+ vertical-align: top;
+ width: 51.359%; }
+ section.tool-wrapper div#graph-container .ui-widget-content {
+ background: none;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0; }
+ section.tool-wrapper div#graph-container canvas {
+ width: 100%; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav {
+ background: #062e39;
+ border-bottom: 1px solid #03181d;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ margin: -22.652px -22.652px 0;
+ padding: 0;
+ position: relative;
+ width: 110%; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li {
+ background: none;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ border-radius: 0;
+ color: #fff;
+ margin-bottom: 0; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected {
+ background-color: #073642;
+ border-left: 1px solid #03181d;
+ border-right: 1px solid #03181d; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected:first-child {
+ border-left: none; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected a {
+ color: #eee8d5; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li a {
+ border: none;
+ color: #839496;
+ font: bold 12px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ letter-spacing: 1px;
+ text-transform: uppercase; }
+ section.tool-wrapper div#graph-container ul.ui-tabs-nav li a:hover {
+ color: #eee8d5; }
+ section.tool-wrapper div#controlls-container {
+ background: #062e39;
+ border-right: 1px solid #001317;
+ -webkit-box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
+ -moz-box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
+ box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ padding: 22.652px;
+ vertical-align: top;
+ width: 48.641%; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper {
+ border-bottom: 1px solid #021014;
+ -webkit-box-shadow: 0 1px 0 #083e4b;
+ -moz-box-shadow: 0 1px 0 #083e4b;
+ box-shadow: 0 1px 0 #083e4b;
+ margin-bottom: 22.652px;
+ padding: 0 0 22.652px; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton {
+ border-color: #001317;
+ border: 1px solid #3d5962;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 0 #939da0;
+ -moz-box-shadow: inset 0 1px 0 0 #939da0;
+ box-shadow: inset 0 1px 0 0 #939da0;
+ color: white;
+ display: inline;
+ font-size: 11px;
+ font-weight: bold;
+ background-color: #637c84;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #637c84), color-stop(100%, #43626b));
+ background-image: -webkit-linear-gradient(top, #637c84, #43626b);
+ background-image: -moz-linear-gradient(top, #637c84, #43626b);
+ background-image: -ms-linear-gradient(top, #637c84, #43626b);
+ background-image: -o-linear-gradient(top, #637c84, #43626b);
+ background-image: linear-gradient(top, #637c84, #43626b);
+ padding: 6px 18px 7px;
+ text-shadow: 0 1px 0 #31505a;
+ -webkit-background-clip: padding-box;
+ display: block;
+ float: right;
+ font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:hover {
+ -webkit-box-shadow: inset 0 1px 0 0 #778589;
+ -moz-box-shadow: inset 0 1px 0 0 #778589;
+ box-shadow: inset 0 1px 0 0 #778589;
+ cursor: pointer;
+ background-color: #5c6c71;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5c6c71), color-stop(100%, #3e5961));
+ background-image: -webkit-linear-gradient(top, #5c6c71, #3e5961);
+ background-image: -moz-linear-gradient(top, #5c6c71, #3e5961);
+ background-image: -ms-linear-gradient(top, #5c6c71, #3e5961);
+ background-image: -o-linear-gradient(top, #5c6c71, #3e5961);
+ background-image: linear-gradient(top, #5c6c71, #3e5961); }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active {
+ border: 1px solid #3d5962;
+ -webkit-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee;
+ -moz-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee;
+ box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"] {
+ border: 1px solid #030d15;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 0 #215f8a;
+ -moz-box-shadow: inset 0 1px 0 0 #215f8a;
+ box-shadow: inset 0 1px 0 0 #215f8a;
+ color: white;
+ display: inline;
+ font-size: 11px;
+ font-weight: bold;
+ background-color: #0f3550;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0f3550), color-stop(100%, #041623));
+ background-image: -webkit-linear-gradient(top, #0f3550, #041623);
+ background-image: -moz-linear-gradient(top, #0f3550, #041623);
+ background-image: -ms-linear-gradient(top, #0f3550, #041623);
+ background-image: -o-linear-gradient(top, #0f3550, #041623);
+ background-image: linear-gradient(top, #0f3550, #041623);
+ padding: 6px 18px 7px;
+ text-shadow: 0 1px 0 #000203;
+ -webkit-background-clip: padding-box;
+ font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:hover {
+ -webkit-box-shadow: inset 0 1px 0 0 #174362;
+ -moz-box-shadow: inset 0 1px 0 0 #174362;
+ box-shadow: inset 0 1px 0 0 #174362;
+ cursor: pointer;
+ background-color: #0c2739;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0c2739), color-stop(100%, #030d15));
+ background-image: -webkit-linear-gradient(top, #0c2739, #030d15);
+ background-image: -moz-linear-gradient(top, #0c2739, #030d15);
+ background-image: -ms-linear-gradient(top, #0c2739, #030d15);
+ background-image: -o-linear-gradient(top, #0c2739, #030d15);
+ background-image: linear-gradient(top, #0c2739, #030d15); }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active {
+ border: 1px solid #030d15;
+ -webkit-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee;
+ -moz-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee;
+ box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper {
+ border-bottom: 1px solid #021014;
+ -webkit-box-shadow: 0 1px 0 #083e4b;
+ -moz-box-shadow: 0 1px 0 #083e4b;
+ box-shadow: 0 1px 0 #083e4b;
+ zoom: 1;
+ margin-bottom: 22.652px;
+ margin-bottom: 22.652px;
+ padding: 0 0 22.652px; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:before, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after {
+ content: "";
+ display: table; }
+ section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after {
+ clear: both; }
+ section.tool-wrapper div#controlls-container div.graph-controls p {
+ font-weight: bold;
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin: 0;
+ text-shadow: 0 -1px 0 #021014;
+ -webkit-font-smoothing: antialiased; }
+ section.tool-wrapper div#controlls-container div.graph-controls ul {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin-bottom: 0; }
+ section.tool-wrapper div#controlls-container div.graph-controls ul li {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin-bottom: 0; }
+ section.tool-wrapper div#controlls-container div.graph-controls ul li input {
+ margin-right: 5px; }
+ section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen {
+ display: block;
+ float: left;
+ margin-bottom: 0;
+ margin-right: 20px;
+ margin-top: 8px;
+ text-align: right; }
+ section.tool-wrapper div#controlls-container label {
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ -ms-border-radius: 2px;
+ -o-border-radius: 2px;
+ border-radius: 2px;
+ color: #fff;
+ font-weight: bold;
+ padding: 3px;
+ -webkit-font-smoothing: antialiased; }
+ section.tool-wrapper div#controlls-container label[for="vinCheckbox"], section.tool-wrapper div#controlls-container label[for="vinRadioButton"] {
+ color: #409fbf; }
+ section.tool-wrapper div#controlls-container label[for="voutCheckbox"], section.tool-wrapper div#controlls-container label[for="voutRadioButton"] {
+ color: #e1a600; }
+ section.tool-wrapper div#controlls-container label[for="vrCheckbox"], section.tool-wrapper div#controlls-container label[for="vrRadioButton"] {
+ color: #49c944; }
+ section.tool-wrapper div#controlls-container label[for="vcCheckbox"], section.tool-wrapper div#controlls-container label[for="vcRadioButton"] {
+ color: #e1a600; }
+ section.tool-wrapper div#controlls-container label[for="vlCheckbox"], section.tool-wrapper div#controlls-container label[for="vlRadioButton"] {
+ color: #a26784; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders {
+ border-bottom: 1px solid #021014;
+ -webkit-box-shadow: 0 1px 0 #083e4b;
+ -moz-box-shadow: 0 1px 0 #083e4b;
+ box-shadow: 0 1px 0 #083e4b;
+ margin-bottom: 22.652px;
+ padding: 0 0 22.652px; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders select#musicTypeSelect {
+ font: 16px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin-bottom: 0; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders p {
+ font-weight: bold;
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin: 0 11.326px 22.652px 0;
+ text-shadow: 0 -1px 0 #021014;
+ -webkit-font-smoothing: antialiased; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider-label {
+ font-weight: bold;
+ margin-bottom: 11.326px;
+ text-shadow: 0 -1px 0 #021014;
+ -webkit-font-smoothing: antialiased; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider {
+ margin-bottom: 22.652px; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider.ui-slider-horizontal {
+ background: #00232c;
+ border: 1px solid #000b0d;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ height: 0.4em; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle {
+ background: #637c84 url("../images/amplifier-slider-handle.png") center no-repeat;
+ border: 1px solid #000b0d;
+ -webkit-box-shadow: inset 0 1px 0 #8ba1a8;
+ -moz-box-shadow: inset 0 1px 0 #8ba1a8;
+ box-shadow: inset 0 1px 0 #8ba1a8;
+ margin-top: -0.3em; }
+ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:hover, section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:active {
+ background-color: #6e8992; }
+
+section.problem-set, div.course-wrapper section.course-content section.problems-wrapper, section.problems-wrapper {
+ position: relative; }
+ section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
+ margin-top: 0;
+ margin-bottom: 15px;
+ width: 20.109%;
+ padding-right: 2.717%;
+ border-right: 1px dashed #ddd;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: table-cell;
+ vertical-align: top; }
+ section.problem-set h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, section.problems-wrapper h2.problem-header section.staff {
+ margin-top: 30px;
+ font-size: 80%; }
+ @media screen and (max-width:1120px) {
+ section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
+ display: block;
+ width: auto;
+ border-right: 0; } }
+ @media print {
+ section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
+ display: block;
+ width: auto;
+ border-right: 0; } }
+ section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
+ display: table-cell;
+ width: 77.174%;
+ padding-left: 2.717%; }
+ @media screen and (max-width:1120px) {
+ section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
+ display: block;
+ width: auto;
+ padding: 0; } }
+ @media print {
+ section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
+ display: block;
+ width: auto;
+ padding: 0; }
+ section.problem-set section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, section.problems-wrapper section.problem canvas, section.problem-set section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, section.problems-wrapper section.problem img {
+ page-break-inside: avoid; } }
+ section.problem-set section.problem div p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.status, section.problems-wrapper section.problem div p.status {
+ text-indent: -9999px;
+ margin: -1px 0 0 10px; }
+ section.problem-set section.problem div.unanswered p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.unanswered p.status, section.problems-wrapper section.problem div.unanswered p.status {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/unanswered-icon.png") center center no-repeat;
+ height: 14px;
+ width: 14px; }
+ section.problem-set section.problem div.correct p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.correct p.status, section.problems-wrapper section.problem div.correct p.status, section.problem-set section.problem div.ui-icon-check p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-check p.status, section.problems-wrapper section.problem div.ui-icon-check p.status {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/correct-icon.png") center center no-repeat;
+ height: 20px;
+ width: 25px; }
+ section.problem-set section.problem div.correct input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.correct input, section.problems-wrapper section.problem div.correct input, section.problem-set section.problem div.ui-icon-check input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-check input, section.problems-wrapper section.problem div.ui-icon-check input {
+ border-color: green; }
+ section.problem-set section.problem div.incorrect p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.incorrect p.status, section.problems-wrapper section.problem div.incorrect p.status, section.problem-set section.problem div.ui-icon-close p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-close p.status, section.problems-wrapper section.problem div.ui-icon-close p.status {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/incorrect-icon.png") center center no-repeat;
+ height: 20px;
+ width: 20px;
+ text-indent: -9999px; }
+ section.problem-set section.problem div.incorrect input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.incorrect input, section.problems-wrapper section.problem div.incorrect input, section.problem-set section.problem div.ui-icon-close input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-close input, section.problems-wrapper section.problem div.ui-icon-close input {
+ border-color: red; }
+ section.problem-set section.problem div > span, div.course-wrapper section.course-content section.problems-wrapper section.problem div > span, section.problems-wrapper section.problem div > span {
+ display: block;
+ margin-bottom: 11.326px; }
+ section.problem-set section.problem div p.answer, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer, section.problems-wrapper section.problem div p.answer {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ margin-bottom: 0;
+ margin-left: 10px; }
+ section.problem-set section.problem div p.answer:before, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer:before, section.problems-wrapper section.problem div p.answer:before {
+ content: "Answer: ";
+ font-weight: bold;
+ display: inline; }
+ section.problem-set section.problem div p.answer:empty:before, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer:empty:before, section.problems-wrapper section.problem div p.answer:empty:before {
+ display: none; }
+ section.problem-set section.problem div div.equation, div.course-wrapper section.course-content section.problems-wrapper section.problem div div.equation, section.problems-wrapper section.problem div div.equation {
+ clear: both;
+ padding: 6px;
+ background: #eee; }
+ section.problem-set section.problem div div.equation span, div.course-wrapper section.course-content section.problems-wrapper section.problem div div.equation span, section.problems-wrapper section.problem div div.equation span {
+ margin-bottom: 0; }
+ section.problem-set section.problem div span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.unanswered, section.problems-wrapper section.problem div span.unanswered, section.problem-set section.problem div span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-bullet, section.problems-wrapper section.problem div span.ui-icon-bullet {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/unanswered-icon.png") center center no-repeat;
+ height: 14px;
+ position: relative;
+ top: 4px;
+ width: 14px; }
+ section.problem-set section.problem div span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.correct, section.problems-wrapper section.problem div span.correct, section.problem-set section.problem div span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-check, section.problems-wrapper section.problem div span.ui-icon-check {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/correct-icon.png") center center no-repeat;
+ height: 20px;
+ position: relative;
+ top: 6px;
+ width: 25px; }
+ section.problem-set section.problem div span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.incorrect, section.problems-wrapper section.problem div span.incorrect, section.problem-set section.problem div span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-close, section.problems-wrapper section.problem div span.ui-icon-close {
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ background: url("../images/incorrect-icon.png") center center no-repeat;
+ height: 20px;
+ width: 20px;
+ position: relative;
+ top: 6px; }
+ section.problem-set section.problem ul, div.course-wrapper section.course-content section.problems-wrapper section.problem ul, section.problems-wrapper section.problem ul {
+ list-style: disc outside none;
+ margin-bottom: 22.652px;
+ margin-left: .75em;
+ margin-left: .75rem; }
+ section.problem-set section.problem ol, div.course-wrapper section.course-content section.problems-wrapper section.problem ol, section.problems-wrapper section.problem ol {
+ list-style: decimal outside none;
+ margin-bottom: 22.652px;
+ margin-left: .75em;
+ margin-left: .75rem; }
+ section.problem-set section.problem dl, div.course-wrapper section.course-content section.problems-wrapper section.problem dl, section.problems-wrapper section.problem dl {
+ line-height: 1.4em; }
+ section.problem-set section.problem dl dt, div.course-wrapper section.course-content section.problems-wrapper section.problem dl dt, section.problems-wrapper section.problem dl dt {
+ font-weight: bold; }
+ section.problem-set section.problem dl dd, div.course-wrapper section.course-content section.problems-wrapper section.problem dl dd, section.problems-wrapper section.problem dl dd {
+ margin-bottom: 0; }
+ section.problem-set section.problem dd, div.course-wrapper section.course-content section.problems-wrapper section.problem dd, section.problems-wrapper section.problem dd {
+ margin-left: .5em;
+ margin-left: .5rem; }
+ section.problem-set section.problem li, div.course-wrapper section.course-content section.problems-wrapper section.problem li, section.problems-wrapper section.problem li {
+ line-height: 1.4em;
+ margin-bottom: 11.326px; }
+ section.problem-set section.problem li:last-child, div.course-wrapper section.course-content section.problems-wrapper section.problem li:last-child, section.problems-wrapper section.problem li:last-child {
+ margin-bottom: 0; }
+ section.problem-set section.problem p, div.course-wrapper section.course-content section.problems-wrapper section.problem p, section.problems-wrapper section.problem p {
+ margin-bottom: 22.652px; }
+ section.problem-set section.problem table, div.course-wrapper section.course-content section.problems-wrapper section.problem table, section.problems-wrapper section.problem table {
+ margin-bottom: 22.652px;
+ width: 100%;
+ border-collapse: collapse; }
+ section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th {
+ font-weight: bold;
+ text-align: left; }
+ section.problem-set section.problem table caption, div.course-wrapper section.course-content section.problems-wrapper section.problem table caption, section.problems-wrapper section.problem table caption, section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th, section.problem-set section.problem table td, div.course-wrapper section.course-content section.problems-wrapper section.problem table td, section.problems-wrapper section.problem table td {
+ padding: .25em .75em .25em 0;
+ padding: .25rem .75rem .25rem 0; }
+ section.problem-set section.problem table caption, div.course-wrapper section.course-content section.problems-wrapper section.problem table caption, section.problems-wrapper section.problem table caption {
+ background: #f1f1f1;
+ margin-bottom: .75em;
+ margin-bottom: .75rem;
+ padding: .75em 0;
+ padding: .75rem 0; }
+ section.problem-set section.problem table tr, div.course-wrapper section.course-content section.problems-wrapper section.problem table tr, section.problems-wrapper section.problem table tr, section.problem-set section.problem table td, div.course-wrapper section.course-content section.problems-wrapper section.problem table td, section.problems-wrapper section.problem table td, section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th {
+ vertical-align: middle; }
+ section.problem-set section.problem hr, div.course-wrapper section.course-content section.problems-wrapper section.problem hr, section.problems-wrapper section.problem hr {
+ background: #ddd;
+ border: none;
+ clear: both;
+ color: #ddd;
+ float: none;
+ height: 1px;
+ margin: 0 0 .75rem;
+ width: 100%; }
+ section.problem-set section.problem .hidden, div.course-wrapper section.course-content section.problems-wrapper section.problem .hidden, section.problems-wrapper section.problem .hidden {
+ display: none;
+ visibility: hidden; }
+ section.problem-set section.problem input[type="email"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="email"], section.problems-wrapper section.problem input[type="email"], section.problem-set section.problem input[type="number"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="number"], section.problems-wrapper section.problem input[type="number"], section.problem-set section.problem input[type="password"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="password"], section.problems-wrapper section.problem input[type="password"], section.problem-set section.problem input[type="search"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="search"], section.problems-wrapper section.problem input[type="search"], section.problem-set section.problem input[type="tel"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="tel"], section.problems-wrapper section.problem input[type="tel"], section.problem-set section.problem input[type="text"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="text"], section.problems-wrapper section.problem input[type="text"], section.problem-set section.problem input[type="url"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="url"], section.problems-wrapper section.problem input[type="url"], section.problem-set section.problem input[type="color"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="color"], section.problems-wrapper section.problem input[type="color"], section.problem-set section.problem input[type="date"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="date"], section.problems-wrapper section.problem input[type="date"], section.problem-set section.problem input[type="datetime"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="datetime"], section.problems-wrapper section.problem input[type="datetime"], section.problem-set section.problem input[type="datetime-local"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="datetime-local"], section.problems-wrapper section.problem input[type="datetime-local"], section.problem-set section.problem input[type="month"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="month"], section.problems-wrapper section.problem input[type="month"], section.problem-set section.problem input[type="time"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="time"], section.problems-wrapper section.problem input[type="time"], section.problem-set section.problem input[type="week"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="week"], section.problems-wrapper section.problem input[type="week"] {
+ display: inline;
+ width: auto; }
+ section.problem-set section.problem center, div.course-wrapper section.course-content section.problems-wrapper section.problem center, section.problems-wrapper section.problem center {
+ display: block;
+ margin: 22.652px 0;
+ border: 1px solid #ccc;
+ padding: 22.652px; }
+ section.problem-set section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, section.problems-wrapper section.action {
+ margin-top: 11.326px; }
+ section.problem-set section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], section.problems-wrapper section.action input[type="button"] {
+ padding: 9.061px 22.652px;
+ text-shadow: 0 -1px 0 #666666; }
+
+section.problems-wrapper {
+ display: table;
+ width: 100%; }
+ @media screen and (max-width:1120px) {
+ section.problems-wrapper {
+ display: block;
+ width: auto; } }
+
+div.info-wrapper section.updates > p {
+ margin-bottom: 22.652px; }
+div.info-wrapper section.updates > ol {
+ list-style: none; }
+ div.info-wrapper section.updates > ol > li {
+ border-bottom: 1px solid #e3e3e3;
+ margin-bottom: 11.326px;
+ padding-bottom: 11.326px;
+ list-style-type: disk; }
+ div.info-wrapper section.updates > ol > li:first-child {
+ background: #f6efd4;
+ border-bottom: 1px solid #eddfaa;
+ margin: 0 -11.326px 22.652px;
+ padding: 11.326px; }
+ div.info-wrapper section.updates > ol > li ol, div.info-wrapper section.updates > ol > li ul {
+ margin: 22.652px 0 0 22.652px;
+ list-style-type: circle; }
+ div.info-wrapper section.updates > ol > li h2 {
+ float: left;
+ margin: 0 2.024% 0 0;
+ width: 20.109%; }
+ div.info-wrapper section.updates > ol > li section.update-description {
+ float: left;
+ margin-bottom: 0;
+ width: 77.174%; }
+ div.info-wrapper section.updates > ol > li section.update-description li {
+ margin-bottom: 11.326px; }
+ div.info-wrapper section.updates > ol > li section.update-description p:last-child {
+ margin-bottom: 0; }
+div.info-wrapper section.handouts {
+ border-left: 1px solid #d3d3d3;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ -ms-border-radius: 0 4px 4px 0;
+ -o-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+ border-right: 0; }
+ div.info-wrapper section.handouts header {
+ padding: 11.326px 16.989px; }
+ div.info-wrapper section.handouts header h1 {
+ font-size: 18px;
+ margin: 0; }
+ div.info-wrapper section.handouts header p {
+ color: #666;
+ font-size: 12px;
+ margin-bottom: 0;
+ margin-top: 4px; }
+ div.info-wrapper section.handouts ol {
+ background: none;
+ list-style: none; }
+ div.info-wrapper section.handouts ol li {
+ background: none;
+ border-bottom: 1px solid #d3d3d3;
+ -webkit-box-shadow: 0 1px 0 #eeeeee;
+ -moz-box-shadow: 0 1px 0 #eeeeee;
+ box-shadow: 0 1px 0 #eeeeee;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 7px 16.989px;
+ position: relative; }
+ div.info-wrapper section.handouts ol li.expandable h4, div.info-wrapper section.handouts ol li.collapsable h4 {
+ font-style: 14px;
+ font-weight: normal;
+ padding-left: 18px; }
+ div.info-wrapper section.handouts ol li ul {
+ background: none;
+ margin: 7px -16.989px 0; }
+ div.info-wrapper section.handouts ol li ul li {
+ border-bottom: 0;
+ border-top: 1px solid #d3d3d3;
+ -webkit-box-shadow: inset 0 1px 0 #eeeeee;
+ -moz-box-shadow: inset 0 1px 0 #eeeeee;
+ box-shadow: inset 0 1px 0 #eeeeee;
+ padding-left: 34.989px; }
+ div.info-wrapper section.handouts ol li:hover {
+ background-color: #e9e9e9; }
+ div.info-wrapper section.handouts ol li div.hitarea {
+ background-image: url("../images/treeview-default.gif");
+ display: block;
+ height: 100%;
+ left: 16.989px;
+ margin-left: 0;
+ max-height: 20px;
+ position: absolute;
+ width: 100%; }
+ div.info-wrapper section.handouts ol li div.hitarea:hover {
+ opacity: 0.6;
+ filter: alpha(opacity=60); }
+ div.info-wrapper section.handouts ol li div.hitarea.expandable-hitarea {
+ background-position: -80px 1px; }
+ div.info-wrapper section.handouts ol li div.hitarea.collapsable-hitarea {
+ background-position: -64px -21px; }
+ div.info-wrapper section.handouts ol li h3 {
+ border-bottom: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ color: #999;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase; }
+ div.info-wrapper section.handouts ol li p {
+ font-size: 14px;
+ letter-spacing: 0;
+ margin: 0;
+ text-transform: none; }
+ div.info-wrapper section.handouts ol li p a {
+ padding-right: 8px; }
+ div.info-wrapper section.handouts ol li p a:before {
+ color: #ccc;
+ content: "•";
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ padding-right: 8px; }
+ div.info-wrapper section.handouts ol li p a:first-child:before {
+ content: "";
+ padding-right: 0; }
+ div.info-wrapper section.handouts ol li a {
+ color: #4d4d4d;
+ display: -moz-inline-box;
+ -moz-box-orient: vertical;
+ display: inline-block;
+ vertical-align: baseline;
+ zoom: 1;
+ *display: inline;
+ *vertical-align: auto;
+ text-decoration: none;
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -ms-transition-property: all;
+ -o-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.15s;
+ -moz-transition-duration: 0.15s;
+ -ms-transition-duration: 0.15s;
+ -o-transition-duration: 0.15s;
+ transition-duration: 0.15s;
+ -webkit-transition-timing-function: ease-out;
+ -moz-transition-timing-function: ease-out;
+ -ms-transition-timing-function: ease-out;
+ -o-transition-timing-function: ease-out;
+ transition-timing-function: ease-out;
+ -webkit-transition-delay: 0;
+ -moz-transition-delay: 0;
+ -ms-transition-delay: 0;
+ -o-transition-delay: 0;
+ transition-delay: 0; }
+ div.info-wrapper section.handouts ol li a:hover {
+ color: #993333; }
+
+/*
+ * jQuery UI CSS Framework 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none; }
+
+.ui-helper-hidden-accessible {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px);
+ clip: rect(1px, 1px, 1px, 1px); }
+
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none; }
+
+.ui-helper-clearfix:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden; }
+
+.ui-helper-clearfix {
+ display: inline-block; }
+
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix {
+ height: 1%; }
+
+.ui-helper-clearfix {
+ display: block; }
+
+/* end clearfix */
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter: Alpha(Opacity=0); }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important; }
+
+/* Icons
+----------------------------------*/
+/* states and images */
+.ui-icon {
+ display: block;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat; }
+
+/* Misc visuals
+----------------------------------*/
+/* Overlays */
+.ui-widget-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%; }
+
+/*
+ * jQuery UI CSS Framework 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=7fbcfd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=50&borderColorHeader=dae5c9&fcHeader=031634&iconColorHeader=031634&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=dae5c9&fcContent=031634&iconColorContent=adcc80&bgColorDefault=7fbcdf&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=100&borderColorDefault=dae5c9&fcDefault=7a994c&iconColorDefault=adcc80&bgColorHover=bddeff&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=7fbcdf&fcHover=7a994c&iconColorHover=adcc80&bgColorActive=023063&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=dae5c9&fcActive=dae5c9&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=adcc80&bgColorError=ffffff&bgTextureError=01_flat.png&bgImgOpacityError=55&borderColorError=fa720a&fcError=222222&iconColorError=fa720a&bgColorOverlay=eeeeee&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
+ */
+/* Component containers
+----------------------------------*/
+.ui-widget {
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: 1.1em; }
+
+.ui-widget .ui-widget {
+ font-size: 1em; }
+
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button {
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: 1em; }
+
+.ui-widget-content {
+ border: 1px solid #dae5c9;
+ background: white url(../images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;
+ color: #031634; }
+
+.ui-widget-content a {
+ color: #031634; }
+
+.ui-widget-header {
+ border: 1px solid #dae5c9;
+ background: #7fbcfd url(../images/ui-bg_highlight-soft_50_7fbcfd_1x100.png) 50% 50% repeat-x;
+ color: #031634;
+ font-weight: bold; }
+
+.ui-widget-header a {
+ color: #031634; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
+ border: 1px solid #dae5c9;
+ background: #7fbcdf url(../images/ui-bg_highlight-soft_100_7fbcdf_1x100.png) 50% 50% repeat-x;
+ font-weight: bold;
+ color: #7a994c; }
+
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited {
+ color: #7a994c;
+ text-decoration: none; }
+
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus {
+ border: 1px solid #7fbcdf;
+ background: #bddeff url(../images/ui-bg_highlight-soft_25_bddeff_1x100.png) 50% 50% repeat-x;
+ font-weight: bold;
+ color: #7a994c; }
+
+.ui-state-hover a, .ui-state-hover a:hover {
+ color: #7a994c;
+ text-decoration: none; }
+
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
+ border: 1px solid #dae5c9;
+ background: #023063 url(../images/ui-bg_glass_65_023063_1x400.png) 50% 50% repeat-x;
+ font-weight: bold;
+ color: #dae5c9; }
+
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited {
+ color: #dae5c9;
+ text-decoration: none; }
+
+.ui-widget :active {
+ outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {
+ border: 1px solid #cccccc;
+ background: white url(../images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;
+ color: #444444; }
+
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a, .ui-widget-header .ui-state-highlight a {
+ color: #444444; }
+
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {
+ border: 1px solid #fa720a;
+ background: white url(../images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;
+ color: #222222; }
+
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a {
+ color: #222222; }
+
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text {
+ color: #222222; }
+
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary {
+ font-weight: bold; }
+
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary {
+ opacity: .7;
+ filter: Alpha(Opacity=70);
+ font-weight: normal; }
+
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled {
+ opacity: .35;
+ filter: Alpha(Opacity=35);
+ background-image: none; }
+
+/* Icons
+----------------------------------*/
+/* states and images */
+.ui-icon {
+ width: 16px;
+ height: 16px;
+ background-image: url(../images/ui-icons_adcc80_256x240.png); }
+
+.ui-widget-content .ui-icon {
+ background-image: url(../images/ui-icons_adcc80_256x240.png); }
+
+.ui-widget-header .ui-icon {
+ background-image: url(../images/ui-icons_031634_256x240.png); }
+
+.ui-state-default .ui-icon {
+ background-image: url(../images/ui-icons_adcc80_256x240.png); }
+
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {
+ background-image: url(../images/ui-icons_adcc80_256x240.png); }
+
+.ui-state-active .ui-icon {
+ background-image: url(../images/ui-icons_454545_256x240.png); }
+
+.ui-state-highlight .ui-icon {
+ background-image: url(../images/ui-icons_adcc80_256x240.png); }
+
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {
+ background-image: url(../images/ui-icons_fa720a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n {
+ background-position: 0 0; }
+
+.ui-icon-carat-1-ne {
+ background-position: -16px 0; }
+
+.ui-icon-carat-1-e {
+ background-position: -32px 0; }
+
+.ui-icon-carat-1-se {
+ background-position: -48px 0; }
+
+.ui-icon-carat-1-s {
+ background-position: -64px 0; }
+
+.ui-icon-carat-1-sw {
+ background-position: -80px 0; }
+
+.ui-icon-carat-1-w {
+ background-position: -96px 0; }
+
+.ui-icon-carat-1-nw {
+ background-position: -112px 0; }
+
+.ui-icon-carat-2-n-s {
+ background-position: -128px 0; }
+
+.ui-icon-carat-2-e-w {
+ background-position: -144px 0; }
+
+.ui-icon-triangle-1-n {
+ background-position: 0 -16px; }
+
+.ui-icon-triangle-1-ne {
+ background-position: -16px -16px; }
+
+.ui-icon-triangle-1-e {
+ background-position: -32px -16px; }
+
+.ui-icon-triangle-1-se {
+ background-position: -48px -16px; }
+
+.ui-icon-triangle-1-s {
+ background-position: -64px -16px; }
+
+.ui-icon-triangle-1-sw {
+ background-position: -80px -16px; }
+
+.ui-icon-triangle-1-w {
+ background-position: -96px -16px; }
+
+.ui-icon-triangle-1-nw {
+ background-position: -112px -16px; }
+
+.ui-icon-triangle-2-n-s {
+ background-position: -128px -16px; }
+
+.ui-icon-triangle-2-e-w {
+ background-position: -144px -16px; }
+
+.ui-icon-arrow-1-n {
+ background-position: 0 -32px; }
+
+.ui-icon-arrow-1-ne {
+ background-position: -16px -32px; }
+
+.ui-icon-arrow-1-e {
+ background-position: -32px -32px; }
+
+.ui-icon-arrow-1-se {
+ background-position: -48px -32px; }
+
+.ui-icon-arrow-1-s {
+ background-position: -64px -32px; }
+
+.ui-icon-arrow-1-sw {
+ background-position: -80px -32px; }
+
+.ui-icon-arrow-1-w {
+ background-position: -96px -32px; }
+
+.ui-icon-arrow-1-nw {
+ background-position: -112px -32px; }
+
+.ui-icon-arrow-2-n-s {
+ background-position: -128px -32px; }
+
+.ui-icon-arrow-2-ne-sw {
+ background-position: -144px -32px; }
+
+.ui-icon-arrow-2-e-w {
+ background-position: -160px -32px; }
+
+.ui-icon-arrow-2-se-nw {
+ background-position: -176px -32px; }
+
+.ui-icon-arrowstop-1-n {
+ background-position: -192px -32px; }
+
+.ui-icon-arrowstop-1-e {
+ background-position: -208px -32px; }
+
+.ui-icon-arrowstop-1-s {
+ background-position: -224px -32px; }
+
+.ui-icon-arrowstop-1-w {
+ background-position: -240px -32px; }
+
+.ui-icon-arrowthick-1-n {
+ background-position: 0 -48px; }
+
+.ui-icon-arrowthick-1-ne {
+ background-position: -16px -48px; }
+
+.ui-icon-arrowthick-1-e {
+ background-position: -32px -48px; }
+
+.ui-icon-arrowthick-1-se {
+ background-position: -48px -48px; }
+
+.ui-icon-arrowthick-1-s {
+ background-position: -64px -48px; }
+
+.ui-icon-arrowthick-1-sw {
+ background-position: -80px -48px; }
+
+.ui-icon-arrowthick-1-w {
+ background-position: -96px -48px; }
+
+.ui-icon-arrowthick-1-nw {
+ background-position: -112px -48px; }
+
+.ui-icon-arrowthick-2-n-s {
+ background-position: -128px -48px; }
+
+.ui-icon-arrowthick-2-ne-sw {
+ background-position: -144px -48px; }
+
+.ui-icon-arrowthick-2-e-w {
+ background-position: -160px -48px; }
+
+.ui-icon-arrowthick-2-se-nw {
+ background-position: -176px -48px; }
+
+.ui-icon-arrowthickstop-1-n {
+ background-position: -192px -48px; }
+
+.ui-icon-arrowthickstop-1-e {
+ background-position: -208px -48px; }
+
+.ui-icon-arrowthickstop-1-s {
+ background-position: -224px -48px; }
+
+.ui-icon-arrowthickstop-1-w {
+ background-position: -240px -48px; }
+
+.ui-icon-arrowreturnthick-1-w {
+ background-position: 0 -64px; }
+
+.ui-icon-arrowreturnthick-1-n {
+ background-position: -16px -64px; }
+
+.ui-icon-arrowreturnthick-1-e {
+ background-position: -32px -64px; }
+
+.ui-icon-arrowreturnthick-1-s {
+ background-position: -48px -64px; }
+
+.ui-icon-arrowreturn-1-w {
+ background-position: -64px -64px; }
+
+.ui-icon-arrowreturn-1-n {
+ background-position: -80px -64px; }
+
+.ui-icon-arrowreturn-1-e {
+ background-position: -96px -64px; }
+
+.ui-icon-arrowreturn-1-s {
+ background-position: -112px -64px; }
+
+.ui-icon-arrowrefresh-1-w {
+ background-position: -128px -64px; }
+
+.ui-icon-arrowrefresh-1-n {
+ background-position: -144px -64px; }
+
+.ui-icon-arrowrefresh-1-e {
+ background-position: -160px -64px; }
+
+.ui-icon-arrowrefresh-1-s {
+ background-position: -176px -64px; }
+
+.ui-icon-arrow-4 {
+ background-position: 0 -80px; }
+
+.ui-icon-arrow-4-diag {
+ background-position: -16px -80px; }
+
+.ui-icon-extlink {
+ background-position: -32px -80px; }
+
+.ui-icon-newwin {
+ background-position: -48px -80px; }
+
+.ui-icon-refresh {
+ background-position: -64px -80px; }
+
+.ui-icon-shuffle {
+ background-position: -80px -80px; }
+
+.ui-icon-transfer-e-w {
+ background-position: -96px -80px; }
+
+.ui-icon-transferthick-e-w {
+ background-position: -112px -80px; }
+
+.ui-icon-folder-collapsed {
+ background-position: 0 -96px; }
+
+.ui-icon-folder-open {
+ background-position: -16px -96px; }
+
+.ui-icon-document {
+ background-position: -32px -96px; }
+
+.ui-icon-document-b {
+ background-position: -48px -96px; }
+
+.ui-icon-note {
+ background-position: -64px -96px; }
+
+.ui-icon-mail-closed {
+ background-position: -80px -96px; }
+
+.ui-icon-mail-open {
+ background-position: -96px -96px; }
+
+.ui-icon-suitcase {
+ background-position: -112px -96px; }
+
+.ui-icon-comment {
+ background-position: -128px -96px; }
+
+.ui-icon-person {
+ background-position: -144px -96px; }
+
+.ui-icon-print {
+ background-position: -160px -96px; }
+
+.ui-icon-trash {
+ background-position: -176px -96px; }
+
+.ui-icon-locked {
+ background-position: -192px -96px; }
+
+.ui-icon-unlocked {
+ background-position: -208px -96px; }
+
+.ui-icon-bookmark {
+ background-position: -224px -96px; }
+
+.ui-icon-tag {
+ background-position: -240px -96px; }
+
+.ui-icon-home {
+ background-position: 0 -112px; }
+
+.ui-icon-flag {
+ background-position: -16px -112px; }
+
+.ui-icon-calendar {
+ background-position: -32px -112px; }
+
+.ui-icon-cart {
+ background-position: -48px -112px; }
+
+.ui-icon-pencil {
+ background-position: -64px -112px; }
+
+.ui-icon-clock {
+ background-position: -80px -112px; }
+
+.ui-icon-disk {
+ background-position: -96px -112px; }
+
+.ui-icon-calculator {
+ background-position: -112px -112px; }
+
+.ui-icon-zoomin {
+ background-position: -128px -112px; }
+
+.ui-icon-zoomout {
+ background-position: -144px -112px; }
+
+.ui-icon-search {
+ background-position: -160px -112px; }
+
+.ui-icon-wrench {
+ background-position: -176px -112px; }
+
+.ui-icon-gear {
+ background-position: -192px -112px; }
+
+.ui-icon-heart {
+ background-position: -208px -112px; }
+
+.ui-icon-star {
+ background-position: -224px -112px; }
+
+.ui-icon-link {
+ background-position: -240px -112px; }
+
+.ui-icon-cancel {
+ background-position: 0 -128px; }
+
+.ui-icon-plus {
+ background-position: -16px -128px; }
+
+.ui-icon-plusthick {
+ background-position: -32px -128px; }
+
+.ui-icon-minus {
+ background-position: -48px -128px; }
+
+.ui-icon-minusthick {
+ background-position: -64px -128px; }
+
+.ui-icon-close {
+ background-position: -80px -128px; }
+
+.ui-icon-closethick {
+ background-position: -96px -128px; }
+
+.ui-icon-key {
+ background-position: -112px -128px; }
+
+.ui-icon-lightbulb {
+ background-position: -128px -128px; }
+
+.ui-icon-scissors {
+ background-position: -144px -128px; }
+
+.ui-icon-clipboard {
+ background-position: -160px -128px; }
+
+.ui-icon-copy {
+ background-position: -176px -128px; }
+
+.ui-icon-contact {
+ background-position: -192px -128px; }
+
+.ui-icon-image {
+ background-position: -208px -128px; }
+
+.ui-icon-video {
+ background-position: -224px -128px; }
+
+.ui-icon-script {
+ background-position: -240px -128px; }
+
+.ui-icon-alert {
+ background-position: 0 -144px; }
+
+.ui-icon-info {
+ background-position: -16px -144px; }
+
+.ui-icon-notice {
+ background-position: -32px -144px; }
+
+.ui-icon-help {
+ background-position: -48px -144px; }
+
+.ui-icon-check {
+ background-position: -64px -144px; }
+
+.ui-icon-bullet {
+ background-position: -80px -144px; }
+
+.ui-icon-radio-off {
+ background-position: -96px -144px; }
+
+.ui-icon-radio-on {
+ background-position: -112px -144px; }
+
+.ui-icon-pin-w {
+ background-position: -128px -144px; }
+
+.ui-icon-pin-s {
+ background-position: -144px -144px; }
+
+.ui-icon-play {
+ background-position: 0 -160px; }
+
+.ui-icon-pause {
+ background-position: -16px -160px; }
+
+.ui-icon-seek-next {
+ background-position: -32px -160px; }
+
+.ui-icon-seek-prev {
+ background-position: -48px -160px; }
+
+.ui-icon-seek-end {
+ background-position: -64px -160px; }
+
+.ui-icon-seek-start {
+ background-position: -80px -160px; }
+
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first {
+ background-position: -80px -160px; }
+
+.ui-icon-stop {
+ background-position: -96px -160px; }
+
+.ui-icon-eject {
+ background-position: -112px -160px; }
+
+.ui-icon-volume-off {
+ background-position: -128px -160px; }
+
+.ui-icon-volume-on {
+ background-position: -144px -160px; }
+
+.ui-icon-power {
+ background-position: 0 -176px; }
+
+.ui-icon-signal-diag {
+ background-position: -16px -176px; }
+
+.ui-icon-signal {
+ background-position: -32px -176px; }
+
+.ui-icon-battery-0 {
+ background-position: -48px -176px; }
+
+.ui-icon-battery-1 {
+ background-position: -64px -176px; }
+
+.ui-icon-battery-2 {
+ background-position: -80px -176px; }
+
+.ui-icon-battery-3 {
+ background-position: -96px -176px; }
+
+.ui-icon-circle-plus {
+ background-position: 0 -192px; }
+
+.ui-icon-circle-minus {
+ background-position: -16px -192px; }
+
+.ui-icon-circle-close {
+ background-position: -32px -192px; }
+
+.ui-icon-circle-triangle-e {
+ background-position: -48px -192px; }
+
+.ui-icon-circle-triangle-s {
+ background-position: -64px -192px; }
+
+.ui-icon-circle-triangle-w {
+ background-position: -80px -192px; }
+
+.ui-icon-circle-triangle-n {
+ background-position: -96px -192px; }
+
+.ui-icon-circle-arrow-e {
+ background-position: -112px -192px; }
+
+.ui-icon-circle-arrow-s {
+ background-position: -128px -192px; }
+
+.ui-icon-circle-arrow-w {
+ background-position: -144px -192px; }
+
+.ui-icon-circle-arrow-n {
+ background-position: -160px -192px; }
+
+.ui-icon-circle-zoomin {
+ background-position: -176px -192px; }
+
+.ui-icon-circle-zoomout {
+ background-position: -192px -192px; }
+
+.ui-icon-circle-check {
+ background-position: -208px -192px; }
+
+.ui-icon-circlesmall-plus {
+ background-position: 0 -208px; }
+
+.ui-icon-circlesmall-minus {
+ background-position: -16px -208px; }
+
+.ui-icon-circlesmall-close {
+ background-position: -32px -208px; }
+
+.ui-icon-squaresmall-plus {
+ background-position: -48px -208px; }
+
+.ui-icon-squaresmall-minus {
+ background-position: -64px -208px; }
+
+.ui-icon-squaresmall-close {
+ background-position: -80px -208px; }
+
+.ui-icon-grip-dotted-vertical {
+ background-position: 0 -224px; }
+
+.ui-icon-grip-dotted-horizontal {
+ background-position: -16px -224px; }
+
+.ui-icon-grip-solid-vertical {
+ background-position: -32px -224px; }
+
+.ui-icon-grip-solid-horizontal {
+ background-position: -48px -224px; }
+
+.ui-icon-gripsmall-diagonal-se {
+ background-position: -64px -224px; }
+
+.ui-icon-grip-diagonal-se {
+ background-position: -80px -224px; }
+
+/* Misc visuals
+----------------------------------*/
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
+ -moz-border-radius-topleft: 2px;
+ -webkit-border-top-left-radius: 2px;
+ -khtml-border-top-left-radius: 2px;
+ border-top-left-radius: 2px; }
+
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
+ -moz-border-radius-topright: 2px;
+ -webkit-border-top-right-radius: 2px;
+ -khtml-border-top-right-radius: 2px;
+ border-top-right-radius: 2px; }
+
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
+ -moz-border-radius-bottomleft: 2px;
+ -webkit-border-bottom-left-radius: 2px;
+ -khtml-border-bottom-left-radius: 2px;
+ border-bottom-left-radius: 2px; }
+
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
+ -moz-border-radius-bottomright: 2px;
+ -webkit-border-bottom-right-radius: 2px;
+ -khtml-border-bottom-right-radius: 2px;
+ border-bottom-right-radius: 2px; }
+
+/* Overlays */
+.ui-widget-overlay {
+ background: #eeeeee url(../images/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x;
+ opacity: .80;
+ filter: Alpha(Opacity=80); }
+
+.ui-widget-shadow {
+ margin: -4px 0 0 -4px;
+ padding: 4px;
+ background: #aaaaaa url(../images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
+ opacity: .60;
+ filter: Alpha(Opacity=60);
+ -moz-border-radius: 0px;
+ -khtml-border-radius: 0px;
+ -webkit-border-radius: 0px;
+ border-radius: 0px; }
+
+ /*
+* jQuery UI Resizable 1.8.16
+*
+* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+* http://docs.jquery.com/UI/Resizable#theming
+*/
+.ui-resizable {
+ position: relative; }
+
+.ui-resizable-handle {
+ position: absolute;
+ font-size: 0.1px;
+ z-index: 99999;
+ display: block; }
+
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle {
+ display: none; }
+
+.ui-resizable-n {
+ cursor: n-resize;
+ height: 7px;
+ width: 100%;
+ top: -5px;
+ left: 0; }
+
+.ui-resizable-s {
+ cursor: s-resize;
+ height: 7px;
+ width: 100%;
+ bottom: -5px;
+ left: 0; }
+
+.ui-resizable-e {
+ cursor: e-resize;
+ width: 7px;
+ right: -5px;
+ top: 0;
+ height: 100%; }
+
+.ui-resizable-w {
+ cursor: w-resize;
+ width: 7px;
+ left: -5px;
+ top: 0;
+ height: 100%; }
+
+.ui-resizable-se {
+ cursor: se-resize;
+ width: 12px;
+ height: 12px;
+ right: 1px;
+ bottom: 1px; }
+
+.ui-resizable-sw {
+ cursor: sw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ bottom: -5px; }
+
+.ui-resizable-nw {
+ cursor: nw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ top: -5px; }
+
+.ui-resizable-ne {
+ cursor: ne-resize;
+ width: 9px;
+ height: 9px;
+ right: -5px;
+ top: -5px; }
+
+ /*
+* jQuery UI Selectable 1.8.16
+*
+* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+* http://docs.jquery.com/UI/Selectable#theming
+*/
+.ui-selectable-helper {
+ position: absolute;
+ z-index: 100;
+ border: 1px dotted black; }
+
+/*
+ * jQuery UI Accordion 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion {
+ width: 100%; }
+
+.ui-accordion .ui-accordion-header {
+ cursor: pointer;
+ position: relative;
+ margin-top: 1px;
+ zoom: 1; }
+
+.ui-accordion .ui-accordion-li-fix {
+ display: inline; }
+
+.ui-accordion .ui-accordion-header-active {
+ border-bottom: 0 !important; }
+
+.ui-accordion .ui-accordion-header a {
+ display: block;
+ font-size: 1em;
+ padding: .5em .5em .5em .7em; }
+
+.ui-accordion-icons .ui-accordion-header a {
+ padding-left: 2.2em; }
+
+.ui-accordion .ui-accordion-header .ui-icon {
+ position: absolute;
+ left: .5em;
+ top: 50%;
+ margin-top: -8px; }
+
+.ui-accordion .ui-accordion-content {
+ padding: 1em 2.2em;
+ border-top: 0;
+ margin-top: -2px;
+ position: relative;
+ margin-bottom: 2px;
+ overflow: auto;
+ display: none;
+ zoom: 1; }
+
+.ui-accordion .ui-accordion-content-active {
+ display: block; }
+
+/*
+ * jQuery UI Autocomplete 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete {
+ position: absolute;
+ cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete {
+ width: 1px; }
+
+/* without this, the menu expands to 100% in IE6 */
+/*
+ * jQuery UI Menu 1.8.16
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style: none;
+ padding: 2px;
+ margin: 0;
+ display: block;
+ float: left; }
+
+.ui-menu .ui-menu {
+ margin-top: -3px; }
+
+.ui-menu .ui-menu-item {
+ margin: 0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%; }
+
+.ui-menu .ui-menu-item a {
+ text-decoration: none;
+ display: block;
+ padding: .2em .4em;
+ line-height: 1.5;
+ zoom: 1; }
+
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px; }
+
+/*
+ * jQuery UI Button 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button {
+ display: inline-block;
+ position: relative;
+ padding: 0;
+ margin-right: .1em;
+ text-decoration: none !important;
+ cursor: pointer;
+ text-align: center;
+ zoom: 1;
+ overflow: visible; }
+
+/* the overflow property removes extra width in IE */
+.ui-button-icon-only {
+ width: 2.2em; }
+
+/* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only {
+ width: 2.4em; }
+
+/* button elements seem to need a little more width */
+.ui-button-icons-only {
+ width: 3.4em; }
+
+button.ui-button-icons-only {
+ width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text {
+ display: block;
+ line-height: 1.4; }
+
+.ui-button-text-only .ui-button-text {
+ padding: .4em 1em; }
+
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text {
+ padding: .4em;
+ text-indent: -9999999px; }
+
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text {
+ padding: .4em 1em .4em 2.1em; }
+
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text {
+ padding: .4em 2.1em .4em 1em; }
+
+.ui-button-text-icons .ui-button-text {
+ padding-left: 2.1em;
+ padding-right: 2.1em; }
+
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+ padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px; }
+
+.ui-button-icon-only .ui-icon {
+ left: 50%;
+ margin-left: -8px; }
+
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary {
+ left: .5em; }
+
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary {
+ right: .5em; }
+
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary {
+ right: .5em; }
+
+/*button sets*/
+.ui-buttonset {
+ margin-right: 7px; }
+
+.ui-buttonset .ui-button {
+ margin-left: 0;
+ margin-right: -0.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0; }
+
+/* reset extra padding in Firefox */
+/*
+ * jQuery UI Dialog 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog {
+ position: absolute;
+ padding: .2em;
+ width: 300px;
+ overflow: hidden; }
+
+.ui-dialog .ui-dialog-titlebar {
+ padding: .4em 1em;
+ position: relative; }
+
+.ui-dialog .ui-dialog-title {
+ float: left;
+ margin: .1em 16px .1em 0; }
+
+.ui-dialog .ui-dialog-titlebar-close {
+ position: absolute;
+ right: .3em;
+ top: 50%;
+ width: 19px;
+ margin: -10px 0 0 0;
+ padding: 1px;
+ height: 18px; }
+
+.ui-dialog .ui-dialog-titlebar-close span {
+ display: block;
+ margin: 1px; }
+
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus {
+ padding: 0; }
+
+.ui-dialog .ui-dialog-content {
+ position: relative;
+ border: 0;
+ padding: .5em 1em;
+ background: none;
+ overflow: auto;
+ zoom: 1; }
+
+.ui-dialog .ui-dialog-buttonpane {
+ text-align: left;
+ border-width: 1px 0 0 0;
+ background-image: none;
+ margin: .5em 0 0 0;
+ padding: .3em 1em .5em .4em; }
+
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+ float: right; }
+
+.ui-dialog .ui-dialog-buttonpane button {
+ margin: .5em .4em .5em 0;
+ cursor: pointer; }
+
+.ui-dialog .ui-resizable-se {
+ width: 14px;
+ height: 14px;
+ right: 3px;
+ bottom: 3px; }
+
+.ui-draggable .ui-dialog-titlebar {
+ cursor: move; }
+
+/*
+ * jQuery UI Slider 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider {
+ position: relative;
+ text-align: left; }
+
+.ui-slider .ui-slider-handle {
+ position: absolute;
+ z-index: 2;
+ width: 1.2em;
+ height: 1.2em;
+ cursor: default; }
+
+.ui-slider .ui-slider-range {
+ position: absolute;
+ z-index: 1;
+ font-size: .7em;
+ display: block;
+ border: 0;
+ background-position: 0 0; }
+
+.ui-slider-horizontal {
+ height: .8em; }
+
+.ui-slider-horizontal .ui-slider-handle {
+ top: -0.3em;
+ margin-left: -0.6em; }
+
+.ui-slider-horizontal .ui-slider-range {
+ top: 0;
+ height: 100%; }
+
+.ui-slider-horizontal .ui-slider-range-min {
+ left: 0; }
+
+.ui-slider-horizontal .ui-slider-range-max {
+ right: 0; }
+
+.ui-slider-vertical {
+ width: .8em;
+ height: 100px; }
+
+.ui-slider-vertical .ui-slider-handle {
+ left: -0.3em;
+ margin-left: 0;
+ margin-bottom: -0.6em; }
+
+.ui-slider-vertical .ui-slider-range {
+ left: 0;
+ width: 100%; }
+
+.ui-slider-vertical .ui-slider-range-min {
+ bottom: 0; }
+
+.ui-slider-vertical .ui-slider-range-max {
+ top: 0; }
+
+ /*
+* jQuery UI Tabs 1.8.16
+*
+* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+* http://docs.jquery.com/UI/Tabs#theming
+*/
+.ui-tabs {
+ position: relative;
+ padding: .2em;
+ zoom: 1; }
+
+/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav {
+ margin: 0;
+ padding: .2em .2em 0; }
+
+.ui-tabs .ui-tabs-nav li {
+ list-style: none;
+ float: left;
+ position: relative;
+ top: 1px;
+ margin: 0 .2em 1px 0;
+ border-bottom: 0 !important;
+ padding: 0;
+ white-space: nowrap; }
+
+.ui-tabs .ui-tabs-nav li a {
+ float: left;
+ padding: .5em 1em;
+ text-decoration: none; }
+
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
+ margin-bottom: 0;
+ padding-bottom: 1px; }
+
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a {
+ cursor: text; }
+
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a {
+ cursor: pointer; }
+
+/* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel {
+ display: block;
+ border-width: 0;
+ padding: 1em 1.4em;
+ background: none; }
+
+.ui-tabs .ui-tabs-hide {
+ display: none !important; }
+
+/*
+ * jQuery UI Datepicker 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker {
+ width: 17em;
+ padding: .2em .2em 0;
+ display: none; }
+
+.ui-datepicker .ui-datepicker-header {
+ position: relative;
+ padding: .2em 0; }
+
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next {
+ position: absolute;
+ top: 2px;
+ width: 1.8em;
+ height: 1.8em; }
+
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover {
+ top: 1px; }
+
+.ui-datepicker .ui-datepicker-prev {
+ left: 2px; }
+
+.ui-datepicker .ui-datepicker-next {
+ right: 2px; }
+
+.ui-datepicker .ui-datepicker-prev-hover {
+ left: 1px; }
+
+.ui-datepicker .ui-datepicker-next-hover {
+ right: 1px; }
+
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span {
+ display: block;
+ position: absolute;
+ left: 50%;
+ margin-left: -8px;
+ top: 50%;
+ margin-top: -8px; }
+
+.ui-datepicker .ui-datepicker-title {
+ margin: 0 2.3em;
+ line-height: 1.8em;
+ text-align: center; }
+
+.ui-datepicker .ui-datepicker-title select {
+ font-size: 1em;
+ margin: 1px 0; }
+
+.ui-datepicker select.ui-datepicker-month-year {
+ width: 100%; }
+
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+ width: 49%; }
+
+.ui-datepicker table {
+ width: 100%;
+ font-size: .9em;
+ border-collapse: collapse;
+ margin: 0 0 .4em; }
+
+.ui-datepicker th {
+ padding: .7em .3em;
+ text-align: center;
+ font-weight: bold;
+ border: 0; }
+
+.ui-datepicker td {
+ border: 0;
+ padding: 1px; }
+
+.ui-datepicker td span, .ui-datepicker td a {
+ display: block;
+ padding: .2em;
+ text-align: right;
+ text-decoration: none; }
+
+.ui-datepicker .ui-datepicker-buttonpane {
+ background-image: none;
+ margin: .7em 0 0 0;
+ padding: 0 .2em;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 0; }
+
+.ui-datepicker .ui-datepicker-buttonpane button {
+ float: right;
+ margin: .5em .2em .4em;
+ cursor: pointer;
+ padding: .2em .6em .3em .6em;
+ width: auto;
+ overflow: visible; }
+
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+ float: left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+ width: auto; }
+
+.ui-datepicker-multi .ui-datepicker-group {
+ float: left; }
+
+.ui-datepicker-multi .ui-datepicker-group table {
+ width: 95%;
+ margin: 0 auto .4em; }
+
+.ui-datepicker-multi-2 .ui-datepicker-group {
+ width: 50%; }
+
+.ui-datepicker-multi-3 .ui-datepicker-group {
+ width: 33.3%; }
+
+.ui-datepicker-multi-4 .ui-datepicker-group {
+ width: 25%; }
+
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header {
+ border-left-width: 0; }
+
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+ border-left-width: 0; }
+
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+ clear: left; }
+
+.ui-datepicker-row-break {
+ clear: both;
+ width: 100%;
+ font-size: 0em; }
+
+/* RTL support */
+.ui-datepicker-rtl {
+ direction: rtl; }
+
+.ui-datepicker-rtl .ui-datepicker-prev {
+ right: 2px;
+ left: auto; }
+
+.ui-datepicker-rtl .ui-datepicker-next {
+ left: 2px;
+ right: auto; }
+
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+ right: 1px;
+ left: auto; }
+
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+ left: 1px;
+ right: auto; }
+
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+ clear: right; }
+
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+ float: left; }
+
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current {
+ float: right; }
+
+.ui-datepicker-rtl .ui-datepicker-group {
+ float: right; }
+
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header {
+ border-right-width: 0;
+ border-left-width: 1px; }
+
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+ border-right-width: 0;
+ border-left-width: 1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none;
+ /*sorry for IE5*/
+ display/**/: block;
+ /*sorry for IE5*/
+ position: absolute;
+ /*must have*/
+ z-index: -1;
+ /*must have*/
+ filter: mask();
+ /*must have*/
+ top: -4px;
+ /*must have*/
+ left: -4px;
+ /*must have*/
+ width: 200px;
+ /*must have*/
+ height: 200px;
+ /*must have*/ }
+
+/*
+* jQuery UI Progressbar 1.8.16
+*
+* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+* http://docs.jquery.com/UI/Progressbar#theming
+*/
+.ui-progressbar {
+ height: 2em;
+ text-align: left; }
+
+.ui-progressbar .ui-progressbar-value {
+ margin: -1px;
+ height: 100%; }
+
+.ui-tooltip, .qtip {
+ position: absolute;
+ left: -28000px;
+ top: -28000px;
+ display: none;
+ max-width: 280px;
+ min-width: 50px;
+ font-size: 10.5px;
+ line-height: 12px; }
+
+.ui-tooltip-fluid {
+ display: block;
+ visibility: hidden;
+ position: static!important;
+ float: left!important; }
+
+.ui-tooltip-content {
+ position: relative;
+ padding: 5px 9px;
+ overflow: hidden;
+ border: 1px solid #000001;
+ text-align: left;
+ word-wrap: break-word;
+ overflow: hidden; }
+
+.ui-tooltip-titlebar {
+ position: relative;
+ min-height: 14px;
+ padding: 5px 35px 5px 10px;
+ overflow: hidden;
+ border: 1px solid #000001;
+ border-width: 1px 1px 0;
+ font-weight: bold; }
+
+.ui-tooltip-titlebar + .ui-tooltip-content {
+ border-top-width: 0!important; }
+
+/*Default close button class */
+.ui-tooltip-titlebar .ui-state-default {
+ position: absolute;
+ right: 4px;
+ top: 50%;
+ margin-top: -9px;
+ cursor: pointer;
+ outline: medium none;
+ border-width: 1px;
+ border-style: solid; }
+
+* html .ui-tooltip-titlebar .ui-state-default {
+ top: 16px; }
+
+.ui-tooltip-titlebar .ui-icon, .ui-tooltip-icon .ui-icon {
+ display: block;
+ text-indent: -1000em; }
+
+.ui-tooltip-icon, .ui-tooltip-icon .ui-icon {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px; }
+
+.ui-tooltip-icon .ui-icon {
+ width: 18px;
+ height: 14px;
+ text-align: center;
+ text-indent: 0;
+ font: normal bold 10px/13px Tahoma, sans-serif;
+ color: inherit;
+ background: transparent none no-repeat -100em -100em; }
+
+/*Default tooltip style */
+.ui-tooltip-default .ui-tooltip-titlebar, .ui-tooltip-default .ui-tooltip-content {
+ border-color: #F1D031;
+ background-color: #FFFFA3;
+ color: #555; }
+
+.ui-tooltip-default .ui-tooltip-titlebar {
+ background-color: #FFEF93; }
+
+.ui-tooltip-default .ui-tooltip-icon {
+ border-color: #CCC;
+ background: #F1F1F1;
+ color: #777; }
+
+.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover {
+ border-color: #AAA;
+ color: #111; }
+
+div.book-wrapper section.book-sidebar {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ div.book-wrapper section.book-sidebar ul#booknav {
+ font-size: 12px; }
+ div.book-wrapper section.book-sidebar ul#booknav a {
+ color: #000; }
+ div.book-wrapper section.book-sidebar ul#booknav a:hover {
+ color: #666; }
+ div.book-wrapper section.book-sidebar ul#booknav li {
+ background: none;
+ padding-left: 30px; }
+ div.book-wrapper section.book-sidebar ul#booknav li div.hitarea {
+ background-image: url("../images/treeview-default.gif");
+ margin-left: -22px;
+ position: relative;
+ top: 4px; }
+ div.book-wrapper section.book-sidebar ul#booknav li div.hitarea:hover {
+ filter: alpha(opacity=60);
+ opacity: 0.6; }
+ div.book-wrapper section.book-sidebar ul#booknav li ul {
+ background: none; }
+ div.book-wrapper section.book-sidebar ul#booknav > li {
+ border-bottom: 1px solid #d3d3d3;
+ -webkit-box-shadow: 0 1px 0 #eeeeee;
+ -moz-box-shadow: 0 1px 0 #eeeeee;
+ box-shadow: 0 1px 0 #eeeeee;
+ padding: 7px 7px 7px 30px; }
+div.book-wrapper section.book nav a {
+ padding: 0 22.652px; }
+div.book-wrapper section.book nav ul li {
+ background-color: #f2e9c3; }
+ div.book-wrapper section.book nav ul li.last {
+ display: block;
+ float: left; }
+ div.book-wrapper section.book nav ul li.last a {
+ border-left: 0;
+ border-right: 1px solid #e4d080;
+ -webkit-box-shadow: inset -1px 0 0 #faf7e9;
+ -moz-box-shadow: inset -1px 0 0 #faf7e9;
+ box-shadow: inset -1px 0 0 #faf7e9; }
+ div.book-wrapper section.book nav ul li.next {
+ display: block;
+ float: right; }
+ div.book-wrapper section.book nav ul li:hover {
+ background: none; }
+div.book-wrapper section.book nav.bottom-nav {
+ border-bottom: 0;
+ border-top: 1px solid #EDDFAA;
+ margin-bottom: -22.652px;
+ margin-top: 22.652px; }
+div.book-wrapper section.book section.page {
+ text-align: center; }
+ div.book-wrapper section.book section.page img {
+ border: 1px solid #dddddd;
+ max-width: 100%; }
+div.book-wrapper.closed section.book-sidebar {
+ width: 3.077%; }
+ div.book-wrapper.closed section.book-sidebar header#open_close_accordion {
+ padding: 0; }
+ div.book-wrapper.closed section.book-sidebar header#open_close_accordion a {
+ background-image: url("../images/slide-right-icon.png"); }
+ div.book-wrapper.closed section.book-sidebar header#open_close_accordion h2 {
+ padding: 0;
+ visibility: hidden;
+ width: 10px; }
+ div.book-wrapper.closed section.book-sidebar ul#booknav {
+ max-height: 100px;
+ overflow: hidden;
+ padding: 0;
+ visibility: hidden;
+ width: 10px; }
+div.book-wrapper.closed section.course-content {
+ width: 97.773%; }
From 9d638d2ac09266f5d5eb4a7928ff69c9b22ecd56 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Wed, 11 Jul 2012 16:12:33 -0400
Subject: [PATCH 29/55] Added some more style for cal view and nav bar
---
cms/static/img/menu.png | Bin 0 -> 95 bytes
cms/static/img/noise.png | Bin 0 -> 4878 bytes
cms/static/sass/_base.scss | 18 +++++---
cms/static/sass/_calendar.scss | 28 +++++++++----
cms/static/sass/_layout.scss | 66 ++++++++++++++++++++++++------
cms/templates/widgets/header.html | 5 ++-
6 files changed, 90 insertions(+), 27 deletions(-)
create mode 100644 cms/static/img/menu.png
create mode 100644 cms/static/img/noise.png
diff --git a/cms/static/img/menu.png b/cms/static/img/menu.png
new file mode 100644
index 0000000000000000000000000000000000000000..7449b34c1c0c2e11ddd7e4f353cf7b86e3071dc5
GIT binary patch
literal 95
zcmeAS@N?(olHy`uVBq!ia0vp@K+MI#1|;*}T{!}z)I41rLn>~)J-<+pfr01Hfp_+~
tvR#Xf8MY~Xa!qsGdGv&y)Bh_rvL~k$BV(q8tni4BTet
z;0XG7o__1IvCyCE@~~w3AVM;AB-!HKNr5Oo4113zL1QgmELjt&BJUo42Kw2XO2=H`+0Uflh)T{_5
z7_8^HU_Xp)u(cgJ*c+|q20U#5&?iIb1UL){1t8;me2Gvp4EPr>ls^Cc8Vm&dWkT|X
z0skA6qt$tU3EmF_&<3fgqSbWN06OX*bxkb@1fl}aP*Ya}t7(AMHB{9hP)!Y}ni}Bm
z3rP3o=jIMYz|Z{ci@t&Zu_O`!3I+!T27&@LL3lq8u)3a}-fs>K4OO~@Dly2Hgd(f@
z5~cqzz%fL$pC^IjiT4HkW<*~QZOf)sLG|s4-m}r>j{=vfWXn!2Wm-Gkg_77G=?O(CKrGO*QJ;O16o&gxQ
zGk$m+;IA!1J^wux_`mY~jdlCiSkz7b6$_>Z1O8pu|5fNeujuOeJ^e?v^u<5I$N19K
z?njq(=lX0E0|RfA8QjQ@{9)w*d!6-r;V$0BJb@tvL5W;Fcy8n^IrFSMgoc2uxl(_D
z2K;U^w?J+rLUhQG$y`HQK_fr69-DJ`5YXJ{zx_kx(JJLm2yOFQNEhv4^O(!>720L*
z$1-MowLTLXKb9*f4UM#xNvp>O)3mWNr!hPv|I@(Z8C>H^O}SZ`oXA*j2AJmlCUf?O
zjqYqrDFr`SQ?|eO06+Dv*!EyOQBZm6QON2S^9<061ewYR@g6ND(Ar`-uS6a>>ip~Q
zpuL`viDhSn8!|PV$~eHwXtuSB;-Hc;LpiB?Em5I
zDcVC(eO}aLE&eKHW$=l~S7SY0~R{=%n?vy8Ji+d{99)};+
zj~PslH25#uoh`j35%TT18e`LP61au%^V;gCjH}yDENuaW*#YMMp$k2?QIfbb)Xl|y
zqU81O7b;Ke<@7BXxmUoWcdwR13^a_a5H3YY2YTkjoQ_DT5lxz6UUbVb{)
z?9h$Zt4oi=x0iVJ7LEn}I{2}FJ=?;{E?w#3)IN%FJCTwcGJHE8zE;L*gZXx9Cd
zUgpop*LP&w{h2{Vn30$r@^V@2_Tm
zjV2kia2&s=>GAeEfAHdckA`l^@Tn`|2V1YEeCt06QB1wVcV=(g9Sz@}@Hni626l;f
z)EPyy)MsgX@6GcX>>!`6rGKj)b6G8KT=nag2r2a*DX^*|j95YH5&7nN%*pp%H@_|K
z1ubPSxrD4}|DZ
zo8dh72C7
ztw#yJRlOTMnrq4#NR4D=kz;(Q7Dqp39}YJ9z`pbjLcG5B{WaO(aP}tTw5;NL^z>|9+*m2S
z$=JV&x*rT~6Lhd^m$5muqD4uKjtF}m{&T&XwUGEFKO=5`Hg(J;1g8X_pSI+wVo5vN
zzGZE3t@4b3MV0LK+Q;>4Yokv1qv>ZbD>o&>c2HjTR4Xs5=BcYekMQ_$u~ro%6Ol*a
ziK@8Ph4su>4nYncV+zVp=qz2LffPZRR;%?oB&0hV>TiC~;@X+`r~;TgE=oU4kL|)e
z&sVea%aQe~v=Y05uDQML=B#71~k}R
zNTZ@CzYaqNWG7f#>)-AN3CpSSob_1Q)PW?KZ4gxX$8rLuIt#&sQeAhL#4Mlo5e
zm4YT24l>UCOC`?re)du+BARlU6>q){n(%IYOmW<&H(Sz`2GTW?8$A8zJSWg^>cbB9
zW-|jhX+9>pQAgNQRV6g8wuF9UQVvGyONRe^enTl`wo!+}d#2_3IIGZTMpRmah(jVP
zUwH3!zMhUau)w*2B_U31K8QXqBn#mBjJ0msa>$AH*X>FJ(NJKIYOFRfV+V>qTCUIfiwU5cC<>o?xuEfK^
zGdvS40H{%%C@790Z<>o4e@^mqRastfaaNHWf8M3lXC(1^jDbzGmi;3qLuO-zqdepl
zqY4ZBGOWfcSxu$wqz>}B<$Jt}EV1j!P2&5xd|H(j4;AdM>+vWPj0=4{b9cmxclUFE~ir!nDyvRiWmg+4$(1t
zml3-E?WJZ+BoneYL6!I+`KCC(oOa;qRPyk%7jU*%QZvlv=F#}pOXL19*JIdR)vL(c
zgEIG8dzAS4Ie0I8;jyvAMJkv^=Q7>Hnj?!0+&4P-ZQSyjsW-6dqD5bY2c(b=Uu>Ub
z=xZOp9R}{XbtXPqitU9GGMiw*ExRM%K9Upp&Lm*k-=U)G9_TYF7yP_nXy+s{NizaD
zsZvdqdh6zd_ewSC1|s?sSwkd6(X_~MJ|!h)8LwIBqPW9K1j|Dy8IitrcExY{TkmXP
z@6=vlDGI5%_cE(xoH(*0m?x{6>=m*4Na5G0OGhN`wi#rlr-d308tM--vWg$uAnSx8
zYDB~27t2Lty^U3hp{4%J`uzP>uk=&oR*wxu&bjF0oYNQ)@qVSP#U*N}#IU^T?-yJy
zDL5ZD#NMgI-*^Y1KTAAzsM{XQr1pD^Qx6P2HEVc
zk0`NQW+j|GFQi-zR^o$nQnelyYUqBwvDHCsEGOcD>7%{MD4v2FdhxnS`Rx&3*bEbu
z$GjMq%S4JcqPg^)3XdKa2xmJU1U><`qmIBSFxFCj#ng;j)uur!q!tj@tdIZ&i$Z
z_m#1?e!}shOe1mWt;=374fWASokGrjly91tzY=Wx2y9Snb|>dWepgk6{>ep!Fpqh}
z1+JQoadX?wB-vt96Uv}|*OM3WEA+3-0j%p_ewrL?4{=-()MwO7u<~TuC~6kx^mYCO
zdvj5X6=dpn+w~S71M=k3LUC;DH|5){8oca>U1In*gGUsSs!|eO%;u>W-j3H2JDXO9
z&AZHHc2q%lQT0j0>@D9*5i$M#0;WIItzX^81;{$xnM`BUyMn#{^U6oXS`}{Vo+rmM
z(e8c+McSG-_AFY-^<*m9)#8?ag}Vxfd+_efSI+A>mQnV<_&>SzIj0p33Nu78&l0EX
zz$s}jvjCh&qmsyg$TuInME33Kb!QMjRvR0o}o&JVwdWeS5f=6EXmaaRcy|PtwpTv
z#TeF=*iD3czOubDNzrw17vbop%?|{o7u`G^$es9ffal%0mA?528_sh&x8BLji`@w5
z?VgA_w)A~B0`cwH?nbB=JAGJgtRv7MBuAh)c~)r*TH=4rz}$OSDkKyW8>t^glam)7SG
zab8@C86wy#3uq@L1%+wlQZj6lj4}gp4
AivR!s
literal 0
HcmV?d00001
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 05014dbb7e..cb00dac83a 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -5,7 +5,7 @@ $body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida
$body-font-size: 14px;
$body-line-height: 20px;
-$light-blue: #f0f8fa;
+$light-blue: #f0f7fd;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
$orange: #f96e5b;
@@ -13,6 +13,14 @@ $yellow: #fff8af;
$cream: #F6EFD4;
$mit-red: #933;
+@mixin hide-text {
+ background-color: transparent;
+ border: 0;
+ color: transparent;
+ font: 0/0 a;
+ text-shadow: none;
+}
+
// Base html styles
html {
height: 100%;
@@ -122,10 +130,10 @@ textarea {
}
}
-.wip {
- outline: 1px solid #f00 !important;
- position: relative;
-}
+// .wip {
+// outline: 1px solid #f00 !important;
+// position: relative;
+// }
.hidden {
display: none;
diff --git a/cms/static/sass/_calendar.scss b/cms/static/sass/_calendar.scss
index 4070766617..35609b2d56 100644
--- a/cms/static/sass/_calendar.scss
+++ b/cms/static/sass/_calendar.scss
@@ -1,13 +1,15 @@
section.cal {
@include box-sizing(border-box);
@include clearfix;
- padding: 25px;
+ padding: 20px;
> header {
+ display: none;
@include clearfix;
margin-bottom: 10px;
opacity: .4;
@include transition;
+ text-shadow: 0 1px 0 #fff;
&:hover {
opacity: 1;
@@ -70,12 +72,15 @@ section.cal {
ol {
list-style: none;
@include clearfix;
- border-left: 1px solid lighten($dark-blue, 40%);
- border-top: 1px solid lighten($dark-blue, 40%);
+ border: 1px solid lighten( $dark-blue , 30% );
+ background: #FFF;
width: 100%;
@include box-sizing(border-box);
margin: 0;
padding: 0;
+ @include box-shadow(0 0 5px lighten($dark-blue, 45%));
+ @include border-radius(3px);
+ overflow: hidden;
> li {
border-right: 1px solid lighten($dark-blue, 40%);
@@ -84,6 +89,7 @@ section.cal {
float: left;
width: flex-grid(3) + ((flex-gutter() * 3) / 4);
background-color: $light-blue;
+ @include box-shadow(inset 0 0 0 1px lighten($light-blue, 8%));
&:hover {
li.create-module {
@@ -91,6 +97,10 @@ section.cal {
}
}
+ &:nth-child(4n) {
+ border-right: 0;
+ }
+
header {
border-bottom: 1px solid lighten($dark-blue, 40%);
@include box-shadow(0 2px 2px $light-blue);
@@ -128,6 +138,7 @@ section.cal {
color: #888;
border-bottom: 0;
font-size: 12px;
+ @include box-shadow(none);
}
}
}
@@ -138,9 +149,11 @@ section.cal {
padding: 0;
li {
- border-bottom: 1px solid darken($light-blue, 8%);
- position: relative;
+ border-bottom: 1px solid darken($light-blue, 6%);
+ // @include box-shadow(0 1px 0 lighten($light-blue, 4%));
overflow: hidden;
+ position: relative;
+ text-shadow: 0 1px 0 #fff;
&:hover {
background-color: lighten($yellow, 14%);
@@ -314,16 +327,13 @@ section.cal {
@include box-sizing(border-box);
opacity: .4;
@include transition();
- background: darken($light-blue, 2%);
&:hover {
opacity: 1;
width: flex-grid(5) + flex-gutter();
- background-color: transparent;
+ section.main-content {
width: flex-grid(7);
- opacity: .6;
}
}
@@ -340,6 +350,7 @@ section.cal {
display: block;
li {
+
ul {
display: inline;
}
@@ -351,6 +362,7 @@ section.cal {
li {
@include box-sizing(border-box);
width: 100%;
+ border-right: 0;
&.create-module {
display: none;
diff --git a/cms/static/sass/_layout.scss b/cms/static/sass/_layout.scss
index f4c9f63ea6..419f1df9d8 100644
--- a/cms/static/sass/_layout.scss
+++ b/cms/static/sass/_layout.scss
@@ -2,6 +2,8 @@ body {
@include clearfix();
height: 100%;
font: 14px $body-font-family;
+ background-color: lighten($dark-blue, 62%);
+ background-image: url('/static/img/noise.png');
> section {
display: table;
@@ -11,28 +13,53 @@ body {
> header {
background: $dark-blue;
+ @include background-image(url('/static/img/noise.png'), linear-gradient(lighten($dark-blue, 10%), $dark-blue));
+ border-bottom: 1px solid darken($dark-blue, 15%);
+ @include box-shadow(inset 0 -1px 0 lighten($dark-blue, 10%));
+ @include box-sizing(border-box);
color: #fff;
display: block;
float: none;
- padding: 8px 25px;
+ padding: 0 25px;
+ text-shadow: 0 -1px 0 darken($dark-blue, 15%);
width: 100%;
- @include box-sizing(border-box);
- -webkit-font-smoothing: antialiased;
nav {
@include clearfix;
- h2 {
- font-size: 14px;
- text-transform: uppercase;
+ > a {
+ @include hide-text;
+ background: url('/static/img/menu.png') 0 center no-repeat;
+ border-right: 1px solid darken($dark-blue, 10%);
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
+ display: block;
float: left;
- margin: 0 15px 0 0;
+ height: 19px;
+ padding: 8px 10px 8px 0;
+ width: 14px;
+
+ &:hover, &:focus {
+ opacity: .7;
+ }
+ }
+
+ h2 {
+ border-right: 1px solid darken($dark-blue, 10%);
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
+ float: left;
+ font-size: 14px;
+ margin: 0;
+ text-transform: uppercase;
+ -webkit-font-smoothing: antialiased;
a {
color: #fff;
+ padding: 8px 20px;
+ display: block;
&:hover {
- color: rgba(#fff, .6);
+ background-color: rgba(darken($dark-blue, 15%), .5);
+ color: $yellow;
}
}
}
@@ -48,21 +75,35 @@ body {
ul {
float: left;
margin: 0;
+ padding: 0;
+ @include clearfix;
&.user-nav {
float: right;
+ border-left: 1px solid darken($dark-blue, 10%);
}
li {
- @include inline-block();
+ border-right: 1px solid darken($dark-blue, 10%);
+ float: left;
+ @include box-shadow(1px 0 0 lighten($dark-blue, 10%));
a {
- padding: 8px 10px;
+ padding: 8px 20px;
display: block;
- margin: -8px 0;
&:hover {
- background-color: darken($dark-blue, 15%);
+ background-color: rgba(darken($dark-blue, 15%), .5);
+ color: $yellow;
+ }
+
+ &.new-module {
+ &:before {
+ @include inline-block;
+ content: "+";
+ font-weight: bold;
+ margin-right: 10px;
+ }
}
}
}
@@ -78,6 +119,7 @@ body {
float: left;
@include box-shadow( -2px 0 0 darken($light-blue, 3%));
@include transition();
+ background: #FFF;
}
}
}
diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html
index c1c05671fa..f9322fb13d 100644
--- a/cms/templates/widgets/header.html
+++ b/cms/templates/widgets/header.html
@@ -1,13 +1,14 @@
<%! from django.core.urlresolvers import reverse %>
+ Home
From d53e4bd38fc1ca1ef3cd2afcd05a0080b661cfcd Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Thu, 12 Jul 2012 14:28:13 -0400
Subject: [PATCH 30/55] Added more styles includeing the index page more color
changes and header styles
---
cms/static/img/content-types/module.png | Bin 0 -> 1138 bytes
cms/static/sass/_base.scss | 12 ++--
cms/static/sass/_content-types.scss | 5 ++
cms/static/sass/_index.scss | 80 ++++++++++++++++++++++++
cms/static/sass/_keyframes.scss | 27 ++++++++
cms/static/sass/_layout.scss | 4 +-
cms/static/sass/_section.scss | 3 +
cms/static/sass/_unit.scss | 65 ++++++++++++-------
cms/static/sass/base-style.scss | 3 +-
cms/templates/base.html | 2 +-
cms/templates/course_index.html | 1 +
cms/templates/index.html | 8 +++
12 files changed, 180 insertions(+), 30 deletions(-)
create mode 100644 cms/static/img/content-types/module.png
create mode 100644 cms/static/sass/_index.scss
create mode 100644 cms/static/sass/_keyframes.scss
diff --git a/cms/static/img/content-types/module.png b/cms/static/img/content-types/module.png
new file mode 100644
index 0000000000000000000000000000000000000000..643c12d1d99d9efb94d6e7f6149a0013444bd7ab
GIT binary patch
literal 1138
zcmbVMO-$2J9IpbyAWKjWiXrh)f?r{4yRF?;8Ek6@EU>YRMdppJeXt7suzj#WydWeZ
zTueN8F-D^|6B94SL?a|}&>JQuenc(!K76
zlMMtxxRZTi7OzL}(|E{*-}CJkm+{h!5_vRajG~fcK_aFY1qhOwGzPO!Ql_uGft>_V
zQ&e+#lur%tvY~k;N5@;%OpGRo&hD})$>R`#0vuEI2)XfmnFOj5A&1!%oiYVjRQqNu
zI5d;a$ur|}SRuQ+Kxdi91R6vVC~FhC&6gwOHZPC&j+i3Bwh9`LkQJx$sSFSd3j)^b
z_sBHE0FLuA0hZ&K4&b91A4TJv^DqIP<#=BZ>|7+aW+|h5R_xiag-;Q(h>*!sRH;<*
zmi%7B8l#wSIP7rvd>*Xfv8Qz;l|8!MR%H;OEnBLIR6_?2qf{^^QG~>vRzlFsRBD%4
zw|5eSQ%02~lVZFyrD;xF+uAnD!ar{8scq+`O-N;-ZA@A+uE%Iw6^wJYzad8vd&3V}
zDlUpNAsX_e26dDaBP9OfRaAwi{UMyiV1N$#XfDJsAv)ym3C1~&j)yoV?5lF@g%xNq
z7UF^l!5?QBCc%W+KrGJrX)(wK5($B=Vw1X!BwdD8yDGN3gBAD1@`42=WLP=Fn5cF@
zrf49;E*d5fhB$CGCCRGp2+lbLs>CZoOPzvBk7a0JJHx!XhX-`{Uy)a^%Kv1I!p=}m
zd;HZdRT1t%XS>_{_^>-ZP{%W4;o*380kz@5x|bAVx$>vN=a=8tYFsW?mn-+9X~EsR
zP}>pRJibu(b~Sc&7 header {
+ display: none;
+ }
+
+ > h1 {
+ font-weight: 300;
+ color: lighten($dark-blue, 40%);
+ text-shadow: 0 1px 0 #fff;
+ -webkit-font-smoothing: antialiased;
+ max-width: 600px;
+ text-align: center;
+ margin: 80px auto 30px;
+ }
+
+ section.main-container {
+ border-right: 3px;
+ background: #FFF;
+ max-width: 600px;
+ margin: 0 auto;
+ display: block;
+ @include box-sizing(border-box);
+ border: 1px solid lighten( $dark-blue , 30% );
+ @include border-radius(3px);
+ overflow: hidden;
+ @include bounce-in-animation(.8s);
+
+ header {
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+ @include linear-gradient(#fff, lighten($dark-blue, 62%));
+ @include clearfix();
+ @include box-shadow( 0 2px 0 $light-blue, inset 0 -1px 0 #fff);
+ text-shadow: 0 1px 0 #fff;
+
+ h1 {
+ font-size: 14px;
+ padding: 8px 20px;
+ float: left;
+ color: $dark-blue;
+ margin: 0;
+ }
+
+ a {
+ float: right;
+ padding: 8px 20px;
+ border-left: 1px solid lighten($dark-blue, 50%);
+ @include box-shadow( inset -1px 0 0 #fff);
+ font-weight: bold;
+ font-size: 22px;
+ line-height: 1;
+ color: $dark-blue;
+ }
+ }
+
+ ol {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+
+ li {
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+
+ a {
+ display: block;
+ padding: 10px 20px;
+
+ &:hover {
+ color: $dark-blue;
+ background: lighten($yellow, 10%);
+ text-shadow: 0 1px 0 #fff;
+ }
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+ }
+ }
+}
diff --git a/cms/static/sass/_keyframes.scss b/cms/static/sass/_keyframes.scss
new file mode 100644
index 0000000000..7661f18980
--- /dev/null
+++ b/cms/static/sass/_keyframes.scss
@@ -0,0 +1,27 @@
+@mixin bounce-in {
+ 0% {
+ opacity: 0;
+ @include transform(scale(.3));
+ }
+
+ 50% {
+ opacity: 1;
+ @include transform(scale(1.05));
+ }
+
+ 100% {
+ @include transform(scale(1));
+ }
+}
+
+@-moz-keyframes bounce-in { @include bounce-in(); }
+@-webkit-keyframes bounce-in { @include bounce-in(); }
+@-o-keyframes bounce-in { @include bounce-in(); }
+@keyframes bounce-in { @include bounce-in();}
+
+@mixin bounce-in-animation($duration, $timing: ease-in-out) {
+ @include animation-name(bounce-in);
+ @include animation-duration($duration);
+ @include animation-timing-function($timing);
+ @include animation-fill-mode(both);
+}
diff --git a/cms/static/sass/_layout.scss b/cms/static/sass/_layout.scss
index 419f1df9d8..43308a973c 100644
--- a/cms/static/sass/_layout.scss
+++ b/cms/static/sass/_layout.scss
@@ -20,7 +20,7 @@ body {
color: #fff;
display: block;
float: none;
- padding: 0 25px;
+ padding: 0 20px;
text-shadow: 0 -1px 0 darken($dark-blue, 15%);
width: 100%;
@@ -117,7 +117,7 @@ body {
@include box-sizing(border-box);
width: flex-grid(9) + flex-gutter();
float: left;
- @include box-shadow( -2px 0 0 darken($light-blue, 3%));
+ @include box-shadow( -2px 0 0 lighten($dark-blue, 55%));
@include transition();
background: #FFF;
}
diff --git a/cms/static/sass/_section.scss b/cms/static/sass/_section.scss
index fa08e02901..7558a2193b 100644
--- a/cms/static/sass/_section.scss
+++ b/cms/static/sass/_section.scss
@@ -1,6 +1,7 @@
section#unit-wrapper {
section.filters {
@include clearfix;
+ display: none;
opacity: .4;
margin-bottom: 10px;
@include transition;
@@ -52,6 +53,8 @@ section#unit-wrapper {
display: table;
border: 1px solid lighten($dark-blue, 40%);
width: 100%;
+ @include border-radius(3px);
+ @include box-shadow(0 0 4px lighten($dark-blue, 50%));
section {
header {
diff --git a/cms/static/sass/_unit.scss b/cms/static/sass/_unit.scss
index d8613be3c2..8c42ba9d08 100644
--- a/cms/static/sass/_unit.scss
+++ b/cms/static/sass/_unit.scss
@@ -1,19 +1,19 @@
section#unit-wrapper {
> header {
- border-bottom: 2px solid $dark-blue;
+ border-bottom: 1px solid lighten($dark-blue, 50%);
+ @include linear-gradient(#fff, lighten($dark-blue, 62%));
@include clearfix();
- @include box-shadow( 0 2px 0 darken($light-blue, 3%));
- padding: 6px 20px;
+ @include box-shadow( 0 2px 0 $light-blue, inset 0 -1px 0 #fff);
+ text-shadow: 0 1px 0 #fff;
section {
float: left;
+ padding: 10px 20px;
h1 {
- font-size: 16px;
- text-transform: uppercase;
- letter-spacing: 1px;
+ font-size: 18px;
@include inline-block();
- color: $bright-blue;
+ color: $dark-blue;
margin: 0;
}
@@ -22,32 +22,55 @@ section#unit-wrapper {
margin: 0;
a {
- text-indent: -9999px;
@include inline-block();
- width: 1px;
- height: 100%;
+ font-size: 12px;
}
}
}
div {
- float: right;
+ @include clearfix;
color: #666;
+ float: right;
+ padding: 0 20px;
a {
- display: block;
@include inline-block;
+ padding: 13px 20px;
- &.cancel {
- margin-right: 20px;
- font-style: italic;
- font-size: 12px;
- }
+ &.cancel {
+ margin-right: 20px;
+ font-style: italic;
+ font-size: 12px;
+ }
- &.save-update {
- @extend .button;
- margin: -6px -21px -6px 0;
- }
+ &.save-update {
+ border-left: 1px solid lighten($dark-blue, 40%);
+ border-right: 1px solid lighten($dark-blue, 40%);
+ // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
+ color: $bright-blue;
+ @include linear-gradient(lighten($dark-blue, 50%), lighten($bright-blue, 55%));
+
+ // &:hover, &:focus {
+ // color: $yellow;
+ // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
+ // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
+ // }
+ }
+ // &.save-update {
+ // border-left: 1px solid lighten($dark-blue, 10%);
+ // border-right: 1px solid lighten($dark-blue, 10%);
+ // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
+ // color: #fff;
+ // @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
+ // text-shadow: 0 -1px 0 darken($bright-blue, 10%);
+
+ // &:hover, &:focus {
+ // color: $yellow;
+ // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
+ // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
+ // }
+ // }
}
}
}
diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss
index 35c02a4758..49a51a59fb 100644
--- a/cms/static/sass/base-style.scss
+++ b/cms/static/sass/base-style.scss
@@ -1,8 +1,9 @@
@import 'bourbon/bourbon';
@import 'vendor/normalize';
+@import 'keyframes';
@import 'base', 'layout', 'content-types';
@import 'calendar';
-@import 'section', 'unit';
+@import 'section', 'unit', 'index';
@import 'module/module-styles.scss';
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 96f881421a..dba7df95b9 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -15,7 +15,7 @@
-
+
<%include file="widgets/header.html"/>
<%include file="courseware_vendor_js.html"/>
diff --git a/cms/templates/course_index.html b/cms/templates/course_index.html
index 92b5cc296c..e490ad7817 100644
--- a/cms/templates/course_index.html
+++ b/cms/templates/course_index.html
@@ -1,5 +1,6 @@
<%inherit file="base.html" />
<%block name="title">Course Manager%block>
+<%include file="widgets/header.html"/>
<%block name="content">
diff --git a/cms/templates/index.html b/cms/templates/index.html
index 2998cb8bd6..6e3cb648ae 100644
--- a/cms/templates/index.html
+++ b/cms/templates/index.html
@@ -1,8 +1,16 @@
<%inherit file="base.html" />
+<%block name="bodyclass">index%block>
<%block name="title">Courses%block>
<%block name="content">
+edX Course Management
+
+
+
%for course, url in courses:
${course}
From 1d5ce541402d32a5dcf608ab1a30c6cd2712b442 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Thu, 12 Jul 2012 16:38:37 -0400
Subject: [PATCH 31/55] Added styles for buttons
---
cms/static/sass/_base.scss | 14 +++++++------
cms/static/sass/_section.scss | 11 +++++-----
cms/static/sass/_unit.scss | 38 +++++++++++------------------------
3 files changed, 25 insertions(+), 38 deletions(-)
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 41424fe08f..82e9a2c16d 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -8,7 +8,7 @@ $body-line-height: 20px;
$light-blue: #f0f7fd;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
-$orange: #ea5155;
+$orange: #f96e5b;
$yellow: #fff8af;
$cream: #F6EFD4;
$mit-red: #933;
@@ -41,17 +41,19 @@ input {
}
button, input[type="submit"], .button {
- @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
- border-left: 1px solid lighten($dark-blue, 10%);
- text-shadow: 0 -1px 0 darken($bright-blue, 10%);
+ background-color: $orange;
+ @include linear-gradient(adjust-hue($orange, 8%), $orange);
+ border: 1px solid darken($orange, 15%);
+ @include box-shadow(inset 0 0 0 1px adjust-hue($orange, 20%), 0 1px 0 #fff);
+ text-shadow: 0 1px 0 darken($orange, 10%);
color: #fff;
font-weight: bold;
- padding: 8px 10px;
+ padding: 6px 20px;
-webkit-font-smoothing: antialiased;
@include border-radius(4px);
&:hover, &:focus {
+ @include box-shadow(inset 0 0 6px 1px adjust-hue($orange, 30%));
}
}
diff --git a/cms/static/sass/_section.scss b/cms/static/sass/_section.scss
index 7558a2193b..97818326be 100644
--- a/cms/static/sass/_section.scss
+++ b/cms/static/sass/_section.scss
@@ -61,16 +61,14 @@ section#unit-wrapper {
background: #fff;
padding: 6px;
border-bottom: 1px solid lighten($dark-blue, 60%);
- border-top: 1px solid lighten($dark-blue, 60%);
- margin-top: -1px;
@include clearfix;
h2 {
color: $bright-blue;
- float: left;
- font-size: 12px;
+ // float: left;
+ font-size: 14px;
letter-spacing: 1px;
- line-height: 19px;
+ // line-height: 20px;
text-transform: uppercase;
margin: 0;
}
@@ -175,7 +173,6 @@ section#unit-wrapper {
padding: 0;
li {
- border-bottom: 1px solid darken($light-blue, 8%);
background: $light-blue;
&:last-child {
@@ -184,6 +181,7 @@ section#unit-wrapper {
&.new-module a {
background-color: darken($light-blue, 2%);
+ border-bottom: 1px solid darken($light-blue, 8%);
&:hover {
background-color: lighten($yellow, 10%);
@@ -202,6 +200,7 @@ section#unit-wrapper {
li {
padding: 6px;
border-collapse: collapse;
+ border-bottom: 1px solid darken($light-blue, 8%);
position: relative;
&:last-child {
diff --git a/cms/static/sass/_unit.scss b/cms/static/sass/_unit.scss
index 8c42ba9d08..0ab0d1064d 100644
--- a/cms/static/sass/_unit.scss
+++ b/cms/static/sass/_unit.scss
@@ -32,45 +32,31 @@ section#unit-wrapper {
@include clearfix;
color: #666;
float: right;
- padding: 0 20px;
+ padding: 6px 20px;
a {
@include inline-block;
- padding: 13px 20px;
&.cancel {
margin-right: 20px;
font-style: italic;
font-size: 12px;
+ padding: 6px 0;
}
&.save-update {
- border-left: 1px solid lighten($dark-blue, 40%);
- border-right: 1px solid lighten($dark-blue, 40%);
- // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- color: $bright-blue;
- @include linear-gradient(lighten($dark-blue, 50%), lighten($bright-blue, 55%));
+ padding: 6px 20px;
+ @include border-radius(3px);
+ border: 1px solid lighten($dark-blue, 40%);
+ @include box-shadow(inset 0 0 0 1px #fff);
+ color: $dark-blue;
+ @include linear-gradient(lighten($dark-blue, 60%), lighten($dark-blue, 55%));
- // &:hover, &:focus {
- // color: $yellow;
- // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
- // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
- // }
+ &:hover, &:focus {
+ @include linear-gradient(lighten($dark-blue, 58%), lighten($dark-blue, 53%));
+ @include box-shadow(inset 0 0 6px 1px #fff);
+ }
}
- // &.save-update {
- // border-left: 1px solid lighten($dark-blue, 10%);
- // border-right: 1px solid lighten($dark-blue, 10%);
- // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- // color: #fff;
- // @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
- // text-shadow: 0 -1px 0 darken($bright-blue, 10%);
-
- // &:hover, &:focus {
- // color: $yellow;
- // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
- // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
- // }
- // }
}
}
}
From 84272f3f8c25e93b1b3421d4eb2f3c175b4dfdf4 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Tue, 10 Jul 2012 16:33:36 -0400
Subject: [PATCH 32/55] Added Gemfile.lock to ignore
---
lms/static/.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/lms/static/.gitignore b/lms/static/.gitignore
index cec91505bb..afc42d5e7e 100644
--- a/lms/static/.gitignore
+++ b/lms/static/.gitignore
@@ -6,3 +6,4 @@
*.DS_Store
application.css
ie.css
+Gemfile.lock
From b777d2c057e20fc83f1c17dfad6651494a660fb2 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Wed, 11 Jul 2012 16:12:33 -0400
Subject: [PATCH 33/55] Added some more style for cal view and nav bar
---
cms/static/sass/_layout.scss | 2 +-
cms/templates/widgets/header.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cms/static/sass/_layout.scss b/cms/static/sass/_layout.scss
index 43308a973c..b3c73d7d2a 100644
--- a/cms/static/sass/_layout.scss
+++ b/cms/static/sass/_layout.scss
@@ -20,7 +20,7 @@ body {
color: #fff;
display: block;
float: none;
- padding: 0 20px;
+ padding: 0 25px;
text-shadow: 0 -1px 0 darken($dark-blue, 15%);
width: 100%;
diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html
index f9322fb13d..c0b9f9e3af 100644
--- a/cms/templates/widgets/header.html
+++ b/cms/templates/widgets/header.html
@@ -2,7 +2,7 @@
Home
-
+
Module
From 270f0f3ae4b28d9e85addda38d1be0c2adab8c7e Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Thu, 12 Jul 2012 14:28:13 -0400
Subject: [PATCH 34/55] Added more styles includeing the index page more color
changes and header styles
---
cms/static/sass/_base.scss | 12 ++++++++-
cms/static/sass/_content-types.scss | 5 ++++
cms/static/sass/_layout.scss | 2 +-
cms/static/sass/_unit.scss | 39 ++++++++++++++++++++---------
4 files changed, 44 insertions(+), 14 deletions(-)
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 82e9a2c16d..13bab02594 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -8,7 +8,7 @@ $body-line-height: 20px;
$light-blue: #f0f7fd;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
-$orange: #f96e5b;
+$orange: #ea5155;
$yellow: #fff8af;
$cream: #F6EFD4;
$mit-red: #933;
@@ -41,11 +41,18 @@ input {
}
button, input[type="submit"], .button {
+<<<<<<< HEAD
background-color: $orange;
@include linear-gradient(adjust-hue($orange, 8%), $orange);
border: 1px solid darken($orange, 15%);
@include box-shadow(inset 0 0 0 1px adjust-hue($orange, 20%), 0 1px 0 #fff);
text-shadow: 0 1px 0 darken($orange, 10%);
+=======
+ @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
+ @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
+ border-left: 1px solid lighten($dark-blue, 10%);
+ text-shadow: 0 -1px 0 darken($bright-blue, 10%);
+>>>>>>> Added more styles includeing the index page more color changes and header styles
color: #fff;
font-weight: bold;
padding: 6px 20px;
@@ -53,7 +60,10 @@ button, input[type="submit"], .button {
@include border-radius(4px);
&:hover, &:focus {
+<<<<<<< HEAD
@include box-shadow(inset 0 0 6px 1px adjust-hue($orange, 30%));
+=======
+>>>>>>> Added more styles includeing the index page more color changes and header styles
}
}
diff --git a/cms/static/sass/_content-types.scss b/cms/static/sass/_content-types.scss
index 5fab0fe874..00af06d5ad 100644
--- a/cms/static/sass/_content-types.scss
+++ b/cms/static/sass/_content-types.scss
@@ -58,3 +58,8 @@
@extend .content-type;
background-image: url('/static/img/content-types/module.png');
}
+
+.module a:first-child {
+ @extend .content-type;
+ background-image: url('/static/img/content-types/module.png');
+}
diff --git a/cms/static/sass/_layout.scss b/cms/static/sass/_layout.scss
index b3c73d7d2a..43308a973c 100644
--- a/cms/static/sass/_layout.scss
+++ b/cms/static/sass/_layout.scss
@@ -20,7 +20,7 @@ body {
color: #fff;
display: block;
float: none;
- padding: 0 25px;
+ padding: 0 20px;
text-shadow: 0 -1px 0 darken($dark-blue, 15%);
width: 100%;
diff --git a/cms/static/sass/_unit.scss b/cms/static/sass/_unit.scss
index 0ab0d1064d..38bd60f20e 100644
--- a/cms/static/sass/_unit.scss
+++ b/cms/static/sass/_unit.scss
@@ -32,31 +32,46 @@ section#unit-wrapper {
@include clearfix;
color: #666;
float: right;
- padding: 6px 20px;
+ padding: 0 20px;
a {
@include inline-block;
+ padding: 13px 20px;
&.cancel {
margin-right: 20px;
font-style: italic;
font-size: 12px;
- padding: 6px 0;
}
&.save-update {
- padding: 6px 20px;
- @include border-radius(3px);
- border: 1px solid lighten($dark-blue, 40%);
- @include box-shadow(inset 0 0 0 1px #fff);
- color: $dark-blue;
- @include linear-gradient(lighten($dark-blue, 60%), lighten($dark-blue, 55%));
+ border-left: 1px solid lighten($dark-blue, 40%);
+ border-right: 1px solid lighten($dark-blue, 40%);
+ // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
+ color: $bright-blue;
+ @include linear-gradient(lighten($dark-blue, 50%), lighten($bright-blue, 55%));
- &:hover, &:focus {
- @include linear-gradient(lighten($dark-blue, 58%), lighten($dark-blue, 53%));
- @include box-shadow(inset 0 0 6px 1px #fff);
- }
+ // &:hover, &:focus {
+ // color: $yellow;
+ // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
+ // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
+ // }
}
+ // &.save-update {
+ // border-left: 1px solid lighten($dark-blue, 10%);
+ // border-right: 1px solid lighten($dark-blue, 10%);
+ // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
+ // color: #fff;
+ // @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
+ // text-shadow: 0 -1px 0 darken($bright-blue, 10%);
+
+ // &:hover, &:focus {
+ // color: $yellow;
+ // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
+ // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
+ // }
+ // }
+>>>>>>> Added more styles includeing the index page more color changes and header styles
}
}
}
From 44168deffc779de02b6b5c76a8674b71063e5596 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Thu, 12 Jul 2012 16:38:37 -0400
Subject: [PATCH 35/55] Added styles for buttons
---
cms/static/sass/_base.scss | 18 ++++--------------
cms/static/sass/_unit.scss | 39 ++++++++++++--------------------------
2 files changed, 16 insertions(+), 41 deletions(-)
diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss
index 13bab02594..cad315f6e4 100644
--- a/cms/static/sass/_base.scss
+++ b/cms/static/sass/_base.scss
@@ -8,7 +8,7 @@ $body-line-height: 20px;
$light-blue: #f0f7fd;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
-$orange: #ea5155;
+$orange: #f96e5b;
$yellow: #fff8af;
$cream: #F6EFD4;
$mit-red: #933;
@@ -41,29 +41,19 @@ input {
}
button, input[type="submit"], .button {
-<<<<<<< HEAD
background-color: $orange;
- @include linear-gradient(adjust-hue($orange, 8%), $orange);
border: 1px solid darken($orange, 15%);
+ @include border-radius(4px);
@include box-shadow(inset 0 0 0 1px adjust-hue($orange, 20%), 0 1px 0 #fff);
- text-shadow: 0 1px 0 darken($orange, 10%);
-=======
- @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
- border-left: 1px solid lighten($dark-blue, 10%);
- text-shadow: 0 -1px 0 darken($bright-blue, 10%);
->>>>>>> Added more styles includeing the index page more color changes and header styles
color: #fff;
font-weight: bold;
+ @include linear-gradient(adjust-hue($orange, 8%), $orange);
padding: 6px 20px;
+ text-shadow: 0 1px 0 darken($orange, 10%);
-webkit-font-smoothing: antialiased;
- @include border-radius(4px);
&:hover, &:focus {
-<<<<<<< HEAD
@include box-shadow(inset 0 0 6px 1px adjust-hue($orange, 30%));
-=======
->>>>>>> Added more styles includeing the index page more color changes and header styles
}
}
diff --git a/cms/static/sass/_unit.scss b/cms/static/sass/_unit.scss
index 38bd60f20e..0ab0d1064d 100644
--- a/cms/static/sass/_unit.scss
+++ b/cms/static/sass/_unit.scss
@@ -32,46 +32,31 @@ section#unit-wrapper {
@include clearfix;
color: #666;
float: right;
- padding: 0 20px;
+ padding: 6px 20px;
a {
@include inline-block;
- padding: 13px 20px;
&.cancel {
margin-right: 20px;
font-style: italic;
font-size: 12px;
+ padding: 6px 0;
}
&.save-update {
- border-left: 1px solid lighten($dark-blue, 40%);
- border-right: 1px solid lighten($dark-blue, 40%);
- // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- color: $bright-blue;
- @include linear-gradient(lighten($dark-blue, 50%), lighten($bright-blue, 55%));
+ padding: 6px 20px;
+ @include border-radius(3px);
+ border: 1px solid lighten($dark-blue, 40%);
+ @include box-shadow(inset 0 0 0 1px #fff);
+ color: $dark-blue;
+ @include linear-gradient(lighten($dark-blue, 60%), lighten($dark-blue, 55%));
- // &:hover, &:focus {
- // color: $yellow;
- // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
- // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
- // }
+ &:hover, &:focus {
+ @include linear-gradient(lighten($dark-blue, 58%), lighten($dark-blue, 53%));
+ @include box-shadow(inset 0 0 6px 1px #fff);
+ }
}
- // &.save-update {
- // border-left: 1px solid lighten($dark-blue, 10%);
- // border-right: 1px solid lighten($dark-blue, 10%);
- // @include box-shadow(inset 0 0 0 1px lighten($bright-blue, 15%));
- // color: #fff;
- // @include linear-gradient(lighten($bright-blue, 10%), $bright-blue);
- // text-shadow: 0 -1px 0 darken($bright-blue, 10%);
-
- // &:hover, &:focus {
- // color: $yellow;
- // @include linear-gradient($bright-blue, darken($bright-blue, 10%));
- // @include box-shadow(inset 0 0 3px 1px lighten($bright-blue, 10%));
- // }
- // }
->>>>>>> Added more styles includeing the index page more color changes and header styles
}
}
}
From c9e637d7197da54d6c802c25d5a2135ae51f8d39 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 11:43:29 -0400
Subject: [PATCH 36/55] Make cms and lms tests run independently (they had been
colliding on collectstatic)
---
{lms => common}/static/images/correct-icon.png | Bin
{lms => common}/static/images/incorrect-icon.png | Bin
{lms => common}/static/images/unanswered-icon.png | Bin
rakefile | 8 ++++++--
4 files changed, 6 insertions(+), 2 deletions(-)
rename {lms => common}/static/images/correct-icon.png (100%)
rename {lms => common}/static/images/incorrect-icon.png (100%)
rename {lms => common}/static/images/unanswered-icon.png (100%)
diff --git a/lms/static/images/correct-icon.png b/common/static/images/correct-icon.png
similarity index 100%
rename from lms/static/images/correct-icon.png
rename to common/static/images/correct-icon.png
diff --git a/lms/static/images/incorrect-icon.png b/common/static/images/incorrect-icon.png
similarity index 100%
rename from lms/static/images/incorrect-icon.png
rename to common/static/images/incorrect-icon.png
diff --git a/lms/static/images/unanswered-icon.png b/common/static/images/unanswered-icon.png
similarity index 100%
rename from lms/static/images/unanswered-icon.png
rename to common/static/images/unanswered-icon.png
diff --git a/rakefile b/rakefile
index d69f7329bb..01491ce981 100644
--- a/rakefile
+++ b/rakefile
@@ -27,7 +27,7 @@ NORMALIZED_DEPLOY_NAME = DEPLOY_NAME.downcase().gsub(/[_\/]/, '-')
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, NORMALIZED_DEPLOY_NAME)
PIP_REPO_REQUIREMENTS = "#{INSTALL_DIR_PATH}/repo-requirements.txt"
# Set up the clean and clobber tasks
-CLOBBER.include(BUILD_DIR, REPORT_DIR, 'cover*', '.coverage', 'test_root/*_repo')
+CLOBBER.include(BUILD_DIR, REPORT_DIR, 'cover*', '.coverage', 'test_root/*_repo', 'test_root/staticfiles')
CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
def select_executable(*cmds)
@@ -54,6 +54,10 @@ task :predjango do
sh('git submodule update --init')
end
+task :clean_test_files do
+ sh("git clean -fdx test_root")
+end
+
[:lms, :cms, :common].each do |system|
report_dir = File.join(REPORT_DIR, system.to_s)
directory report_dir
@@ -93,7 +97,7 @@ end
# Per System tasks
desc "Run all django tests on our djangoapps for the #{system}"
- task "test_#{system}" => ["#{system}:collectstatic:test", "fasttest_#{system}"]
+ task "test_#{system}" => ["clean_test_files", "#{system}:collectstatic:test", "fasttest_#{system}"]
# Have a way to run the tests without running collectstatic -- useful when debugging without
# messing with static files.
From 39e5a7762eaa8d6480c15d80fe380ac4efb96abb Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 11:47:45 -0400
Subject: [PATCH 37/55] Make github_sync use a namedtuple for repo settings
---
cms/djangoapps/github_sync/__init__.py | 29 ++++++++++----------
cms/djangoapps/github_sync/exceptions.py | 4 +++
cms/djangoapps/github_sync/tests/__init__.py | 8 ++----
cms/envs/dev.py | 27 ++++--------------
4 files changed, 27 insertions(+), 41 deletions(-)
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index 1089db7efd..bf6e2114b3 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -7,34 +7,33 @@ from git import Repo, PushInfo
from xmodule.modulestore.xml_importer import import_from_xml
from xmodule.modulestore.django import modulestore
-from xmodule.modulestore import Location
+from collections import namedtuple
-from .exceptions import GithubSyncError
+from .exceptions import GithubSyncError, InvalidRepo
log = logging.getLogger(__name__)
+RepoSettings = namedtuple('RepoSettings', 'path branch origin')
+
def setup_repo(repo_settings):
"""
Reset the local github repo specified by repo_settings
- repo_settings is a dictionary with the following keys:
- path: file system path to the local git repo
- branch: name of the branch to track on github
- origin: git url for the repository to track
+ repo_settings (RepoSettings): The settings for the repo to reset
"""
- course_dir = repo_settings['path']
+ course_dir = repo_settings.path
repo_path = settings.GITHUB_REPO_ROOT / course_dir
if not os.path.isdir(repo_path):
- Repo.clone_from(repo_settings['origin'], repo_path)
+ Repo.clone_from(repo_settings.origin, repo_path)
git_repo = Repo(repo_path)
origin = git_repo.remotes.origin
origin.fetch()
# Do a hard reset to the remote branch so that we have a clean import
- git_repo.git.checkout(repo_settings['branch'])
+ git_repo.git.checkout(repo_settings.branch)
return git_repo
@@ -43,19 +42,19 @@ def load_repo_settings(course_dir):
"""
Returns the repo_settings for the course stored in course_dir
"""
- for repo_settings in settings.REPOS.values():
- if repo_settings['path'] == course_dir:
- return repo_settings
- raise InvalidRepo(course_dir)
+ if course_dir not in settings.REPOS:
+ raise InvalidRepo(course_dir)
+
+ return RepoSettings(course_dir, **settings.REPOS[course_dir])
def import_from_github(repo_settings):
"""
Imports data into the modulestore based on the XML stored on github
"""
- course_dir = repo_settings['path']
+ course_dir = repo_settings.path
git_repo = setup_repo(repo_settings)
- git_repo.head.reset('origin/%s' % repo_settings['branch'], index=True, working_tree=True)
+ git_repo.head.reset('origin/%s' % repo_settings.branch, index=True, working_tree=True)
module_store = import_from_xml(modulestore(),
settings.GITHUB_REPO_ROOT, course_dirs=[course_dir])
diff --git a/cms/djangoapps/github_sync/exceptions.py b/cms/djangoapps/github_sync/exceptions.py
index 9097ffc2a6..1fe8d1d73e 100644
--- a/cms/djangoapps/github_sync/exceptions.py
+++ b/cms/djangoapps/github_sync/exceptions.py
@@ -1,2 +1,6 @@
class GithubSyncError(Exception):
pass
+
+
+class InvalidRepo(Exception):
+ pass
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
index 6b374cda2c..ef6a2f349a 100644
--- a/cms/djangoapps/github_sync/tests/__init__.py
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -1,8 +1,7 @@
from django.test import TestCase
from path import path
import shutil
-import os
-from github_sync import import_from_github, export_to_github
+from github_sync import import_from_github, export_to_github, load_repo_settings
from git import Repo
from django.conf import settings
from xmodule.modulestore.django import modulestore
@@ -16,8 +15,7 @@ REMOTE_DIR = WORKING_DIR / 'remote_repo'
@override_settings(REPOS={
- 'local': {
- 'path': 'local_repo',
+ 'local_repo': {
'origin': REMOTE_DIR,
'branch': 'master',
}
@@ -40,7 +38,7 @@ class GithubSyncTestCase(TestCase):
remote.git.commit(m='Initial commit')
remote.git.config("receive.denyCurrentBranch", "ignore")
- self.import_revision, self.import_course = import_from_github(settings.REPOS['local'])
+ self.import_revision, self.import_course = import_from_github(load_repo_settings('local_repo'))
def tearDown(self):
self.cleanup()
diff --git a/cms/envs/dev.py b/cms/envs/dev.py
index dd12ce5770..b0729ba885 100644
--- a/cms/envs/dev.py
+++ b/cms/envs/dev.py
@@ -32,38 +32,23 @@ DATABASES = {
REPOS = {
'edx4edx': {
- 'path': "edx4edx",
- 'org': 'edx',
- 'course': 'edx4edx',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/edx4edx.git',
},
- '6002x-fall-2012': {
- 'path': '6002x-fall-2012',
- 'org': 'mit.edu',
- 'course': '6.002x',
- 'branch': 'for_cms',
+ 'content-mit-6002x': {
+ 'branch': 'master',
'origin': 'git@github.com:MITx/6002x-fall-2012.git',
},
'6.00x': {
- 'path': '6.00x',
- 'org': 'mit.edu',
- 'course': '6.00x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/6.00x.git',
},
'7.00x': {
- 'path': '7.00x',
- 'org': 'mit.edu',
- 'course': '7.00x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/7.00x.git',
},
'3.091x': {
- 'path': '3.091x',
- 'org': 'mit.edu',
- 'course': '3.091x',
- 'branch': 'for_cms',
+ 'branch': 'master',
'origin': 'git@github.com:MITx/3.091x.git',
},
}
From 012036a47847931153dabf9cbc796aa33e31e178 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 11:48:00 -0400
Subject: [PATCH 38/55] Clean up minor whitespace stuff in settings
---
lms/envs/aws.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lms/envs/aws.py b/lms/envs/aws.py
index bd2a0fc389..460ec18d27 100644
--- a/lms/envs/aws.py
+++ b/lms/envs/aws.py
@@ -32,12 +32,12 @@ LOG_DIR = ENV_TOKENS['LOG_DIR']
CACHES = ENV_TOKENS['CACHES']
-for feature,value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
+for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
MITX_FEATURES[feature] = value
-WIKI_ENABLED = ENV_TOKENS.get('WIKI_ENABLED',WIKI_ENABLED)
+WIKI_ENABLED = ENV_TOKENS.get('WIKI_ENABLED', WIKI_ENABLED)
-LOGGING = get_logger_config(LOG_DIR,
+LOGGING = get_logger_config(LOG_DIR,
logging_env=ENV_TOKENS['LOGGING_ENV'],
syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
debug=False)
From d6dc45756cbb30a8f707d683943ccd4ee0391e6b Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 11:48:43 -0400
Subject: [PATCH 39/55] Add an aws settings for the cms
---
cms/envs/aws.py | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 cms/envs/aws.py
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
new file mode 100644
index 0000000000..531141f656
--- /dev/null
+++ b/cms/envs/aws.py
@@ -0,0 +1,45 @@
+"""
+This is the default template for our main set of AWS servers.
+"""
+import json
+
+from .logsettings import get_logger_config
+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']
+
+LOG_DIR = ENV_TOKENS['LOG_DIR']
+
+CACHES = ENV_TOKENS['CACHES']
+
+for feature, value in ENV_TOKENS.get('MITX_FEATURES', {}).items():
+ MITX_FEATURES[feature] = value
+
+LOGGING = get_logger_config(LOG_DIR,
+ logging_env=ENV_TOKENS['LOGGING_ENV'],
+ syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
+ debug=False)
+
+REPOS = ENV_TOKENS['REPOS']
+
+
+############################## SECURE AUTH ITEMS ###############################
+# Secret things: passwords, access keys, etc.
+with open(ENV_ROOT / "auth.json") as auth_file:
+ AUTH_TOKENS = json.load(auth_file)
+
+DATABASES = AUTH_TOKENS['DATABASES']
+MODULESTORE = AUTH_TOKENS['MODULESTORE']
From 7e06c72e4205b1a37d39a95eb06b0b33d12ec723 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 12:27:42 -0400
Subject: [PATCH 40/55] Add logsettings to CMS
---
cms/envs/logsettings.py | 96 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
create mode 100644 cms/envs/logsettings.py
diff --git a/cms/envs/logsettings.py b/cms/envs/logsettings.py
new file mode 100644
index 0000000000..916cd77748
--- /dev/null
+++ b/cms/envs/logsettings.py
@@ -0,0 +1,96 @@
+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', 'newrelic']
+
+ 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',
+ },
+ 'newrelic' : {
+ 'level': 'ERROR',
+ 'class': 'newrelic_logging.NewRelicHandler',
+ 'formatter': 'raw',
+ }
+ },
+ 'loggers' : {
+ 'django' : {
+ 'handlers' : handlers,
+ 'propagate' : True,
+ 'level' : 'INFO'
+ },
+ 'tracking' : {
+ 'handlers' : ['tracking'],
+ 'level' : 'DEBUG',
+ 'propagate' : False,
+ },
+ '' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ 'mitx' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ 'keyedcache' : {
+ 'handlers' : handlers,
+ 'level' : 'DEBUG',
+ 'propagate' : False
+ },
+ }
+ }
From d86b72fc24e843ba2f0e36c24c232cadb67c4427 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 12:37:38 -0400
Subject: [PATCH 41/55] Split REPOS data into separate file on aws
---
cms/envs/aws.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index 531141f656..26a3545324 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -33,7 +33,8 @@ LOGGING = get_logger_config(LOG_DIR,
syslog_addr=(ENV_TOKENS['SYSLOG_SERVER'], 514),
debug=False)
-REPOS = ENV_TOKENS['REPOS']
+with open(ENV_ROOT / "repos.json") as repos_file:
+ REPOS = json.load(repos_file)
############################## SECURE AUTH ITEMS ###############################
From 818cb0d1e78022cd157d8e822712fcbd54f13ec3 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 12:40:05 -0400
Subject: [PATCH 42/55] Separate cms and lms auth and env files, and have the
LMS that runs with the CMS use the CMS modulestore
---
cms/envs/aws.py | 4 ++--
lms/envs/with_cms.py | 10 ++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
create mode 100644 lms/envs/with_cms.py
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index 26a3545324..79c90a6df9 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -16,7 +16,7 @@ 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:
+with open(ENV_ROOT / "cms.env.json") as env_file:
ENV_TOKENS = json.load(env_file)
SITE_NAME = ENV_TOKENS['SITE_NAME']
@@ -39,7 +39,7 @@ with open(ENV_ROOT / "repos.json") as repos_file:
############################## SECURE AUTH ITEMS ###############################
# Secret things: passwords, access keys, etc.
-with open(ENV_ROOT / "auth.json") as auth_file:
+with open(ENV_ROOT / "cms.auth.json") as auth_file:
AUTH_TOKENS = json.load(auth_file)
DATABASES = AUTH_TOKENS['DATABASES']
diff --git a/lms/envs/with_cms.py b/lms/envs/with_cms.py
new file mode 100644
index 0000000000..b807a0f545
--- /dev/null
+++ b/lms/envs/with_cms.py
@@ -0,0 +1,10 @@
+"""
+Settings for the LMS that runs alongside the CMS on AWS
+"""
+
+from .aws import *
+
+with open(ENV_ROOT / "cms.auth.json") as auth_file:
+ CMS_AUTH_TOKENS = json.load(auth_file)
+
+MODULESTORE = CMS_AUTH_TOKENS['MODULESTORE']
From cec2c893be15a263336eae02bd6cc4f9b0f7354d Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 14:25:49 -0400
Subject: [PATCH 43/55] Add AWS keys so that the CMS can send email
---
cms/envs/aws.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index 79c90a6df9..f03e10c9b1 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -42,5 +42,7 @@ with open(ENV_ROOT / "repos.json") as repos_file:
with open(ENV_ROOT / "cms.auth.json") as auth_file:
AUTH_TOKENS = json.load(auth_file)
+AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"]
+AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"]
DATABASES = AUTH_TOKENS['DATABASES']
MODULESTORE = AUTH_TOKENS['MODULESTORE']
From 6bd9cd6c2892cf53be2614fed61a03f7621acdb4 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 26 Jul 2012 15:31:51 -0400
Subject: [PATCH 44/55] Add management command for syncing with github
---
.../contentstore/management/commands/import.py | 2 +-
cms/djangoapps/github_sync/__init__.py | 18 ++++++++++++++++++
.../github_sync/management/__init__.py | 0
.../management/commands/__init__.py | 0
.../management/commands/sync_with_github.py | 14 ++++++++++++++
cms/djangoapps/github_sync/views.py | 9 ++++-----
cms/envs/common.py | 1 +
7 files changed, 38 insertions(+), 6 deletions(-)
create mode 100644 cms/djangoapps/github_sync/management/__init__.py
create mode 100644 cms/djangoapps/github_sync/management/commands/__init__.py
create mode 100644 cms/djangoapps/github_sync/management/commands/sync_with_github.py
diff --git a/cms/djangoapps/contentstore/management/commands/import.py b/cms/djangoapps/contentstore/management/commands/import.py
index 0e4dc5cc89..6be03b7850 100644
--- a/cms/djangoapps/contentstore/management/commands/import.py
+++ b/cms/djangoapps/contentstore/management/commands/import.py
@@ -1,5 +1,5 @@
###
-### One-off script for importing courseware form XML format
+### Script for importing courseware form XML format
###
from django.core.management.base import BaseCommand, CommandError
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index bf6e2114b3..e3215cbec1 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -16,6 +16,24 @@ log = logging.getLogger(__name__)
RepoSettings = namedtuple('RepoSettings', 'path branch origin')
+def sync_all_with_github():
+ """
+ Sync all defined repositories from github
+ """
+ for repo_name in settings.REPOS:
+ sync_with_github(load_repo_settings(repo_name))
+
+
+def sync_with_github(repo_settings):
+ """
+ Sync specified repository from github
+
+ repo_settings: A RepoSettings defining which repo to sync
+ """
+ revision, course = import_from_github(repo_settings)
+ export_to_github(course, "Changes from cms import of revision %s" % revision, "CMS ")
+
+
def setup_repo(repo_settings):
"""
Reset the local github repo specified by repo_settings
diff --git a/cms/djangoapps/github_sync/management/__init__.py b/cms/djangoapps/github_sync/management/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/cms/djangoapps/github_sync/management/commands/__init__.py b/cms/djangoapps/github_sync/management/commands/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/cms/djangoapps/github_sync/management/commands/sync_with_github.py b/cms/djangoapps/github_sync/management/commands/sync_with_github.py
new file mode 100644
index 0000000000..4383871df3
--- /dev/null
+++ b/cms/djangoapps/github_sync/management/commands/sync_with_github.py
@@ -0,0 +1,14 @@
+###
+### Script for syncing CMS with defined github repos
+###
+
+from django.core.management.base import NoArgsCommand
+from github_sync import sync_all_with_github
+
+
+class Command(NoArgsCommand):
+ help = \
+'''Sync the CMS with the defined github repos'''
+
+ def handle_noargs(self, **options):
+ sync_all_with_github()
diff --git a/cms/djangoapps/github_sync/views.py b/cms/djangoapps/github_sync/views.py
index e4cae6cad8..941d50f986 100644
--- a/cms/djangoapps/github_sync/views.py
+++ b/cms/djangoapps/github_sync/views.py
@@ -5,7 +5,7 @@ from django.http import HttpResponse
from django.conf import settings
from django_future.csrf import csrf_exempt
-from . import import_from_github, export_to_github
+from . import sync_with_github, load_repo_settings
log = logging.getLogger()
@@ -40,13 +40,12 @@ def github_post_receive(request):
log.info('No repository matching %s found' % repo_name)
return HttpResponse('No Repo Found')
- repo = settings.REPOS[repo_name]
+ repo = load_repo_settings(repo_name)
- if repo['branch'] != branch_name:
+ if repo.branch != branch_name:
log.info('Ignoring changes to non-tracked branch %s in repo %s' % (branch_name, repo_name))
return HttpResponse('Ignoring non-tracked branch')
- revision, course = import_from_github(repo)
- export_to_github(course, repo['path'], "Changes from cms import of revision %s" % revision)
+ sync_with_github(repo)
return HttpResponse('Push received')
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 582cb75abf..e7609c517f 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -309,6 +309,7 @@ INSTALLED_APPS = (
# For CMS
'contentstore',
+ 'github_sync',
'student', # misleading name due to sharing with lms
# For asset pipelining
From 05add5818ba15fd4aa3c558ac2647ac0642c1c2f Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 08:48:38 -0400
Subject: [PATCH 45/55] Return a custom error for duplicate elements, and
ignore it when loading into mongo
---
cms/djangoapps/contentstore/__init__.py | 0
common/lib/xmodule/xmodule/exceptions.py | 1 +
.../xmodule/xmodule/modulestore/exceptions.py | 5 +++++
.../lib/xmodule/xmodule/modulestore/mongo.py | 22 ++++++++++---------
.../xmodule/modulestore/xml_importer.py | 3 ++-
5 files changed, 20 insertions(+), 11 deletions(-)
delete mode 100644 cms/djangoapps/contentstore/__init__.py
diff --git a/cms/djangoapps/contentstore/__init__.py b/cms/djangoapps/contentstore/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/common/lib/xmodule/xmodule/exceptions.py b/common/lib/xmodule/xmodule/exceptions.py
index 9107d9dc4d..3db5ceccde 100644
--- a/common/lib/xmodule/xmodule/exceptions.py
+++ b/common/lib/xmodule/xmodule/exceptions.py
@@ -1,5 +1,6 @@
class InvalidDefinitionError(Exception):
pass
+
class NotFoundError(Exception):
pass
diff --git a/common/lib/xmodule/xmodule/modulestore/exceptions.py b/common/lib/xmodule/xmodule/modulestore/exceptions.py
index d860a1d263..a63efc3e43 100644
--- a/common/lib/xmodule/xmodule/modulestore/exceptions.py
+++ b/common/lib/xmodule/xmodule/modulestore/exceptions.py
@@ -14,5 +14,10 @@ class InsufficientSpecificationError(Exception):
class InvalidLocationError(Exception):
pass
+
class NoPathToItem(Exception):
pass
+
+
+class DuplicateItemError(Exception):
+ pass
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index b6b71f61fb..a2c5d7aec5 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -1,6 +1,5 @@
import pymongo
-from bson.objectid import ObjectId
from bson.son import SON
from fs.osfs import OSFS
from itertools import repeat
@@ -14,14 +13,13 @@ from mitxmako.shortcuts import render_to_string
from . import ModuleStore, Location
from .exceptions import (ItemNotFoundError, InsufficientSpecificationError,
- NoPathToItem)
+ NoPathToItem, DuplicateItemError)
# TODO (cpennington): This code currently operates under the assumption that
# there is only one revision for each item. Once we start versioning inside the CMS,
# that assumption will have to change
-
class CachingDescriptorSystem(MakoDescriptorSystem):
"""
A system that has a cache of module json that it will use to load modules
@@ -215,15 +213,22 @@ class MongoModuleStore(ModuleStore):
return self._load_items(list(items), depth)
+ # TODO (cpennington): This needs to be replaced by clone_item as soon as we allow
+ # creation of items from the cms
def create_item(self, location):
"""
- Create an empty item at the specified location with the supplied editor
+ Create an empty item at the specified location.
+
+ If that location already exists, raises a DuplicateItemError
location: Something that can be passed to Location
"""
- self.collection.insert({
- '_id': Location(location).dict(),
- })
+ try:
+ self.collection.insert({
+ '_id': Location(location).dict(),
+ })
+ except pymongo.errors.DuplicateKeyError:
+ raise DuplicateItemError(location)
def update_item(self, location, data):
"""
@@ -286,8 +291,6 @@ class MongoModuleStore(ModuleStore):
{'_id': True})
return [i['_id'] for i in items]
-
-
def path_to_location(self, location, course_name=None):
'''
Try to find a course_id/chapter/section[/position] path to this location.
@@ -361,7 +364,6 @@ class MongoModuleStore(ModuleStore):
if path is None:
raise(NoPathToItem(location))
-
n = len(path)
course_id = CourseDescriptor.location_to_id(path[0])
chapter = path[1].name if n > 1 else None
diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
index b315e0625a..578ade95fe 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py
@@ -1,6 +1,7 @@
import logging
from .xml import XMLModuleStore
+from .exceptions import DuplicateItemError
log = logging.getLogger(__name__)
@@ -27,7 +28,7 @@ def import_from_xml(store, data_dir, course_dirs=None, eager=True,
# This should in the future create new revisions of the items on import
try:
store.create_item(module.location)
- except:
+ except DuplicateItemError:
log.exception('Item already exists at %s' % module.location.url())
pass
if 'data' in module.definition:
From 6997fc579ecdc0486e5776f0749b14892cfbc83f Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 08:57:53 -0400
Subject: [PATCH 46/55] Continue on errors when syncing with github
---
common/lib/xmodule/xmodule/raw_module.py | 3 ++-
common/lib/xmodule/xmodule/xml_module.py | 19 ++++++++++---------
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/common/lib/xmodule/xmodule/raw_module.py b/common/lib/xmodule/xmodule/raw_module.py
index d8c18b251a..90f4139bd5 100644
--- a/common/lib/xmodule/xmodule/raw_module.py
+++ b/common/lib/xmodule/xmodule/raw_module.py
@@ -6,6 +6,7 @@ import logging
log = logging.getLogger(__name__)
+
class RawDescriptor(MakoModuleDescriptor, XmlDescriptor):
"""
Module that provides a raw editing view of its data and children
@@ -33,7 +34,7 @@ class RawDescriptor(MakoModuleDescriptor, XmlDescriptor):
line, offset = err.position
msg = ("Unable to create xml for problem {loc}. "
"Context: '{context}'".format(
- context=lines[line-1][offset - 40:offset + 40],
+ context=lines[line - 1][offset - 40:offset + 40],
loc=self.location))
log.exception(msg)
self.system.error_handler(msg)
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 8327a3ddec..2465a941b2 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -1,5 +1,6 @@
from collections import MutableMapping
from xmodule.x_module import XModuleDescriptor
+from xmodule.modulestore import Location
from lxml import etree
import copy
import logging
@@ -13,6 +14,7 @@ log = logging.getLogger(__name__)
# but the actual improvement wasn't measured (and it was implemented late at night).
# We should check if it hurts, and whether there's a better way of doing lazy loading
+
class LazyLoadingDict(MutableMapping):
"""
A dictionary object that lazily loads its contents from a provided
@@ -173,6 +175,9 @@ class XmlDescriptor(XModuleDescriptor):
url identifiers
"""
xml_object = etree.fromstring(xml_data)
+ # VS[compat] -- just have the url_name lookup once translation is done
+ slug = xml_object.get('url_name', xml_object.get('slug'))
+ location = Location('i4x', org, course, xml_object.tag, slug)
def metadata_loader():
metadata = {}
@@ -210,25 +215,21 @@ class XmlDescriptor(XModuleDescriptor):
with system.resources_fs.open(filepath) as file:
definition_xml = cls.file_to_xml(file)
except (ResourceNotFoundError, etree.XMLSyntaxError):
- msg = 'Unable to load file contents at path %s' % filepath
+ msg = 'Unable to load file contents at path %s for item %s' % (filepath, location.url())
log.exception(msg)
system.error_handler(msg)
# if error_handler didn't reraise, work around problem.
- return {'data': 'Error loading file contents at path %s' % filepath}
+ error_elem = etree.Element('error')
+ error_elem.text = msg
+ return {'data': etree.tostring(error_elem)}
cls.clean_metadata_from_xml(definition_xml)
return cls.definition_from_xml(definition_xml, system)
- # VS[compat] -- just have the url_name lookup once translation is done
- slug = xml_object.get('url_name', xml_object.get('slug'))
return cls(
system,
LazyLoadingDict(definition_loader),
- location=['i4x',
- org,
- course,
- xml_object.tag,
- slug],
+ location=location,
metadata=LazyLoadingDict(metadata_loader),
)
From 66d5c8effd106dd365bfd5003416bb27a34d7b84 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 09:04:48 -0400
Subject: [PATCH 47/55] Add more detail to error messages during loading from
xml
---
common/lib/xmodule/xmodule/xml_module.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py
index 2465a941b2..6750906eb4 100644
--- a/common/lib/xmodule/xmodule/xml_module.py
+++ b/common/lib/xmodule/xmodule/xml_module.py
@@ -4,6 +4,7 @@ from xmodule.modulestore import Location
from lxml import etree
import copy
import logging
+import traceback
from collections import namedtuple
from fs.errors import ResourceNotFoundError
import os
@@ -220,7 +221,10 @@ class XmlDescriptor(XModuleDescriptor):
system.error_handler(msg)
# if error_handler didn't reraise, work around problem.
error_elem = etree.Element('error')
- error_elem.text = msg
+ message_elem = etree.SubElement(error_elem, 'error_message')
+ message_elem.text = msg
+ stack_elem = etree.SubElement(error_elem, 'stack_trace')
+ stack_elem.text = traceback.format_exc()
return {'data': etree.tostring(error_elem)}
cls.clean_metadata_from_xml(definition_xml)
From 7ae0836f770bda280c075e91fcc357fac9f86be5 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 12:36:30 -0400
Subject: [PATCH 48/55] Add some more tests of github_sync
---
cms/djangoapps/github_sync/tests/__init__.py | 16 +++++++-
.../github_sync/tests/test_views.py | 39 +++++++------------
2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
index ef6a2f349a..39a94abb71 100644
--- a/cms/djangoapps/github_sync/tests/__init__.py
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -1,13 +1,14 @@
from django.test import TestCase
from path import path
import shutil
-from github_sync import import_from_github, export_to_github, load_repo_settings
+from github_sync import import_from_github, export_to_github, load_repo_settings, sync_all_with_github, sync_with_github
from git import Repo
from django.conf import settings
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location
from override_settings import override_settings
from github_sync.exceptions import GithubSyncError
+from mock import patch, Mock
REPO_DIR = settings.GITHUB_REPO_ROOT / 'local_repo'
WORKING_DIR = path(settings.TEST_ROOT)
@@ -59,6 +60,19 @@ class GithubSyncTestCase(TestCase):
[child.location for child in self.import_course.get_children()])
self.assertEquals(1, len(self.import_course.get_children()))
+ @patch('github_sync.sync_with_github')
+ def test_sync_all_with_github(self, sync_with_github):
+ sync_all_with_github()
+ sync_with_github.assert_called_with(load_repo_settings('local_repo'))
+
+ def test_sync_with_github(self):
+ with patch('github_sync.import_from_github', Mock(return_value=(Mock(), Mock()))) as import_from_github:
+ with patch('github_sync.export_to_github') as export_to_github:
+ settings = load_repo_settings('local_repo')
+ sync_with_github(settings)
+ import_from_github.assert_called_with(settings)
+ export_to_github.assert_called
+
@override_settings(MITX_FEATURES={'GITHUB_PUSH': False})
def test_export_no_pash(self):
"""
diff --git a/cms/djangoapps/github_sync/tests/test_views.py b/cms/djangoapps/github_sync/tests/test_views.py
index f46e7f7db3..212d707340 100644
--- a/cms/djangoapps/github_sync/tests/test_views.py
+++ b/cms/djangoapps/github_sync/tests/test_views.py
@@ -1,52 +1,43 @@
import json
from django.test.client import Client
from django.test import TestCase
-from mock import patch, Mock
+from mock import patch
from override_settings import override_settings
-from django.conf import settings
+from github_sync import load_repo_settings
-@override_settings(REPOS={'repo': {'path': 'path', 'branch': 'branch'}})
+@override_settings(REPOS={'repo': {'branch': 'branch', 'origin': 'origin'}})
class PostReceiveTestCase(TestCase):
def setUp(self):
self.client = Client()
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/tags/foo'})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_watched_repo(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_watched_repo(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/branch',
'repository': {'name': 'bad_repo'}})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github')
- def test_non_tracked_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_non_tracked_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/non_branch',
'repository': {'name': 'repo'}})
})
- self.assertFalse(import_from_github.called)
- self.assertFalse(export_to_github.called)
+ self.assertFalse(sync_with_github.called)
- @patch('github_sync.views.export_to_github')
- @patch('github_sync.views.import_from_github', return_value=(Mock(), Mock()))
- def test_tracked_branch(self, import_from_github, export_to_github):
+ @patch('github_sync.views.sync_with_github')
+ def test_tracked_branch(self, sync_with_github):
self.client.post('/github_service_hook', {'payload': json.dumps({
'ref': 'refs/heads/branch',
'repository': {'name': 'repo'}})
})
- import_from_github.assert_called_with(settings.REPOS['repo'])
- mock_revision, mock_course = import_from_github.return_value
- export_to_github.assert_called_with(mock_course, 'path', "Changes from cms import of revision %s" % mock_revision)
+ sync_with_github.assert_called_with(load_repo_settings('repo'))
From d0c99151f0c60fa6749a814e581716b48c092370 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 15:00:57 -0400
Subject: [PATCH 49/55] Continue during backcompat imports by replacing
contents with error xml
---
.../lib/xmodule/xmodule/backcompat_module.py | 45 ++++++++++---------
1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/common/lib/xmodule/xmodule/backcompat_module.py b/common/lib/xmodule/xmodule/backcompat_module.py
index 2b6ca5c25a..997ad476c4 100644
--- a/common/lib/xmodule/xmodule/backcompat_module.py
+++ b/common/lib/xmodule/xmodule/backcompat_module.py
@@ -5,6 +5,7 @@ from x_module import XModuleDescriptor
from lxml import etree
from functools import wraps
import logging
+import traceback
log = logging.getLogger(__name__)
@@ -21,29 +22,31 @@ def process_includes(fn):
next_include = xml_object.find('include')
while next_include is not None:
file = next_include.get('file')
- if file is not None:
- try:
- ifp = system.resources_fs.open(file)
- except Exception:
- msg = 'Error in problem xml include: %s\n' % (
- etree.tostring(next_include, pretty_print=True))
- msg += 'Cannot find file %s in %s' % (file, dir)
- log.exception(msg)
- system.error_handler(msg)
- raise
- try:
- # read in and convert to XML
- incxml = etree.XML(ifp.read())
- except Exception:
- msg = 'Error in problem xml include: %s\n' % (
- etree.tostring(next_include, pretty_print=True))
- msg += 'Cannot parse XML in %s' % (file)
- log.exception(msg)
- system.error_handler(msg)
- raise
+ parent = next_include.getparent()
+
+ if file is None:
+ continue
+
+ try:
+ ifp = system.resources_fs.open(file)
+ # read in and convert to XML
+ incxml = etree.XML(ifp.read())
+
# insert new XML into tree in place of inlcude
- parent = next_include.getparent()
parent.insert(parent.index(next_include), incxml)
+ except Exception:
+ msg = "Error in problem xml include: %s" % (etree.tostring(next_include, pretty_print=True))
+ log.exception(msg)
+ parent = next_include.getparent()
+
+ errorxml = etree.Element('error')
+ messagexml = etree.SubElement(errorxml, 'message')
+ messagexml.text = msg
+ stackxml = etree.SubElement(errorxml, 'stacktrace')
+ stackxml.text = traceback.format_exc()
+
+ # insert error XML in place of include
+ parent.insert(parent.index(next_include), errorxml)
parent.remove(next_include)
next_include = xml_object.find('include')
From 2caf1024f1c3b105728c2d9e7a7c7c1d820e77c8 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 15:08:03 -0400
Subject: [PATCH 50/55] Force mongodb fs_root to be a path object
---
common/lib/xmodule/xmodule/modulestore/mongo.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index a2c5d7aec5..e0e3f4ad9d 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -3,6 +3,7 @@ import pymongo
from bson.son import SON
from fs.osfs import OSFS
from itertools import repeat
+from path import path
from importlib import import_module
from xmodule.errorhandlers import strict_error_handler
@@ -96,7 +97,7 @@ class MongoModuleStore(ModuleStore):
module_path, _, class_name = default_class.rpartition('.')
class_ = getattr(import_module(module_path), class_name)
self.default_class = class_
- self.fs_root = fs_root
+ self.fs_root = path(fs_root)
def _clean_item_data(self, item):
"""
From 395cf147bee52577897f3b5ea6ee1d256c129752 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 15:24:24 -0400
Subject: [PATCH 51/55] Look up data_dir in the metadata, not in the top of the
json object when loading from mongodb
---
common/lib/xmodule/xmodule/modulestore/mongo.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py
index e0e3f4ad9d..df4e20f3a7 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo.py
@@ -141,8 +141,9 @@ class MongoModuleStore(ModuleStore):
"""
Load an XModuleDescriptor from item, using the children stored in data_cache
"""
- resource_fs = OSFS(self.fs_root / item.get('data_dir',
- item['location']['course']))
+ data_dir = item.get('metadata', {}).get('data_dir', item['location']['course'])
+ resource_fs = OSFS(self.fs_root / data_dir)
+
system = CachingDescriptorSystem(
self,
data_cache,
From 1fce1dbe34d90d41c9614435adeed27b88d05eec Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 15:46:11 -0400
Subject: [PATCH 52/55] Make sure that django-pipelined css and js don't
collide between the cms and lms
---
cms/envs/common.py | 8 ++++----
lms/envs/common.py | 16 ++++++++--------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/cms/envs/common.py b/cms/envs/common.py
index e7609c517f..3f8f4440c5 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -243,7 +243,7 @@ with open(module_styles_path, 'w') as module_styles:
PIPELINE_CSS = {
'base-style': {
'source_filenames': ['sass/base-style.scss'],
- 'output_filename': 'css/base-style.css',
+ 'output_filename': 'css/cms-base-style.css',
},
}
@@ -260,15 +260,15 @@ PIPELINE_JS = {
for pth
in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')
],
- 'output_filename': 'js/application.js',
+ 'output_filename': 'js/cms-application.js',
},
'module-js': {
'source_filenames': module_js_sources,
- 'output_filename': 'js/modules.js',
+ 'output_filename': 'js/cms-modules.js',
},
'spec': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
- 'output_filename': 'js/spec.js'
+ 'output_filename': 'js/cms-spec.js'
}
}
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 6d46f1cf9d..83ad08daa3 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -301,15 +301,15 @@ STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
PIPELINE_CSS = {
'application': {
'source_filenames': ['sass/application.scss'],
- 'output_filename': 'css/application.css',
+ 'output_filename': 'css/lms-application.css',
},
'course': {
'source_filenames': ['sass/course.scss', 'js/vendor/CodeMirror/codemirror.css', 'css/vendor/jquery.treeview.css'],
- 'output_filename': 'css/course.css',
+ 'output_filename': 'css/lms-course.css',
},
'ie-fixes': {
'source_filenames': ['sass/ie.scss'],
- 'output_filename': 'css/ie.css',
+ 'output_filename': 'css/lms-ie.css',
},
}
@@ -410,23 +410,23 @@ PIPELINE_JS = {
'js/toggle_login_modal.js',
'js/sticky_filter.js',
],
- 'output_filename': 'js/application.js'
+ 'output_filename': 'js/lms-application.js'
},
'courseware': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in courseware_only_js],
- 'output_filename': 'js/courseware.js'
+ 'output_filename': 'js/lms-courseware.js'
},
'main_vendor': {
'source_filenames': main_vendor_js,
- 'output_filename': 'js/main_vendor.js',
+ 'output_filename': 'js/lms-main_vendor.js',
},
'module-js': {
'source_filenames': module_js_sources,
- 'output_filename': 'js/modules.js',
+ 'output_filename': 'js/lms-modules.js',
},
'spec': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
- 'output_filename': 'js/spec.js'
+ 'output_filename': 'js/lms-spec.js'
}
}
From ab0055c2013944762d22339e4df19e3ad970c2a6 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Fri, 27 Jul 2012 16:17:06 -0400
Subject: [PATCH 53/55] Add update_schematic to window in schematic.js
---
common/lib/xmodule/xmodule/js/src/capa/schematic.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/common/lib/xmodule/xmodule/js/src/capa/schematic.js b/common/lib/xmodule/xmodule/js/src/capa/schematic.js
index a92bca65cd..56c4bc8195 100644
--- a/common/lib/xmodule/xmodule/js/src/capa/schematic.js
+++ b/common/lib/xmodule/xmodule/js/src/capa/schematic.js
@@ -52,6 +52,7 @@ function update_schematics() {
schematics[i].setAttribute("loaded","true");
}
}
+window.update_schematics = update_schematics;
// add ourselves to the tasks that get performed when window is loaded
function add_schematic_handler(other_onload) {
From 89b5f5b2be37a6cc13226bdefc589ece891fd705 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Mon, 30 Jul 2012 16:11:35 -0400
Subject: [PATCH 54/55] Minor review notes
---
cms/djangoapps/contentstore/management/commands/import.py | 2 +-
cms/djangoapps/github_sync/tests/__init__.py | 5 ++++-
cms/envs/logsettings.py | 1 -
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/cms/djangoapps/contentstore/management/commands/import.py b/cms/djangoapps/contentstore/management/commands/import.py
index 6be03b7850..69aaa35a7d 100644
--- a/cms/djangoapps/contentstore/management/commands/import.py
+++ b/cms/djangoapps/contentstore/management/commands/import.py
@@ -1,5 +1,5 @@
###
-### Script for importing courseware form XML format
+### Script for importing courseware from XML format
###
from django.core.management.base import BaseCommand, CommandError
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
index 39a94abb71..581ac3cb25 100644
--- a/cms/djangoapps/github_sync/tests/__init__.py
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -1,7 +1,10 @@
from django.test import TestCase
from path import path
import shutil
-from github_sync import import_from_github, export_to_github, load_repo_settings, sync_all_with_github, sync_with_github
+from github_sync import (
+ import_from_github, export_to_github, load_repo_settings,
+ sync_all_with_github, sync_with_github
+)
from git import Repo
from django.conf import settings
from xmodule.modulestore.django import modulestore
diff --git a/cms/envs/logsettings.py b/cms/envs/logsettings.py
index 916cd77748..31130e33c6 100644
--- a/cms/envs/logsettings.py
+++ b/cms/envs/logsettings.py
@@ -33,7 +33,6 @@ def get_logger_config(log_dir,
return {
'version': 1,
- 'disable_existing_loggers': True,
'formatters' : {
'standard' : {
'format' : '%(asctime)s %(levelname)s %(process)d [%(name)s] %(filename)s:%(lineno)d - %(message)s',
From 3bb82c41d2882ee480bf9cdea14ca824a2e7ec21 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Mon, 30 Jul 2012 16:21:03 -0400
Subject: [PATCH 55/55] Remove couse css file
---
lms/static/sass/course.css | 5253 ------------------------------------
1 file changed, 5253 deletions(-)
delete mode 100644 lms/static/sass/course.css
diff --git a/lms/static/sass/course.css b/lms/static/sass/course.css
deleted file mode 100644
index 78c7421f5b..0000000000
--- a/lms/static/sass/course.css
+++ /dev/null
@@ -1,5253 +0,0 @@
-@charset "UTF-8";
-/* HTML5 Boilerplate */
-article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
- display: block; }
-
-audio, canvas, video {
- display: inline-block;
- *display: inline;
- *zoom: 1; }
-
-audio:not([controls]) {
- display: none; }
-
-[hidden] {
- display: none; }
-
-html {
- font-size: 100%;
- -webkit-text-size-adjust: 100%;
- -ms-text-size-adjust: 100%; }
-
-html, button, input, select, textarea {
- font-family: sans-serif;
- color: #222; }
-
-body {
- margin: 0;
- font-size: 1em;
- line-height: 1.4; }
-
-::-moz-selection {
- background: #fe57a1;
- color: #fff;
- text-shadow: none; }
-
-::selection {
- background: #fe57a1;
- color: #fff;
- text-shadow: none; }
-
-a {
- color: #00e; }
-
-a:visited {
- color: #551a8b; }
-
-a:hover {
- color: #06e; }
-
-a:focus {
- outline: thin dotted; }
-
-a:hover, a:active {
- outline: 0; }
-
-abbr[title] {
- border-bottom: 1px dotted; }
-
-b, strong {
- font-weight: bold; }
-
-blockquote {
- margin: 1em 40px; }
-
-dfn {
- font-style: italic; }
-
-hr {
- display: block;
- height: 1px;
- border: 0;
- border-top: 1px solid #ccc;
- margin: 1em 0;
- padding: 0; }
-
-ins {
- background: #ff9;
- color: #000;
- text-decoration: none; }
-
-mark {
- background: #ff0;
- color: #000;
- font-style: italic;
- font-weight: bold; }
-
-pre, code, kbd, samp {
- font-family: monospace, serif;
- _font-family: 'courier new', monospace;
- font-size: 1em; }
-
-pre {
- white-space: pre;
- white-space: pre-wrap;
- word-wrap: break-word; }
-
-q {
- quotes: none; }
-
-q:before, q:after {
- content: "";
- content: none; }
-
-small {
- font-size: 85%; }
-
-sub, sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline; }
-
-sup {
- top: -0.5em; }
-
-sub {
- bottom: -0.25em; }
-
-ul, ol {
- margin: 1em 0;
- padding: 0 0 0 40px; }
-
-dd {
- margin: 0 0 0 40px; }
-
-nav ul, nav ol {
- list-style: none;
- list-style-image: none;
- margin: 0;
- padding: 0; }
-
-img {
- border: 0;
- -ms-interpolation-mode: bicubic;
- vertical-align: middle; }
-
-svg:not(:root) {
- overflow: hidden; }
-
-figure {
- margin: 0; }
-
-form {
- margin: 0; }
-
-fieldset {
- border: 0;
- margin: 0;
- padding: 0; }
-
-label {
- cursor: pointer; }
-
-legend {
- border: 0;
- *margin-left: -7px;
- padding: 0;
- white-space: normal; }
-
-button, input, select, textarea {
- font-size: 100%;
- margin: 0;
- vertical-align: baseline;
- *vertical-align: middle; }
-
-button, input {
- line-height: normal; }
-
-button, input[type="button"], input[type="reset"], input[type="submit"] {
- cursor: pointer;
- -webkit-appearance: button;
- *overflow: visible; }
-
-button[disabled], input[disabled] {
- cursor: default; }
-
-input[type="checkbox"], input[type="radio"] {
- box-sizing: border-box;
- padding: 0;
- *width: 13px;
- *height: 13px; }
-
-input[type="search"] {
- -webkit-appearance: textfield;
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box;
- box-sizing: content-box; }
-
-input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button {
- -webkit-appearance: none; }
-
-button::-moz-focus-inner, input::-moz-focus-inner {
- border: 0;
- padding: 0; }
-
-textarea {
- overflow: auto;
- vertical-align: top;
- resize: vertical; }
-
-input:invalid, textarea:invalid {
- background-color: #f0dddd; }
-
-table {
- border-collapse: collapse;
- border-spacing: 0; }
-
-td {
- vertical-align: top; }
-
-.chromeframe {
- margin: 0.2em 0;
- background: #ccc;
- color: black;
- padding: 0.2em 0; }
-
-.ir {
- display: block;
- border: 0;
- text-indent: -999em;
- overflow: hidden;
- background-color: transparent;
- background-repeat: no-repeat;
- text-align: left;
- direction: ltr;
- *line-height: 0; }
-
-.ir br {
- display: none; }
-
-.hidden {
- display: none !important;
- visibility: hidden; }
-
-.visuallyhidden {
- border: 0;
- clip: rect(0 0 0 0);
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position: absolute;
- width: 1px; }
-
-.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus {
- clip: auto;
- height: auto;
- margin: 0;
- overflow: visible;
- position: static;
- width: auto; }
-
-.invisible {
- visibility: hidden; }
-
-.clearfix:before, .topbar:before, nav.sequence-nav:before, div.book-wrapper section.book nav:before, div.course-wrapper section.course-content .problem-set:before, div.course-wrapper section.course-content section.problems-wrapper:before, div.course-wrapper section.course-content div#seq_content:before, div.course-wrapper section.course-content ol.vert-mod > li:before, section.course-content nav.sequence-bottom ul:before, section.course-content div.video article.video-wrapper section.video-controls:before, section.course-content div.video article.video-wrapper section.video-controls div.slider:before, section.tool-wrapper:before, section.tool-wrapper div#controlls-container:before, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:before, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:before, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:before, section.problem-set:before, section.problems-wrapper:before, div.info-wrapper section.updates > ol > li:before, div.info-wrapper section.handouts ol li:before, div.book-wrapper section.book nav ul:before, .clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
- content: "";
- display: table; }
-
-.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
- clear: both; }
-
-.clearfix, .topbar, nav.sequence-nav, div.book-wrapper section.book nav, div.course-wrapper section.course-content .problem-set, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content, div.course-wrapper section.course-content ol.vert-mod > li, section.course-content nav.sequence-bottom ul, section.course-content div.video article.video-wrapper section.video-controls, section.course-content div.video article.video-wrapper section.video-controls div.slider, section.tool-wrapper, section.tool-wrapper div#controlls-container, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders, section.problem-set, section.problems-wrapper, div.info-wrapper section.updates > ol > li, div.info-wrapper section.handouts ol li, div.book-wrapper section.book nav ul {
- *zoom: 1; }
-
-@media print {
- * {
- background: transparent !important;
- color: black !important;
- box-shadow: none !important;
- text-shadow: none !important;
- filter: none !important;
- -ms-filter: none !important; }
-
- a, a:visited {
- text-decoration: underline; }
-
- a[href]:after {
- content: " (" attr(href) ")"; }
-
- abbr[title]:after {
- content: " (" attr(title) ")"; }
-
- .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
- content: ""; }
-
- pre, blockquote {
- border: 1px solid #999;
- page-break-inside: avoid; }
-
- thead {
- display: table-header-group; }
-
- tr, img {
- page-break-inside: avoid; }
-
- img {
- max-width: 100% !important; }
-
- @page {
- margin: 0.5cm; }
-
- p, h2, h3 {
- orphans: 3;
- widows: 3; }
-
- h2, h3 {
- page-break-after: avoid; } }
-/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-Light-webfont.eot");
- src: url("../fonts/OpenSans-Light-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Light-webfont.woff") format("woff"), url("../fonts/OpenSans-Light-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Light-webfont.svg#OpenSansLight") format("svg");
- font-weight: 300;
- font-style: normal; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-LightItalic-webfont.eot");
- src: url("../fonts/OpenSans-LightItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-LightItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-LightItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic") format("svg");
- font-weight: 300;
- font-style: italic; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-Regular-webfont.eot");
- src: url("../fonts/OpenSans-Regular-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Regular-webfont.woff") format("woff"), url("../fonts/OpenSans-Regular-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular") format("svg");
- font-weight: 400;
- font-style: normal; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-Italic-webfont.eot");
- src: url("../fonts/OpenSans-Italic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Italic-webfont.woff") format("woff"), url("../fonts/OpenSans-Italic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic") format("svg");
- font-weight: 400;
- font-style: italic; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-Bold-webfont.eot");
- src: url("../fonts/OpenSans-Bold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-Bold-webfont.woff") format("woff"), url("../fonts/OpenSans-Bold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-Bold-webfont.svg#OpenSansBold") format("svg");
- font-weight: 700;
- font-style: normal; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-BoldItalic-webfont.eot");
- src: url("../fonts/OpenSans-BoldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-BoldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-BoldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic") format("svg");
- font-weight: 700;
- font-style: italic; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-ExtraBold-webfont.eot");
- src: url("../fonts/OpenSans-ExtraBold-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-ExtraBold-webfont.woff") format("woff"), url("../fonts/OpenSans-ExtraBold-webfont.ttf") format("truetype"), url("../fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold") format("svg");
- font-weight: 800;
- font-style: normal; }
-
-@font-face {
- font-family: 'Open Sans';
- src: url("../fonts/OpenSans-ExtraBoldItalic-webfont.eot");
- src: url("../fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.woff") format("woff"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.ttf") format("truetype"), url("../fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic") format("svg");
- font-weight: 800;
- font-style: italic; }
-
-html, body {
- background: #fafafa;
- font-family: "Open Sans", Verdana, Geneva, sans-serif;
- font-size: 1em;
- line-height: 1em; }
-
-h1, h2, h3, h4, h5, h6 {
- color: #3c3c3c;
- font: normal 1.2em/1.2em Georgia, Cambria, "Times New Roman", Times, serif;
- margin: 0px; }
-
-h1 {
- color: #3c3c3c;
- font: normal 2em/1.4em "Open Sans", Verdana, Geneva, sans-serif;
- letter-spacing: 1px;
- margin-bottom: 30px;
- text-align: center; }
-
-h2 {
- color: #a0a0a0;
- font: normal 1.2em/1.2em Georgia, Cambria, "Times New Roman", Times, serif;
- letter-spacing: 1px;
- margin-bottom: 15px;
- text-transform: uppercase;
- -webkit-font-smoothing: antialiased; }
-
-p + h2, ul + h2, ol + h2 {
- margin-top: 40px; }
-
-p {
- color: #3c3c3c;
- font: normal 1em/1.6em Georgia, Cambria, "Times New Roman", Times, serif;
- margin: 0px; }
-
-span {
- font: normal 1em/1.6em "Open Sans", Verdana, Geneva, sans-serif; }
-
-p + p, ul + p, ol + p {
- margin-top: 20px; }
-
-p a:link, p a:visited {
- color: #1d9dd9;
- font: normal 1em/1em Georgia, Cambria, "Times New Roman", Times, serif;
- text-decoration: none;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.1s;
- -moz-transition-duration: 0.1s;
- -ms-transition-duration: 0.1s;
- -o-transition-duration: 0.1s;
- transition-duration: 0.1s;
- -webkit-transition-timing-function: linear;
- -moz-transition-timing-function: linear;
- -ms-transition-timing-function: linear;
- -o-transition-timing-function: linear;
- transition-timing-function: linear;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- p a:link:hover, p a:visited:hover {
- color: #1d9dd9;
- text-decoration: underline; }
-
-a:link, a:visited {
- color: #1d9dd9;
- font: normal 1em/1em "Open Sans", Verdana, Geneva, sans-serif;
- text-decoration: none;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.1s;
- -moz-transition-duration: 0.1s;
- -ms-transition-duration: 0.1s;
- -o-transition-duration: 0.1s;
- transition-duration: 0.1s;
- -webkit-transition-timing-function: linear;
- -moz-transition-timing-function: linear;
- -ms-transition-timing-function: linear;
- -o-transition-timing-function: linear;
- transition-timing-function: linear;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- a:link:hover, a:visited:hover {
- text-decoration: underline; }
-
-.content-wrapper {
- background: white;
- margin: 0 auto 0;
- width: 100%; }
-
-.container {
- zoom: 1;
- margin: 0 auto 0;
- padding: 0px 30px;
- max-width: 1180px;
- min-width: 760px; }
- .container:before, .container:after {
- content: "";
- display: table; }
- .container:after {
- clear: both; }
-
-span.edx {
- text-transform: none;
- font: inherit; }
-
-.static-container {
- zoom: 1;
- margin: 0 auto 0;
- max-width: 1200px;
- padding: 60px 0px 120px;
- width: 100%; }
- .static-container:before, .static-container:after {
- content: "";
- display: table; }
- .static-container:after {
- clear: both; }
- .static-container .inner-wrapper {
- margin: 0 auto 0;
- width: 83.051%; }
- .static-container ol, .static-container ul {
- list-style: disc; }
- .static-container ol li, .static-container ul li {
- color: #3c3c3c;
- font: normal 1em/1.4em Georgia, Cambria, "Times New Roman", Times, serif;
- margin: 0px; }
- .static-container h1 {
- margin-bottom: 30px; }
- .static-container h1 + hr {
- margin-bottom: 60px; }
- .static-container p + h2, .static-container ul + h2, .static-container ol + h2 {
- margin-top: 40px; }
- .static-container ul + p, .static-container ol + p {
- margin-top: 20px; }
-
-.faded-hr-divider, .horizontal-divider {
- background-image: -webkit-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -moz-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -ms-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -o-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- height: 1px;
- width: 100%; }
-
-.faded-hr-divider-medium {
- background-image: -webkit-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
- background-image: -moz-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
- background-image: -ms-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
- background-image: -o-linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
- background-image: linear-gradient(180deg, rgba(240, 240, 240, 0) 0%, #f0f0f0 50%, rgba(240, 240, 240, 0));
- height: 1px;
- width: 100%; }
-
-.faded-hr-divider-light, .horizontal-divider::after {
- background-image: -webkit-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
- background-image: -moz-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
- background-image: -ms-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
- background-image: -o-linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
- background-image: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0));
- height: 1px;
- width: 100%; }
-
-.faded-vertical-divider, .vertical-divider {
- background-image: -webkit-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -moz-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -ms-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: -o-linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- background-image: linear-gradient(90deg, rgba(200, 200, 200, 0) 0%, #c8c8c8 50%, rgba(200, 200, 200, 0));
- height: 100%;
- width: 1px; }
-
-.faded-vertical-divider-light, .vertical-divider::after {
- background-image: -webkit-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
- background-image: -moz-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
- background-image: -ms-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
- background-image: -o-linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
- background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 50%, rgba(255, 255, 255, 0));
- height: 100%;
- width: 1px; }
-
-.vertical-divider {
- position: relative; }
- .vertical-divider::after {
- content: "";
- display: block;
- position: absolute;
- left: 1px; }
-
-.horizontal-divider {
- border: none;
- position: relative; }
- .horizontal-divider::after {
- content: "";
- display: block;
- position: absolute;
- top: 1px; }
-
-.fade-right-hr-divider {
- background-image: -webkit-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
- background-image: -moz-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
- background-image: -ms-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
- background-image: -o-linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
- background-image: linear-gradient(180deg, rgba(200, 200, 200, 0) 0%, #c8c8c8);
- border: none; }
-
-.fade-left-hr-divider {
- background-image: -webkit-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
- background-image: -moz-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
- background-image: -ms-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
- background-image: -o-linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
- background-image: linear-gradient(180deg, #c8c8c8 0%, rgba(200, 200, 200, 0));
- border: none; }
-
-.error-message-colors {
- background: #fd5757;
- border: 1px solid #ca1111;
- color: #8f0e0e; }
-
-.success-message-colors {
- background: #63ec89;
- border: 1px solid #11ca36;
- color: #238f0e; }
-
-.animation-home-header-pop-up {
- -webkit-animation: home-header-pop-up 1.15s ease-in-out;
- -moz-animation: home-header-pop-up 1.15s ease-in-out;
- animation: home-header-pop-up 1.15s ease-in-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 1s;
- -moz-animation-delay: 1s;
- animation-delay: 1s; }
-
-@-webkit-keyframes home-header-pop-up {
- 0% {
- opacity: 0;
- top: 300px; }
-
- 45% {
- opacity: 1; }
-
- 65% {
- top: -40px; }
-
- 85% {
- top: 10px; }
-
- 100% {
- top: 0px; } }
-
-@-moz-keyframes home-header-pop-up {
- 0% {
- opacity: 0;
- top: 300px; }
-
- 45% {
- opacity: 1; }
-
- 65% {
- top: -40px; }
-
- 85% {
- top: 10px; }
-
- 100% {
- top: 0px; } }
-
-@keyframes home-header-pop-up {
- 0% {
- opacity: 0;
- top: 300px; }
-
- 45% {
- opacity: 1; }
-
- 65% {
- top: -40px; }
-
- 85% {
- top: 10px; }
-
- 100% {
- top: 0px; } }
-
-.animation-title-appear {
- -webkit-animation: title-appear 4.65s ease-out;
- -moz-animation: title-appear 4.65s ease-out;
- animation: title-appear 4.65s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 1s;
- -moz-animation-delay: 1s;
- animation-delay: 1s; }
-
-@-webkit-keyframes title-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 27% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 90% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- top: 0px; } }
-
-@-moz-keyframes title-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 27% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 90% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- top: 0px; } }
-
-@keyframes title-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 27% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 90% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- top: 0px; } }
-
-.animation-home-appear {
- -webkit-animation: home-appear 4.25s ease-out;
- -moz-animation: home-appear 4.25s ease-out;
- animation: home-appear 4.25s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 1s;
- -moz-animation-delay: 1s;
- animation-delay: 1s; }
-
-@-webkit-keyframes home-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 30% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 80% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.7);
- -moz-transform: scale(0.7);
- -ms-transform: scale(0.7);
- -o-transform: scale(0.7);
- transform: scale(0.7); } }
-
-@-moz-keyframes home-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 30% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 80% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.7);
- -moz-transform: scale(0.7);
- -ms-transform: scale(0.7);
- -o-transform: scale(0.7);
- transform: scale(0.7); } }
-
-@keyframes home-appear {
- 0% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.9);
- -moz-transform: scale(0.9);
- -ms-transform: scale(0.9);
- -o-transform: scale(0.9);
- transform: scale(0.9); }
-
- 20% {
- opacity: 1; }
-
- 30% {
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 80% {
- opacity: 1;
- top: 40px;
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1); }
-
- 100% {
- opacity: 0;
- top: 60px;
- -webkit-transform: scale(0.7);
- -moz-transform: scale(0.7);
- -ms-transform: scale(0.7);
- -o-transform: scale(0.7);
- transform: scale(0.7); } }
-
-.animation-edx-appear {
- -webkit-animation: edx-appear 1.25s ease-in;
- -moz-animation: edx-appear 1.25s ease-in;
- animation: edx-appear 1.25s ease-in;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 2.15s;
- -moz-animation-delay: 2.15s;
- animation-delay: 2.15s; }
-
-@-webkit-keyframes edx-appear {
- 0% {
- opacity: 0; }
-
- 100% {
- opacity: 1; } }
-
-@-moz-keyframes edx-appear {
- 0% {
- opacity: 0; }
-
- 100% {
- opacity: 1; } }
-
-@keyframes edx-appear {
- 0% {
- opacity: 0; }
-
- 100% {
- opacity: 1; } }
-
-.animation-mit-slide {
- -webkit-animation: mit-slide 1.15s ease-out;
- -moz-animation: mit-slide 1.15s ease-out;
- animation: mit-slide 1.15s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 2s;
- -moz-animation-delay: 2s;
- animation-delay: 2s; }
-
-@-webkit-keyframes mit-slide {
- 0% {
- left: 80px; }
-
- 100% {
- left: 0px; } }
-
-@-moz-keyframes mit-slide {
- 0% {
- left: 80px; }
-
- 100% {
- left: 0px; } }
-
-@keyframes mit-slide {
- 0% {
- left: 80px; }
-
- 100% {
- left: 0px; } }
-
-.animation-harvard-slide {
- -webkit-animation: harvard-slide 1.15s ease-out;
- -moz-animation: harvard-slide 1.15s ease-out;
- animation: harvard-slide 1.15s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 2s;
- -moz-animation-delay: 2s;
- animation-delay: 2s; }
-
-@-webkit-keyframes harvard-slide {
- 0% {
- right: 80px; }
-
- 100% {
- right: 0px; } }
-
-@-moz-keyframes harvard-slide {
- 0% {
- right: 80px; }
-
- 100% {
- right: 0px; } }
-
-@keyframes harvard-slide {
- 0% {
- right: 80px; }
-
- 100% {
- right: 0px; } }
-
-.animation-divider-left-slide {
- -webkit-animation: divider-left-slide 1.1s ease-out;
- -moz-animation: divider-left-slide 1.1s ease-out;
- animation: divider-left-slide 1.1s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 2s;
- -moz-animation-delay: 2s;
- animation-delay: 2s; }
-
-@-webkit-keyframes divider-left-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 200px; } }
-
-@-moz-keyframes divider-left-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 200px; } }
-
-@keyframes divider-left-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 200px; } }
-
-.animation-divider-right-slide {
- -webkit-animation: divider-right-slide 1.1s ease-out;
- -moz-animation: divider-right-slide 1.1s ease-out;
- animation: divider-right-slide 1.1s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 2s;
- -moz-animation-delay: 2s;
- animation-delay: 2s; }
-
-@-webkit-keyframes divider-right-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 480px; } }
-
-@-moz-keyframes divider-right-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 480px; } }
-
-@keyframes divider-right-slide {
- 0% {
- left: 340px; }
-
- 100% {
- left: 480px; } }
-
-.animation-video-appear {
- -webkit-animation: video-appear 1.25s ease-out;
- -moz-animation: video-appear 1.25s ease-out;
- animation: video-appear 1.25s ease-out;
- -webkit-animation-fill-mode: both;
- -moz-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-delay: 4.4s;
- -moz-animation-delay: 4.4s;
- animation-delay: 4.4s; }
-
-@-webkit-keyframes video-appear {
- 0% {
- bottom: -270px;
- opacity: 0.9; }
-
- 80% {
- opacity: 1; }
-
- 100% {
- bottom: 0px; } }
-
-@-moz-keyframes video-appear {
- 0% {
- bottom: -270px;
- opacity: 0.9; }
-
- 80% {
- opacity: 1; }
-
- 100% {
- bottom: 0px; } }
-
-@keyframes video-appear {
- 0% {
- bottom: -270px;
- opacity: 0.9; }
-
- 80% {
- opacity: 1; }
-
- 100% {
- bottom: 0px; } }
-
-nav.course-material {
- background: #d2d2d2;
- zoom: 1;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- -webkit-box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 5px 0 rgba(0, 0, 0, 0.05);
- border-bottom: 1px solid #bebebe;
- margin: 0px auto 0px;
- padding: 0px;
- width: 100%; }
- nav.course-material:before, nav.course-material:after {
- content: "";
- display: table; }
- nav.course-material:after {
- clear: both; }
- nav.course-material .inner-wrapper {
- margin: 0 auto;
- max-width: 1200px;
- width: 100%; }
- nav.course-material ol.course-tabs {
- -webkit-border-top-left-radius: 4px;
- -moz-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- -ms-border-top-left-radius: 4px;
- -o-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- -moz-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- -ms-border-top-right-radius: 4px;
- -o-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
- zoom: 1;
- padding: 10px 0 0 0; }
- nav.course-material ol.course-tabs:before, nav.course-material ol.course-tabs:after {
- content: "";
- display: table; }
- nav.course-material ol.course-tabs:after {
- clear: both; }
- nav.course-material ol.course-tabs li {
- float: left;
- list-style: none; }
- nav.course-material ol.course-tabs li a {
- color: #a0a0a0;
- display: block;
- text-align: center;
- padding: 5px 13px;
- text-decoration: none;
- text-shadow: 0 1px rgba(255, 255, 255, 0.4); }
- nav.course-material ol.course-tabs li a:hover {
- color: #3c3c3c; }
- nav.course-material ol.course-tabs li a.active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_video_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_video_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_other_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_other_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_vertical_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_vertical_active, nav.course-material nav.sequence-nav ol.course-tabs li a.seq_problem_active, nav.sequence-nav nav.course-material ol.course-tabs li a.seq_problem_active {
- background: white;
- border: 1px solid #c8c8c8;
- border-bottom: 0px;
- -webkit-border-top-left-radius: 4px;
- -moz-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- -ms-border-top-left-radius: 4px;
- -o-border-top-left-radius: 4px;
- border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- -moz-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- -ms-border-top-right-radius: 4px;
- -o-border-top-right-radius: 4px;
- border-top-right-radius: 4px;
- -webkit-box-shadow: 0 2px 0 0 white;
- -moz-box-shadow: 0 2px 0 0 white;
- box-shadow: 0 2px 0 0 white;
- color: #3c3c3c; }
-
-.course-content {
- margin-top: 30px; }
- .course-content .courseware {
- min-height: 300px; }
-
-.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content nav.sequence-bottom ul:after, section.course-content div.video article.video-wrapper section.video-controls:after, section.course-content div.video article.video-wrapper section.video-controls div.slider:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, section.problem-set:after, section.problems-wrapper:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.book-wrapper section.book nav ul:after {
- clear: both;
- content: ".";
- display: block;
- height: 0;
- visibility: hidden; }
-
-.wrapper {
- margin: 0 auto;
- max-width: 1400px;
- min-width: 810px;
- text-align: left;
- width: 100%; }
- .wrapper div.table-wrapper, .wrapper div.course-wrapper, .wrapper div.info-wrapper, .wrapper div.book-wrapper {
- display: table;
- width: 100%;
- overflow: hidden; }
- @media screen and (min-width: 1400px) {
- .wrapper div.table-wrapper, .wrapper div.course-wrapper, .wrapper div.info-wrapper, .wrapper div.book-wrapper {
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- -ms-border-radius: 4px;
- -o-border-radius: 4px;
- border-radius: 4px; } }
-
-h1.top-header, div.course-wrapper section.course-content ol.vert-mod > li header, div.info-wrapper section.updates > h1 {
- background: #f3f3f3;
- border-bottom: 1px solid #e3e3e3;
- margin: -lh() -lh() lh();
- padding: lh(); }
-
-.button {
- border: 1px solid #6f6f6f;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
- -moz-box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
- box-shadow: inset 0 1px 0 #a2a2a2, 0 0 3px #cccccc;
- color: #fff;
- cursor: pointer;
- font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- background-color: #959595;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #959595), color-stop(100%, #7b7b7b));
- background-image: -webkit-linear-gradient(top, #959595, #7b7b7b);
- background-image: -moz-linear-gradient(top, #959595, #7b7b7b);
- background-image: -ms-linear-gradient(top, #959595, #7b7b7b);
- background-image: -o-linear-gradient(top, #959595, #7b7b7b);
- background-image: linear-gradient(top, #959595, #7b7b7b);
- padding: 4px 8px;
- text-decoration: none;
- text-shadow: none;
- -webkit-font-smoothing: antialiased; }
- .button:hover, .button:focus {
- border: 1px solid #555555;
- -webkit-box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
- -moz-box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
- box-shadow: inset 0 1px 0 #bbbbbb, 0 0 3px #cccccc;
- background-color: #a2a2a2;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a2a2a2), color-stop(100%, #7b7b7b));
- background-image: -webkit-linear-gradient(top, #a2a2a2, #7b7b7b);
- background-image: -moz-linear-gradient(top, #a2a2a2, #7b7b7b);
- background-image: -ms-linear-gradient(top, #a2a2a2, #7b7b7b);
- background-image: -o-linear-gradient(top, #a2a2a2, #7b7b7b);
- background-image: linear-gradient(top, #a2a2a2, #7b7b7b); }
-
-.light-button, a.light-button {
- border: 1px solid #ccc;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 0 white;
- -moz-box-shadow: inset 0 1px 0 white;
- box-shadow: inset 0 1px 0 white;
- color: #666;
- cursor: pointer;
- font: normal 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- background-color: white;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #eeeeee));
- background-image: -webkit-linear-gradient(top, white, #eeeeee);
- background-image: -moz-linear-gradient(top, white, #eeeeee);
- background-image: -ms-linear-gradient(top, white, #eeeeee);
- background-image: -o-linear-gradient(top, white, #eeeeee);
- background-image: linear-gradient(top, white, #eeeeee);
- padding: 4px 8px;
- text-decoration: none;
- -webkit-font-smoothing: antialiased; }
- .light-button:hover, .light-button:focus, a.light-button:hover, a.light-button:focus {
- border: 1px solid #ccc;
- background-color: white;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #e6e6e6));
- background-image: -webkit-linear-gradient(top, white, #e6e6e6);
- background-image: -moz-linear-gradient(top, white, #e6e6e6);
- background-image: -ms-linear-gradient(top, white, #e6e6e6);
- background-image: -o-linear-gradient(top, white, #e6e6e6);
- background-image: linear-gradient(top, white, #e6e6e6);
- text-decoration: none; }
-
-.action-link a {
- color: #993333; }
- .action-link a:hover {
- color: #4d1919;
- text-decoration: none; }
-
-.content, div.course-wrapper section.course-content, div.info-wrapper section.updates, div.book-wrapper section.book {
- -webkit-box-shadow: inset 0 0 2px 3px #f3f3f3;
- -moz-box-shadow: inset 0 0 2px 3px #f3f3f3;
- box-shadow: inset 0 0 2px 3px #f3f3f3;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- padding: lh();
- vertical-align: top;
- width: 76.518%;
- overflow: hidden; }
- @media print {
- .content, div.course-wrapper section.course-content, div.info-wrapper section.updates, div.book-wrapper section.book {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none; } }
-
-.sidebar, section.course-index, div.info-wrapper section.handouts, div.book-wrapper section.book-sidebar {
- background: #e3e3e3;
- -webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- -ms-border-radius: 4px 0 0 4px;
- -o-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
- border-right: 1px solid #d3d3d3;
- -webkit-box-shadow: inset 0 0 0 1px #f6f6f6;
- -moz-box-shadow: inset 0 0 0 1px #f6f6f6;
- box-shadow: inset 0 0 0 1px #f6f6f6;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- position: relative;
- text-shadow: 0 1px 0 #f1f1f1;
- vertical-align: top;
- width: 23.482%; }
- .sidebar h1, section.course-index h1, div.info-wrapper section.handouts h1, div.book-wrapper section.book-sidebar h1, .sidebar h2, section.course-index h2, div.info-wrapper section.handouts h2, div.book-wrapper section.book-sidebar h2 {
- font-size: 18px;
- font-weight: bold;
- letter-spacing: 0;
- text-transform: none; }
- .sidebar a, section.course-index a, div.info-wrapper section.handouts a, div.book-wrapper section.book-sidebar a {
- border: none;
- font-style: normal; }
- .sidebar .bottom-border, section.course-index .bottom-border, div.info-wrapper section.handouts .bottom-border, div.book-wrapper section.book-sidebar .bottom-border, .sidebar div.info-wrapper section.handouts header, div.info-wrapper section.handouts .sidebar header, section.course-index div.info-wrapper section.handouts header, div.info-wrapper section.handouts section.course-index header, div.info-wrapper section.handouts header, div.book-wrapper section.book-sidebar div.info-wrapper section.handouts header, div.info-wrapper section.handouts div.book-wrapper section.book-sidebar header {
- border-bottom: 1px solid #d3d3d3;
- -webkit-box-shadow: 0 1px 0 #eeeeee;
- -moz-box-shadow: 0 1px 0 #eeeeee;
- box-shadow: 0 1px 0 #eeeeee; }
- @media print {
- .sidebar, section.course-index, div.info-wrapper section.handouts, div.book-wrapper section.book-sidebar {
- display: none; } }
- .sidebar h3, section.course-index h3, div.info-wrapper section.handouts h3, div.book-wrapper section.book-sidebar h3 {
- background: none;
- border: none;
- color: #000;
- font-weight: normal;
- margin: 0;
- overflow: hidden; }
- .sidebar h3 a, section.course-index h3 a, div.info-wrapper section.handouts h3 a, div.book-wrapper section.book-sidebar h3 a {
- color: #4d4d4d;
- display: block;
- font-size: 14px;
- padding: 7px 7px 7px 30px;
- text-decoration: none;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- .sidebar h3 span.ui-icon, section.course-index h3 span.ui-icon, div.info-wrapper section.handouts h3 span.ui-icon, div.book-wrapper section.book-sidebar h3 span.ui-icon {
- background-image: url(../images/ui-icons_454545_256x240.png); }
- .sidebar h3.active, section.course-index h3.active, div.info-wrapper section.handouts h3.active, div.book-wrapper section.book-sidebar h3.active, .sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion .sidebar h3.ui-accordion-header.ui-state-active, section.course-index div#accordion h3.ui-accordion-header.ui-state-active, div.info-wrapper section.handouts section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion div.info-wrapper section.handouts h3.ui-accordion-header.ui-state-active, div.book-wrapper section.book-sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion div.book-wrapper section.book-sidebar h3.ui-accordion-header.ui-state-active {
- background: none;
- background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- border-bottom: 1px solid #d3d3d3;
- -webkit-box-shadow: inset 0 1px 0 0 #eeeeee;
- -moz-box-shadow: inset 0 1px 0 0 #eeeeee;
- box-shadow: inset 0 1px 0 0 #eeeeee;
- color: #000;
- font-weight: bold; }
- .sidebar h3.active a, section.course-index h3.active a, div.info-wrapper section.handouts h3.active a, div.book-wrapper section.book-sidebar h3.active a, .sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion .sidebar h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, div.info-wrapper section.handouts section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion div.info-wrapper section.handouts h3.ui-accordion-header.ui-state-active a, div.book-wrapper section.book-sidebar section.course-index div#accordion h3.ui-accordion-header.ui-state-active a, section.course-index div#accordion div.book-wrapper section.book-sidebar h3.ui-accordion-header.ui-state-active a {
- color: #000; }
- .sidebar header#open_close_accordion, section.course-index header#open_close_accordion, div.info-wrapper section.handouts header#open_close_accordion, div.book-wrapper section.book-sidebar header#open_close_accordion {
- border-bottom: 1px solid #d3d3d3;
- -webkit-box-shadow: 0 1px 0 #eeeeee;
- -moz-box-shadow: 0 1px 0 #eeeeee;
- box-shadow: 0 1px 0 #eeeeee;
- padding: lh(0.5) lh();
- position: relative; }
- .sidebar header#open_close_accordion h2, section.course-index header#open_close_accordion h2, div.info-wrapper section.handouts header#open_close_accordion h2, div.book-wrapper section.book-sidebar header#open_close_accordion h2 {
- margin: 0;
- padding-right: 20px; }
- .sidebar header#open_close_accordion a, section.course-index header#open_close_accordion a, div.info-wrapper section.handouts header#open_close_accordion a, div.book-wrapper section.book-sidebar header#open_close_accordion a {
- background: #eeeeee url("../images/slide-left-icon.png") center center no-repeat;
- border: 1px solid #D3D3D3;
- -webkit-border-radius: 3px 0 0 3px;
- -moz-border-radius: 3px 0 0 3px;
- -ms-border-radius: 3px 0 0 3px;
- -o-border-radius: 3px 0 0 3px;
- border-radius: 3px 0 0 3px;
- height: 16px;
- padding: 8px;
- position: absolute;
- right: -1px;
- text-indent: -9999px;
- top: 6px;
- width: 16px; }
- .sidebar header#open_close_accordion a:hover, section.course-index header#open_close_accordion a:hover, div.info-wrapper section.handouts header#open_close_accordion a:hover, div.book-wrapper section.book-sidebar header#open_close_accordion a:hover {
- background-color: white; }
- .sidebar a.button, section.course-index a.button, div.info-wrapper section.handouts a.button, div.book-wrapper section.book-sidebar a.button {
- text-decoration: none; }
-
-.topbar, nav.sequence-nav, div.book-wrapper section.book nav {
- background: #f6efd4;
- border-bottom: 1px solid #eddfaa;
- border-top: 1px solid #fff;
- font-size: 12px;
- line-height: 46px;
- text-shadow: 0 1px 0 #fff; }
- @media print {
- .topbar, nav.sequence-nav, div.book-wrapper section.book nav {
- display: none; } }
- .topbar a, nav.sequence-nav a, div.book-wrapper section.book nav a {
- line-height: 46px;
- border-bottom: 0;
- color: #292309; }
- .topbar a:hover, nav.sequence-nav a:hover, div.book-wrapper section.book nav a:hover {
- color: #7e691a;
- text-decoration: none; }
- .topbar a.block-link, nav.sequence-nav a.block-link, div.book-wrapper section.book nav a.block-link, .topbar nav.sequence-nav ol a, nav.sequence-nav ol .topbar a, nav.sequence-nav ol a, div.book-wrapper section.book nav.sequence-nav ol a, .topbar div.book-wrapper section.book nav a, div.book-wrapper section.book nav .topbar a, div.book-wrapper section.book nav.sequence-nav a, div.book-wrapper section.book nav a {
- border-left: 1px solid #e4d080;
- -webkit-box-shadow: inset 1px 0 0 #faf7e9;
- -moz-box-shadow: inset 1px 0 0 #faf7e9;
- box-shadow: inset 1px 0 0 #faf7e9;
- display: block;
- text-transform: uppercase; }
- .topbar a.block-link:hover, nav.sequence-nav a.block-link:hover, div.book-wrapper section.book nav a.block-link:hover, .topbar nav.sequence-nav ol a:hover, nav.sequence-nav ol .topbar a:hover, nav.sequence-nav ol a:hover, div.book-wrapper section.book nav.sequence-nav ol a:hover, .topbar div.book-wrapper section.book nav a:hover, div.book-wrapper section.book nav .topbar a:hover, div.book-wrapper section.book nav.sequence-nav a:hover, div.book-wrapper section.book nav a:hover {
- background: none; }
-
-.tran, section.course-index, div.book-wrapper section.book-sidebar {
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.2s;
- -moz-transition-duration: 0.2s;
- -ms-transition-duration: 0.2s;
- -o-transition-duration: 0.2s;
- transition-duration: 0.2s;
- -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
-
-p.ie-warning {
- background: yellow;
- display: block !important;
- line-height: 1.3em;
- margin-bottom: 0;
- padding: lh();
- text-align: left; }
-
-html {
- height: 100%;
- max-height: 100%; }
-
-body.courseware {
- height: 100%;
- max-height: 100%; }
- body.courseware .container {
- margin-bottom: 40px;
- margin-top: 20px; }
- body.courseware footer.fixed-bottom {
- Position: static; }
-
-div.course-wrapper ul, div.course-wrapper ol {
- list-style: none; }
-div.course-wrapper section.course-content {
- -webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- -ms-border-radius: 0 4px 4px 0;
- -o-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0; }
- div.course-wrapper section.course-content h1 {
- margin: 0 0 22.652px; }
- div.course-wrapper section.course-content p {
- margin-bottom: 22.652px; }
- div.course-wrapper section.course-content p:empty {
- display: none;
- margin-bottom: 0; }
- div.course-wrapper section.course-content ul li {
- margin-bottom: 11.326px; }
- div.course-wrapper section.course-content .problem-set, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content, div.course-wrapper section.course-content ol.vert-mod > li, div.course-wrapper section.course-content section.problems-wrapper, div.course-wrapper section.course-content div#seq_content {
- position: relative; }
- div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
- margin-top: 0;
- margin-bottom: 15px;
- width: 20.109%;
- padding-right: 2.717%;
- border-right: 1px dashed #ddd;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- vertical-align: top; }
- div.course-wrapper section.course-content .problem-set h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, div.course-wrapper section.course-content div#seq_content h2.problem-header section.staff, div.course-wrapper section.course-content ol.vert-mod > li h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, div.course-wrapper section.course-content div#seq_content h2.problem-header section.staff {
- margin-top: 30px;
- font-size: 80%; }
- @media screen and (max-width:1120px) {
- div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
- display: block;
- width: auto;
- border-right: 0; } }
- @media print {
- div.course-wrapper section.course-content .problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2, div.course-wrapper section.course-content ol.vert-mod > li h2, div.course-wrapper section.course-content section.problems-wrapper h2, div.course-wrapper section.course-content div#seq_content h2 {
- display: block;
- width: auto;
- border-right: 0; } }
- div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
- display: table-cell;
- width: 77.174%;
- padding-left: 2.717%; }
- @media screen and (max-width:1120px) {
- div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
- display: block;
- width: auto;
- padding: 0; } }
- @media print {
- div.course-wrapper section.course-content .problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem, div.course-wrapper section.course-content ol.vert-mod > li section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, div.course-wrapper section.course-content div#seq_content section.problem {
- display: block;
- width: auto;
- padding: 0; }
- div.course-wrapper section.course-content .problem-set section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, div.course-wrapper section.course-content div#seq_content section.problem canvas, div.course-wrapper section.course-content ol.vert-mod > li section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, div.course-wrapper section.course-content div#seq_content section.problem canvas, div.course-wrapper section.course-content .problem-set section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, div.course-wrapper section.course-content div#seq_content section.problem img, div.course-wrapper section.course-content ol.vert-mod > li section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, div.course-wrapper section.course-content div#seq_content section.problem img {
- page-break-inside: avoid; } }
- div.course-wrapper section.course-content .problem-set section.problem span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem span.unanswered, div.course-wrapper section.course-content div#seq_content section.problem span.unanswered, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem span.unanswered, div.course-wrapper section.course-content div#seq_content section.problem span.unanswered, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-bullet, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-bullet, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-bullet, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-bullet {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/unanswered-icon.png") center center no-repeat;
- height: 14px;
- position: relative;
- top: 4px;
- width: 14px; }
- div.course-wrapper section.course-content .problem-set section.problem span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem span.correct, div.course-wrapper section.course-content div#seq_content section.problem span.correct, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem span.correct, div.course-wrapper section.course-content div#seq_content section.problem span.correct, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-check, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-check, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-check, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-check {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/correct-icon.png") center center no-repeat;
- height: 20px;
- position: relative;
- top: 6px;
- width: 25px; }
- div.course-wrapper section.course-content .problem-set section.problem span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem span.incorrect, div.course-wrapper section.course-content div#seq_content section.problem span.incorrect, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem span.incorrect, div.course-wrapper section.course-content div#seq_content section.problem span.incorrect, div.course-wrapper section.course-content .problem-set section.problem span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-close, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-close, div.course-wrapper section.course-content ol.vert-mod > li section.problem span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem span.ui-icon-close, div.course-wrapper section.course-content div#seq_content section.problem span.ui-icon-close {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/incorrect-icon.png") center center no-repeat;
- height: 20px;
- width: 20px;
- position: relative;
- top: 6px; }
- div.course-wrapper section.course-content .problem-set div > span, div.course-wrapper section.course-content section.problems-wrapper div > span, div.course-wrapper section.course-content div#seq_content div > span, div.course-wrapper section.course-content ol.vert-mod > li div > span, div.course-wrapper section.course-content section.problems-wrapper div > span, div.course-wrapper section.course-content div#seq_content div > span {
- display: block;
- margin-bottom: 11.326px; }
- div.course-wrapper section.course-content .problem-set div > span[answer], div.course-wrapper section.course-content section.problems-wrapper div > span[answer], div.course-wrapper section.course-content div#seq_content div > span[answer], div.course-wrapper section.course-content ol.vert-mod > li div > span[answer], div.course-wrapper section.course-content section.problems-wrapper div > span[answer], div.course-wrapper section.course-content div#seq_content div > span[answer] {
- border-top: 1px solid #ededed;
- border-bottom: 1px solid #ededed;
- background: #f3f3f3;
- margin: 0 -22.652px;
- padding: 11.326px 22.652px; }
- div.course-wrapper section.course-content .problem-set input[type="text"], div.course-wrapper section.course-content section.problems-wrapper input[type="text"], div.course-wrapper section.course-content div#seq_content input[type="text"], div.course-wrapper section.course-content ol.vert-mod > li input[type="text"], div.course-wrapper section.course-content section.problems-wrapper input[type="text"], div.course-wrapper section.course-content div#seq_content input[type="text"] {
- display: inline-block;
- width: 50%; }
- div.course-wrapper section.course-content .problem-set center, div.course-wrapper section.course-content section.problems-wrapper center, div.course-wrapper section.course-content div#seq_content center, div.course-wrapper section.course-content ol.vert-mod > li center, div.course-wrapper section.course-content section.problems-wrapper center, div.course-wrapper section.course-content div#seq_content center {
- display: block;
- margin: 22.652px 0;
- border: 1px solid #ccc;
- padding: 22.652px; }
- div.course-wrapper section.course-content .problem-set section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, div.course-wrapper section.course-content div#seq_content section.action, div.course-wrapper section.course-content ol.vert-mod > li section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, div.course-wrapper section.course-content div#seq_content section.action {
- margin-top: 22.652px; }
- div.course-wrapper section.course-content .problem-set section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], div.course-wrapper section.course-content div#seq_content section.action input[type="button"], div.course-wrapper section.course-content ol.vert-mod > li section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], div.course-wrapper section.course-content div#seq_content section.action input[type="button"] {
- padding: 9.061px 22.652px;
- text-shadow: 0 -1px 0 #666666; }
- div.course-wrapper section.course-content section.problems-wrapper {
- display: table;
- width: 100%; }
- @media screen and (max-width:1120px) {
- div.course-wrapper section.course-content section.problems-wrapper {
- display: block;
- width: auto; } }
- div.course-wrapper section.course-content div#seq_content h1 {
- background: none;
- margin-bottom: 22.652px;
- padding-bottom: 0;
- border-bottom: none; }
- div.course-wrapper section.course-content ol.vert-mod > li {
- border-bottom: 1px solid #ddd;
- margin-bottom: 15px;
- padding: 0 0 15px; }
- div.course-wrapper section.course-content ol.vert-mod > li header {
- -webkit-border-radius: 0 4px 0 0;
- -moz-border-radius: 0 4px 0 0;
- -ms-border-radius: 0 4px 0 0;
- -o-border-radius: 0 4px 0 0;
- border-radius: 0 4px 0 0;
- margin-bottom: -16px; }
- div.course-wrapper section.course-content ol.vert-mod > li header h1 {
- margin: 0; }
- div.course-wrapper section.course-content ol.vert-mod > li header h2 {
- float: right;
- margin-right: 0;
- margin-top: 8px;
- text-align: right;
- padding-right: 0;
- border-right: 0; }
- div.course-wrapper section.course-content ol.vert-mod > li:last-child {
- border-bottom: none;
- margin-bottom: 0;
- padding-bottom: 0; }
- div.course-wrapper section.course-content ol.vert-mod > li .histogram {
- width: 200px;
- height: 150px; }
- div.course-wrapper section.course-content ol.vert-mod > li ul {
- list-style: disc outside none;
- padding-left: 1em; }
- div.course-wrapper section.course-content ol.vert-mod > li nav.sequence-bottom ul {
- list-style: none;
- padding: 0; }
- div.course-wrapper section.course-content section.tutorials h2 {
- margin-bottom: 22.652px; }
- div.course-wrapper section.course-content section.tutorials ul {
- margin: 0;
- zoom: 1; }
- div.course-wrapper section.course-content section.tutorials ul:before, div.course-wrapper section.course-content section.tutorials ul:after {
- content: "";
- display: table; }
- div.course-wrapper section.course-content section.tutorials ul:after {
- clear: both; }
- div.course-wrapper section.course-content section.tutorials ul li {
- width: 31.522%;
- float: left;
- margin-right: 2.717%;
- margin-bottom: 22.652px; }
- div.course-wrapper section.course-content section.tutorials ul li:nth-child(3n) {
- margin-right: 0; }
- div.course-wrapper section.course-content section.tutorials ul li:nth-child(3n+1) {
- clear: both; }
- div.course-wrapper section.course-content section.tutorials ul li a {
- font-weight: bold; }
- div.course-wrapper section.course-content div.staff_info {
- zoom: 1;
- white-space: pre-wrap;
- border-top: 1px solid #ccc;
- padding-top: 22.652px;
- margin-top: 22.652px;
- line-height: 22.652px;
- font-family: Consolas, "Lucida Console", Monaco, "Courier New", Courier, monospace; }
- div.course-wrapper section.course-content div.staff_info:before, div.course-wrapper section.course-content div.staff_info:after {
- content: "";
- display: table; }
- div.course-wrapper section.course-content div.staff_info:after {
- clear: both; }
- div.course-wrapper section.course-content div.ui-slider {
- border: 1px solid #aaa;
- background: #ddd;
- -webkit-box-shadow: inset 0 1px 0 #eeeeee;
- -moz-box-shadow: inset 0 1px 0 #eeeeee;
- box-shadow: inset 0 1px 0 #eeeeee;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0; }
- div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle {
- -webkit-box-shadow: inset 0 1px 0 #bf4040;
- -moz-box-shadow: inset 0 1px 0 #bf4040;
- box-shadow: inset 0 1px 0 #bf4040;
- background: #993333 url(../images/slider-bars.png) center center no-repeat;
- border: 1px solid #4d1919;
- cursor: pointer; }
- div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle:hover, div.course-wrapper section.course-content div.ui-slider a.ui-slider-handle:focus {
- background-color: #bf4040;
- outline: none; }
- div.course-wrapper section.course-content div.ui-tabs {
- border: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- margin: 0;
- padding: 0; }
- div.course-wrapper section.course-content div.ui-tabs .ui-tabs-nav {
- background: none;
- border: 0;
- margin-bottom: 11.326px; }
- div.course-wrapper section.course-content div.ui-tabs .ui-tabs-panel {
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- padding: 0; }
-div.course-wrapper.closed section.course-index {
- width: 3.077%;
- overflow: hidden; }
- div.course-wrapper.closed section.course-index header#open_close_accordion {
- padding: 0;
- min-height: 47px; }
- div.course-wrapper.closed section.course-index header#open_close_accordion a {
- background-image: url("../images/slide-right-icon.png"); }
- div.course-wrapper.closed section.course-index header#open_close_accordion h2 {
- visibility: hidden;
- width: 10px; }
- div.course-wrapper.closed section.course-index div#accordion {
- visibility: hidden;
- width: 10px;
- padding: 0; }
- div.course-wrapper.closed section.course-index div#accordion nav {
- white-space: pre;
- overflow: hidden; }
- div.course-wrapper.closed section.course-index div#accordion nav ul {
- overflow: hidden;
- white-space: nowrap; }
-div.course-wrapper.closed section.course-content {
- width: 97.773%; }
-
-nav.sequence-nav {
- border-bottom: 1px solid #e4d080;
- margin-bottom: 22.652px;
- position: relative;
- -webkit-border-top-right-radius: 4px;
- -moz-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- -ms-border-top-right-radius: 4px;
- -o-border-top-right-radius: 4px;
- border-top-right-radius: 4px; }
- nav.sequence-nav ol {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table;
- height: 100%;
- padding-right: 8.696%;
- width: 100%; }
- nav.sequence-nav ol li {
- border-left: 1px solid #e4d080;
- display: table-cell;
- min-width: 20px; }
- nav.sequence-nav ol li:first-child {
- border-left: none; }
- nav.sequence-nav ol li .inactive, nav.sequence-nav ol li a.seq_video_inactive, nav.sequence-nav ol li a.seq_other_inactive, nav.sequence-nav ol li a.seq_vertical_inactive, nav.sequence-nav ol li a.seq_problem_inactive {
- background-repeat: no-repeat; }
- nav.sequence-nav ol li .inactive:hover, nav.sequence-nav ol li a.seq_video_inactive:hover, nav.sequence-nav ol li a.seq_other_inactive:hover, nav.sequence-nav ol li a.seq_vertical_inactive:hover, nav.sequence-nav ol li a.seq_problem_inactive:hover {
- background-color: #f9f4e1; }
- nav.sequence-nav ol li .visited, nav.sequence-nav ol li a.seq_video_visited, nav.sequence-nav ol li a.seq_other_visited, nav.sequence-nav ol li a.seq_vertical_visited, nav.sequence-nav ol li a.seq_problem_visited {
- background-color: #DCCDA2;
- background-repeat: no-repeat;
- -webkit-box-shadow: inset 0 0 3px #ceb97d;
- -moz-box-shadow: inset 0 0 3px #ceb97d;
- box-shadow: inset 0 0 3px #ceb97d; }
- nav.sequence-nav ol li .visited:hover, nav.sequence-nav ol li a.seq_video_visited:hover, nav.sequence-nav ol li a.seq_other_visited:hover, nav.sequence-nav ol li a.seq_vertical_visited:hover, nav.sequence-nav ol li a.seq_problem_visited:hover {
- background-color: #f6efd4;
- background-position: center center; }
- nav.sequence-nav ol li .active, nav.sequence-nav ol li a.seq_video_active, nav.sequence-nav ol li a.seq_other_active, nav.sequence-nav ol li a.seq_vertical_active, nav.sequence-nav ol li a.seq_problem_active, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active {
- background-color: #fff;
- background-repeat: no-repeat;
- -webkit-box-shadow: 0 1px 0 white;
- -moz-box-shadow: 0 1px 0 white;
- box-shadow: 0 1px 0 white; }
- nav.sequence-nav ol li .active:hover, nav.sequence-nav ol li a.seq_video_active:hover, nav.sequence-nav ol li a.seq_other_active:hover, nav.sequence-nav ol li a.seq_vertical_active:hover, nav.sequence-nav ol li a.seq_problem_active:hover, nav.sequence-nav ol li section.course-index div#accordion h3.ui-accordion-header.ui-state-active:hover, section.course-index div#accordion nav.sequence-nav ol li h3.ui-accordion-header.ui-state-active:hover {
- background-color: #fff;
- background-position: center; }
- nav.sequence-nav ol li a {
- background-position: center center;
- border: none;
- cursor: pointer;
- display: block;
- height: 17px;
- padding: 15px 0 14px;
- position: relative;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.4s;
- -moz-transition-duration: 0.4s;
- -ms-transition-duration: 0.4s;
- -o-transition-duration: 0.4s;
- transition-duration: 0.4s;
- -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 100%; }
- nav.sequence-nav ol li a.progress, nav.sequence-nav ol li a.progress-none, nav.sequence-nav ol li a.progress-some, nav.sequence-nav ol li a.progress-done {
- border-bottom-style: solid;
- border-bottom-width: 4px; }
- nav.sequence-nav ol li a.progress-none {
- border-bottom-color: red; }
- nav.sequence-nav ol li a.progress-some {
- border-bottom-color: yellow; }
- nav.sequence-nav ol li a.progress-done {
- border-bottom-color: green; }
- nav.sequence-nav ol li a.seq_video_inactive {
- background-image: url("../images/sequence-nav/video-icon-normal.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_video_visited {
- background-image: url("../images/sequence-nav/video-icon-visited.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_video_active {
- background-image: url("../images/sequence-nav/video-icon-current.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_other_inactive {
- background-image: url("../images/sequence-nav/document-icon-normal.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_other_visited {
- background-image: url("../images/sequence-nav/document-icon-visited.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_other_active {
- background-image: url("../images/sequence-nav/document-icon-current.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_vertical_inactive, nav.sequence-nav ol li a.seq_problem_inactive {
- background-image: url("../images/sequence-nav/list-icon-normal.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_vertical_visited, nav.sequence-nav ol li a.seq_problem_visited {
- background-image: url("../images/sequence-nav/list-icon-visited.png");
- background-position: center; }
- nav.sequence-nav ol li a.seq_vertical_active, nav.sequence-nav ol li a.seq_problem_active {
- background-image: url("../images/sequence-nav/list-icon-current.png");
- background-position: center; }
- nav.sequence-nav ol li a p {
- background: #333;
- color: #fff;
- display: none;
- line-height: 22.652px;
- left: 0px;
- opacity: 0;
- padding: 6px;
- position: absolute;
- top: 48px;
- text-shadow: 0 -1px 0 black;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.1s;
- -moz-transition-duration: 0.1s;
- -ms-transition-duration: 0.1s;
- -o-transition-duration: 0.1s;
- transition-duration: 0.1s;
- -webkit-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
- -moz-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
- -ms-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
- -o-transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
- transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- white-space: pre;
- z-index: 99; }
- nav.sequence-nav ol li a p:empty {
- background: none; }
- nav.sequence-nav ol li a p:empty::after {
- display: none; }
- nav.sequence-nav ol li a p::after {
- background: #333;
- content: " ";
- display: block;
- height: 10px;
- left: 18px;
- position: absolute;
- top: -5px;
- -webkit-transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -o-transform: rotate(45deg);
- transform: rotate(45deg);
- width: 10px; }
- nav.sequence-nav ol li a:hover p {
- display: block;
- margin-top: 4px;
- opacity: 1; }
- nav.sequence-nav ul {
- list-style: none;
- height: 100%;
- position: absolute;
- right: 0;
- top: 0;
- width: 8.696%; }
- nav.sequence-nav ul li {
- float: left;
- width: 50%; }
- nav.sequence-nav ul li.prev a, nav.sequence-nav ul li.next a {
- background-color: #f2e7bf;
- background-position: center center;
- background-repeat: no-repeat;
- border-left: 1px solid #e4d080;
- -webkit-box-shadow: inset 1px 0 0 #faf7e9;
- -moz-box-shadow: inset 1px 0 0 #faf7e9;
- box-shadow: inset 1px 0 0 #faf7e9;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- cursor: pointer;
- display: block;
- text-indent: -9999px;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.2s;
- -moz-transition-duration: 0.2s;
- -ms-transition-duration: 0.2s;
- -o-transition-duration: 0.2s;
- transition-duration: 0.2s;
- -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- nav.sequence-nav ul li.prev a:hover, nav.sequence-nav ul li.next a:hover {
- opacity: .5; }
- nav.sequence-nav ul li.prev a.disabled, nav.sequence-nav ul li.next a.disabled {
- cursor: normal;
- opacity: .4; }
- nav.sequence-nav ul li.prev a {
- background-image: url("../images/sequence-nav/previous-icon.png"); }
- nav.sequence-nav ul li.prev a:hover {
- background-color: #f6efd4; }
- nav.sequence-nav ul li.next a {
- background-image: url("../images/sequence-nav/next-icon.png"); }
- nav.sequence-nav ul li.next a:hover {
- background-color: #f6efd4; }
- body.touch-based-device nav.sequence-nav ol li a:hover p {
- display: none; }
-
-section.course-content {
- position: relative; }
- section.course-content ol.vert-mod nav.sequence-nav {
- margin-top: -15px;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0; }
- section.course-content nav.sequence-bottom {
- margin: 45.304px 0 0;
- text-align: center; }
- section.course-content nav.sequence-bottom ul {
- background-color: #f2e7bf;
- background-color: #f2e7bf;
- border: 1px solid #e4d080;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 0 0 1px #faf7e9;
- -moz-box-shadow: inset 0 0 0 1px #faf7e9;
- box-shadow: inset 0 0 0 1px #faf7e9;
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto; }
- section.course-content nav.sequence-bottom ul li {
- float: left; }
- section.course-content nav.sequence-bottom ul li.prev, section.course-content nav.sequence-bottom ul li.next {
- margin-bottom: 0; }
- section.course-content nav.sequence-bottom ul li.prev a, section.course-content nav.sequence-bottom ul li.next a {
- background-position: center center;
- background-repeat: no-repeat;
- border-bottom: none;
- display: block;
- padding: 11.326px 4px;
- text-indent: -9999px;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.2s;
- -moz-transition-duration: 0.2s;
- -ms-transition-duration: 0.2s;
- -o-transition-duration: 0.2s;
- transition-duration: 0.2s;
- -webkit-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -moz-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -ms-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -o-transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 45px; }
- section.course-content nav.sequence-bottom ul li.prev a:hover, section.course-content nav.sequence-bottom ul li.next a:hover {
- background-color: #f6efd4;
- color: #7e691a;
- opacity: .5;
- text-decoration: none; }
- section.course-content nav.sequence-bottom ul li.prev a.disabled, section.course-content nav.sequence-bottom ul li.next a.disabled {
- background-color: #fffffe;
- opacity: .4; }
- section.course-content nav.sequence-bottom ul li.prev a {
- background-image: url("../images/sequence-nav/previous-icon.png");
- border-right: 1px solid #e4d080; }
- section.course-content nav.sequence-bottom ul li.prev a:hover {
- background-color: none; }
- section.course-content nav.sequence-bottom ul li.next a {
- background-image: url("../images/sequence-nav/next-icon.png"); }
- section.course-content nav.sequence-bottom ul li.next a:hover {
- background-color: none; }
-
-section.course-index header {
- max-height: 47px; }
- section.course-index header h2 {
- white-space: nowrap; }
-section.course-index div#accordion h3 {
- -webkit-box-shadow: inset 0 1px 0 0 #eeeeee;
- -moz-box-shadow: inset 0 1px 0 0 #eeeeee;
- box-shadow: inset 0 1px 0 0 #eeeeee;
- border-top: 1px solid #d3d3d3;
- overflow: hidden;
- margin: 0; }
- section.course-index div#accordion h3:first-child {
- border: none; }
- section.course-index div#accordion h3:hover {
- background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1); }
- section.course-index div#accordion h3.ui-accordion-header {
- color: #000; }
- section.course-index div#accordion h3.ui-accordion-header a {
- font-size: 14px;
- color: #4d4d4d; }
- section.course-index div#accordion h3.ui-accordion-header.ui-state-active {
- background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: -o-linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- background-image: linear-gradient(-90deg, #f5f5f5, #e1e1e1);
- border-bottom: 1px solid #d3d3d3; }
-section.course-index div#accordion ul.ui-accordion-content {
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- -webkit-box-shadow: inset -1px 0 0 #e6e6e6;
- -moz-box-shadow: inset -1px 0 0 #e6e6e6;
- box-shadow: inset -1px 0 0 #e6e6e6;
- background: #dadada;
- border: none;
- font-size: 12px;
- margin: 0;
- padding: 1em 1.5em; }
- section.course-index div#accordion ul.ui-accordion-content li {
- margin-bottom: 11.326px; }
- section.course-index div#accordion ul.ui-accordion-content li a {
- border: 1px solid transparent;
- background: transparent;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- -ms-border-radius: 4px;
- -o-border-radius: 4px;
- border-radius: 4px;
- position: relative;
- padding: 5px 36px 5px 10px;
- text-decoration: none;
- display: block;
- color: #666; }
- section.course-index div#accordion ul.ui-accordion-content li a p {
- font-weight: bold;
- margin-bottom: 0; }
- section.course-index div#accordion ul.ui-accordion-content li a p span.subtitle {
- color: #666;
- font-weight: normal;
- display: block; }
- section.course-index div#accordion ul.ui-accordion-content li a:after {
- background: transparent;
- border-top: 1px solid #b4b4b4;
- border-right: 1px solid #b4b4b4;
- content: "";
- display: block;
- height: 12px;
- margin-top: -6px;
- opacity: 0;
- position: absolute;
- top: 50%;
- right: 30px;
- -webkit-transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -o-transform: rotate(45deg);
- transform: rotate(45deg);
- width: 12px; }
- section.course-index div#accordion ul.ui-accordion-content li a:hover {
- background-image: -webkit-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
- background-image: -moz-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
- background-image: -ms-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
- background-image: -o-linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
- background-image: linear-gradient(-90deg, rgba(245, 245, 245, 0.4), rgba(230, 230, 230, 0.4));
- border-color: #c8c8c8; }
- section.course-index div#accordion ul.ui-accordion-content li a:hover:after {
- opacity: 1;
- right: 15px;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.2s;
- -moz-transition-duration: 0.2s;
- -ms-transition-duration: 0.2s;
- -o-transition-duration: 0.2s;
- transition-duration: 0.2s;
- -webkit-transition-timing-function: linear;
- -moz-transition-timing-function: linear;
- -ms-transition-timing-function: linear;
- -o-transition-timing-function: linear;
- transition-timing-function: linear;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- section.course-index div#accordion ul.ui-accordion-content li a:hover > a p {
- color: #333; }
- section.course-index div#accordion ul.ui-accordion-content li a:active {
- -webkit-box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1);
- -moz-box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1);
- box-shadow: inset 0 1px 14px 0 rgba(0, 0, 0, 0.1); }
- section.course-index div#accordion ul.ui-accordion-content li a:active:after {
- opacity: 1;
- right: 15px; }
- section.course-index div#accordion ul.ui-accordion-content li.active {
- font-weight: bold; }
- section.course-index div#accordion ul.ui-accordion-content li.active > a {
- background: #f0f0f0;
- background-image: -webkit-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
- background-image: -moz-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
- background-image: -ms-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
- background-image: -o-linear-gradient(-90deg, #f5f5f5, #e6e6e6);
- background-image: linear-gradient(-90deg, #f5f5f5, #e6e6e6);
- border-color: #c8c8c8; }
- section.course-index div#accordion ul.ui-accordion-content li.active > a:after {
- opacity: 1;
- right: 15px; }
- section.course-index div#accordion ul.ui-accordion-content li.active > a p {
- color: #333; }
- section.course-index div#accordion ul.ui-accordion-content li.active span.subtitle {
- font-weight: normal; }
-
-@-moz-document url-prefix() {
- a.add-fullscreen {
- display: none !important; } }
-
-section.course-content .dullify, section.course-content div.video article.video-wrapper section.video-controls ul.vcr, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls {
- opacity: .4;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- section.course-content .dullify:hover, section.course-content div.video article.video-wrapper section.video-controls ul.vcr:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls:hover {
- opacity: 1; }
-section.course-content div.video {
- zoom: 1;
- background: #f3f3f3;
- border-bottom: 1px solid #e1e1e1;
- border-top: 1px solid #e1e1e1;
- display: block;
- margin: 0 -22.652px;
- padding: 6px 22.652px; }
- section.course-content div.video:before, section.course-content div.video:after {
- content: "";
- display: table; }
- section.course-content div.video:after {
- clear: both; }
- section.course-content div.video article.video-wrapper {
- float: left;
- margin-right: 2.717%;
- width: 65.761%; }
- section.course-content div.video article.video-wrapper section.video-player {
- height: 0;
- overflow: hidden;
- padding-bottom: 56.25%;
- padding-top: 30px;
- position: relative; }
- section.course-content div.video article.video-wrapper section.video-player object, section.course-content div.video article.video-wrapper section.video-player iframe {
- border: none;
- height: 100%;
- left: 0;
- position: absolute;
- top: 0;
- width: 100%; }
- section.course-content div.video article.video-wrapper section.video-controls {
- background: #333;
- border: 1px solid #000;
- border-top: 0;
- color: #ccc;
- position: relative; }
- section.course-content div.video article.video-wrapper section.video-controls:hover ul, section.course-content div.video article.video-wrapper section.video-controls:hover div {
- opacity: 1; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider {
- background: #c2c2c2;
- border: none;
- border-bottom: 1px solid #000;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- border-top: 1px solid #000;
- -webkit-box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
- -moz-box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
- box-shadow: inset 0 1px 0 #eeeeee, 0 1px 0 #555555;
- height: 7px;
- -webkit-transition-property: height, 2s, ease-in-out;
- -moz-transition-property: height, 2s, ease-in-out;
- -ms-transition-property: height, 2s, ease-in-out;
- -o-transition-property: height, 2s, ease-in-out;
- transition-property: height, 2s, ease-in-out;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider div.ui-widget-header {
- background: #777;
- -webkit-box-shadow: inset 0 1px 0 #999999;
- -moz-box-shadow: inset 0 1px 0 #999999;
- box-shadow: inset 0 1px 0 #999999; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider .ui-tooltip.qtip .ui-tooltip-content {
- background: #993333;
- border: 1px solid #4d1919;
- -webkit-border-radius: 2px;
- -moz-border-radius: 2px;
- -ms-border-radius: 2px;
- -o-border-radius: 2px;
- border-radius: 2px;
- -webkit-box-shadow: inset 0 1px 0 #bf4040;
- -moz-box-shadow: inset 0 1px 0 #bf4040;
- box-shadow: inset 0 1px 0 #bf4040;
- color: #fff;
- font: bold 12px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- margin-bottom: 6px;
- margin-right: 0;
- overflow: visible;
- padding: 4px;
- text-align: center;
- text-shadow: 0 -1px 0 #732626;
- -webkit-font-smoothing: antialiased; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider .ui-tooltip.qtip .ui-tooltip-content::after {
- background: #993333;
- border-bottom: 1px solid #4d1919;
- border-right: 1px solid #4d1919;
- bottom: -5px;
- content: " ";
- display: block;
- height: 7px;
- left: 50%;
- margin-left: -3px;
- position: absolute;
- -webkit-transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -o-transform: rotate(45deg);
- transform: rotate(45deg);
- width: 7px; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle {
- background: #993333 url(../images/slider-handle.png) center center no-repeat;
- -webkit-background-size: 50%;
- -moz-background-size: 50%;
- -ms-background-size: 50%;
- -o-background-size: 50%;
- background-size: 50%;
- border: 1px solid #4d1919;
- -webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- -ms-border-radius: 15px;
- -o-border-radius: 15px;
- border-radius: 15px;
- -webkit-box-shadow: inset 0 1px 0 #bf4040;
- -moz-box-shadow: inset 0 1px 0 #bf4040;
- box-shadow: inset 0 1px 0 #bf4040;
- cursor: pointer;
- height: 15px;
- margin-left: -7px;
- top: -4px;
- -webkit-transition-property: height, 2s, ease-in-out;
- -moz-transition-property: height, 2s, ease-in-out;
- -ms-transition-property: height, 2s, ease-in-out;
- -o-transition-property: height, 2s, ease-in-out;
- transition-property: height, 2s, ease-in-out;
- -webkit-transition-duration: width, 2s, ease-in-out;
- -moz-transition-duration: width, 2s, ease-in-out;
- -ms-transition-duration: width, 2s, ease-in-out;
- -o-transition-duration: width, 2s, ease-in-out;
- transition-duration: width, 2s, ease-in-out;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 15px; }
- section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle:focus, section.course-content div.video article.video-wrapper section.video-controls div.slider a.ui-slider-handle:hover {
- background-color: #bf4040;
- outline: none; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr {
- float: left;
- list-style: none;
- margin-right: 22.652px;
- padding: 0; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li {
- float: left;
- margin-bottom: 0; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a {
- border-bottom: none;
- border-right: 1px solid #000;
- -webkit-box-shadow: 1px 0 0 #555555;
- -moz-box-shadow: 1px 0 0 #555555;
- box-shadow: 1px 0 0 #555555;
- cursor: pointer;
- display: block;
- line-height: 46px;
- padding: 0 16.989px;
- text-indent: -9999px;
- -webkit-transition-property: background-color;
- -moz-transition-property: background-color;
- -ms-transition-property: background-color;
- -o-transition-property: background-color;
- transition-property: background-color;
- -webkit-transition-duration: opacity;
- -moz-transition-duration: opacity;
- -ms-transition-duration: opacity;
- -o-transition-duration: opacity;
- transition-duration: opacity;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 14px;
- background: url("../images/vcr.png") 15px 15px no-repeat; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a:empty {
- height: 46px;
- background: url("../images/vcr.png") 15px 15px no-repeat; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.play {
- background-position: 17px -114px; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.play:hover {
- background-color: #444; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.pause {
- background-position: 16px -50px; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li a.pause:hover {
- background-color: #444; }
- section.course-content div.video article.video-wrapper section.video-controls ul.vcr li div.vidtime {
- padding-left: 16.989px;
- font-weight: bold;
- line-height: 46px;
- padding-left: 16.989px;
- -webkit-font-smoothing: antialiased; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls {
- float: right; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds {
- float: left;
- position: relative; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds.open > a {
- background: url("../images/open-arrow.png") 10px center no-repeat; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds.open ol.video_speeds {
- display: block;
- opacity: 1; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a {
- background: url("../images/closed-arrow.png") 10px center no-repeat;
- border-left: 1px solid #000;
- border-right: 1px solid #000;
- -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- zoom: 1;
- color: #fff;
- cursor: pointer;
- display: block;
- line-height: 46px;
- margin-right: 0;
- padding-left: 15px;
- position: relative;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- -webkit-font-smoothing: antialiased;
- width: 110px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:before, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:after {
- content: "";
- display: table; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:after {
- clear: both; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a h3 {
- color: #999;
- float: left;
- font-size: 12px;
- font-weight: normal;
- letter-spacing: 1px;
- padding: 0 5.663px 0 11.326px;
- text-transform: uppercase; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a p.active {
- float: left;
- font-weight: bold;
- margin-bottom: 0;
- padding: 0 11.326px 0 0; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:active, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds > a:focus {
- opacity: 1;
- background-color: #444; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds {
- -webkit-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- -moz-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- background-color: #444;
- border: 1px solid #000;
- bottom: 46px;
- display: none;
- opacity: 0;
- position: absolute;
- width: 125px;
- z-index: 10; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li {
- -webkit-box-shadow: 0 1px 0 #555555;
- -moz-box-shadow: 0 1px 0 #555555;
- box-shadow: 0 1px 0 #555555;
- border-bottom: 1px solid #000;
- color: #fff;
- cursor: pointer; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li a {
- border: 0;
- color: #fff;
- display: block;
- padding: 11.326px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li a:hover {
- background-color: #666;
- color: #aaa; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li.active {
- font-weight: bold; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.speeds ol.video_speeds li:last-child {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- border-bottom: 0;
- margin-top: 0; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume {
- float: left;
- position: relative; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume.open .volume-slider-container {
- display: block;
- opacity: 1; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume.muted > a {
- background: url("../images/mute.png") 10px center no-repeat; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a {
- background: url("../images/volume.png") 10px center no-repeat;
- border-right: 1px solid #000;
- -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- zoom: 1;
- color: #fff;
- cursor: pointer;
- display: block;
- height: 46px;
- margin-right: 0;
- padding-left: 15px;
- position: relative;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- -webkit-font-smoothing: antialiased;
- width: 30px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:before, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:after {
- content: "";
- display: table; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:after {
- clear: both; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:hover, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:active, section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume > a:focus {
- background-color: #444; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container {
- -webkit-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- -moz-box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- box-shadow: inset 1px 0 0 #555555, 0 3px 0 #444444;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- background-color: #444;
- border: 1px solid #000;
- bottom: 46px;
- display: none;
- opacity: 0;
- position: absolute;
- width: 45px;
- height: 125px;
- margin-left: -1px;
- z-index: 10; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider {
- height: 100px;
- border: 0;
- width: 5px;
- margin: 14px auto;
- background: #666;
- border: 1px solid #000;
- -webkit-box-shadow: 0 1px 0 #333333;
- -moz-box-shadow: 0 1px 0 #333333;
- box-shadow: 0 1px 0 #333333; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider a.ui-slider-handle {
- background: #993333 url(../images/slider-handle.png) center center no-repeat;
- -webkit-background-size: 50%;
- -moz-background-size: 50%;
- -ms-background-size: 50%;
- -o-background-size: 50%;
- background-size: 50%;
- border: 1px solid #4d1919;
- -webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- -ms-border-radius: 15px;
- -o-border-radius: 15px;
- border-radius: 15px;
- -webkit-box-shadow: inset 0 1px 0 #bf4040;
- -moz-box-shadow: inset 0 1px 0 #bf4040;
- box-shadow: inset 0 1px 0 #bf4040;
- cursor: pointer;
- height: 15px;
- left: -6px;
- -webkit-transition-property: height, 2s, ease-in-out;
- -moz-transition-property: height, 2s, ease-in-out;
- -ms-transition-property: height, 2s, ease-in-out;
- -o-transition-property: height, 2s, ease-in-out;
- transition-property: height, 2s, ease-in-out;
- -webkit-transition-duration: width, 2s, ease-in-out;
- -moz-transition-duration: width, 2s, ease-in-out;
- -ms-transition-duration: width, 2s, ease-in-out;
- -o-transition-duration: width, 2s, ease-in-out;
- transition-duration: width, 2s, ease-in-out;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 15px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls div.volume .volume-slider-container .volume-slider .ui-slider-range {
- background: #ddd; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.add-fullscreen {
- background: url(../images/fullscreen.png) center no-repeat;
- border-right: 1px solid #000;
- -webkit-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- -moz-box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- box-shadow: 1px 0 0 #555555, inset 1px 0 0 #555555;
- color: #797979;
- display: block;
- float: left;
- line-height: 46px;
- margin-left: 0;
- padding: 0 11.326px;
- text-indent: -9999px;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- width: 30px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.add-fullscreen:hover {
- background-color: #444;
- color: #fff;
- text-decoration: none; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles {
- background: url("../images/cc.png") center no-repeat;
- color: #797979;
- display: block;
- float: left;
- font-weight: 800;
- line-height: 46px;
- margin-left: 0;
- opacity: 1;
- padding: 0 11.326px;
- position: relative;
- text-indent: -9999px;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0;
- -webkit-font-smoothing: antialiased;
- width: 30px; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles:hover {
- background-color: #444;
- color: #fff;
- text-decoration: none; }
- section.course-content div.video article.video-wrapper section.video-controls div.secondary-controls a.hide-subtitles.off {
- opacity: .7; }
- section.course-content div.video article.video-wrapper:hover section.video-controls ul, section.course-content div.video article.video-wrapper:hover section.video-controls div {
- opacity: 1; }
- section.course-content div.video article.video-wrapper:hover section.video-controls div.slider {
- height: 14px;
- margin-top: -7px; }
- section.course-content div.video article.video-wrapper:hover section.video-controls div.slider a.ui-slider-handle {
- -webkit-border-radius: 20px;
- -moz-border-radius: 20px;
- -ms-border-radius: 20px;
- -o-border-radius: 20px;
- border-radius: 20px;
- height: 20px;
- margin-left: -10px;
- top: -4px;
- width: 20px; }
- section.course-content div.video ol.subtitles {
- float: left;
- max-height: 460px;
- overflow: auto;
- width: 31.522%; }
- section.course-content div.video ol.subtitles li {
- border: 0;
- color: #666;
- cursor: pointer;
- margin-bottom: 8px;
- padding: 0; }
- section.course-content div.video ol.subtitles li.current {
- color: #333;
- font-weight: 700; }
- section.course-content div.video ol.subtitles li:hover {
- color: #993333; }
- section.course-content div.video ol.subtitles li:empty {
- margin-bottom: 0px; }
- section.course-content div.video.closed article.video-wrapper {
- width: 100%; }
- section.course-content div.video.closed ol.subtitles {
- width: 0px; }
- section.course-content div.video.fullscreen {
- background: rgba(0, 0, 0, 0.95);
- border: 0;
- bottom: 0;
- height: 100%;
- left: 0;
- margin: 0;
- max-height: 100%;
- overflow: hidden;
- padding: 0;
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 999; }
- section.course-content div.video.fullscreen.closed ol.subtitles {
- right: -31.984%;
- width: auto; }
- section.course-content div.video.fullscreen a.exit {
- color: #aaa;
- display: none;
- font-style: 12px;
- left: 20px;
- letter-spacing: 1px;
- position: absolute;
- text-transform: uppercase;
- top: 20px; }
- section.course-content div.video.fullscreen a.exit::after {
- content: "✖";
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- padding-left: 6px; }
- section.course-content div.video.fullscreen a.exit:hover {
- color: #993333; }
- section.course-content div.video.fullscreen div.tc-wrapper article.video-wrapper {
- width: 100%; }
- section.course-content div.video.fullscreen div.tc-wrapper object, section.course-content div.video.fullscreen div.tc-wrapper iframe {
- bottom: 0;
- height: 100%;
- left: 0;
- overflow: hidden;
- position: fixed;
- top: 0; }
- section.course-content div.video.fullscreen div.tc-wrapper section.video-controls {
- bottom: 0;
- left: 0;
- position: absolute;
- width: 100%;
- z-index: 9999; }
- section.course-content div.video.fullscreen ol.subtitles {
- background: rgba(0, 0, 0, 0.8);
- bottom: 0;
- height: 100%;
- max-height: 100%;
- max-width: 23.482%;
- padding: 22.652px;
- position: fixed;
- right: 0;
- top: 0;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- section.course-content div.video.fullscreen ol.subtitles li {
- color: #aaa; }
- section.course-content div.video.fullscreen ol.subtitles li.current {
- color: #fff; }
-
-div.course-wrapper.closed section.course-content div.video ol.subtitles {
- max-height: 577px; }
-
-section.tool-wrapper {
- background: #073642;
- border-bottom: 1px solid #000203;
- border-top: 1px solid #000203;
- -webkit-box-shadow: inset 0 0 0 4px #084150;
- -moz-box-shadow: inset 0 0 0 4px #084150;
- box-shadow: inset 0 0 0 4px #084150;
- color: #839496;
- display: table;
- margin: 22.652px -22.652px 0; }
- section.tool-wrapper div#graph-container {
- background: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- padding: 22.652px;
- vertical-align: top;
- width: 51.359%; }
- section.tool-wrapper div#graph-container .ui-widget-content {
- background: none;
- border: none;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0; }
- section.tool-wrapper div#graph-container canvas {
- width: 100%; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav {
- background: #062e39;
- border-bottom: 1px solid #03181d;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- margin: -22.652px -22.652px 0;
- padding: 0;
- position: relative;
- width: 110%; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li {
- background: none;
- border: none;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- -ms-border-radius: 0;
- -o-border-radius: 0;
- border-radius: 0;
- color: #fff;
- margin-bottom: 0; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected {
- background-color: #073642;
- border-left: 1px solid #03181d;
- border-right: 1px solid #03181d; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected:first-child {
- border-left: none; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li.ui-tabs-selected a {
- color: #eee8d5; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li a {
- border: none;
- color: #839496;
- font: bold 12px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- letter-spacing: 1px;
- text-transform: uppercase; }
- section.tool-wrapper div#graph-container ul.ui-tabs-nav li a:hover {
- color: #eee8d5; }
- section.tool-wrapper div#controlls-container {
- background: #062e39;
- border-right: 1px solid #001317;
- -webkit-box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
- -moz-box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
- box-shadow: 1px 0 0 #004355, inset 0 0 0 4px #06323d;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- padding: 22.652px;
- vertical-align: top;
- width: 48.641%; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper {
- border-bottom: 1px solid #021014;
- -webkit-box-shadow: 0 1px 0 #083e4b;
- -moz-box-shadow: 0 1px 0 #083e4b;
- box-shadow: 0 1px 0 #083e4b;
- margin-bottom: 22.652px;
- padding: 0 0 22.652px; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton {
- border-color: #001317;
- border: 1px solid #3d5962;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 0 0 #939da0;
- -moz-box-shadow: inset 0 1px 0 0 #939da0;
- box-shadow: inset 0 1px 0 0 #939da0;
- color: white;
- display: inline;
- font-size: 11px;
- font-weight: bold;
- background-color: #637c84;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #637c84), color-stop(100%, #43626b));
- background-image: -webkit-linear-gradient(top, #637c84, #43626b);
- background-image: -moz-linear-gradient(top, #637c84, #43626b);
- background-image: -ms-linear-gradient(top, #637c84, #43626b);
- background-image: -o-linear-gradient(top, #637c84, #43626b);
- background-image: linear-gradient(top, #637c84, #43626b);
- padding: 6px 18px 7px;
- text-shadow: 0 1px 0 #31505a;
- -webkit-background-clip: padding-box;
- display: block;
- float: right;
- font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:hover {
- -webkit-box-shadow: inset 0 1px 0 0 #778589;
- -moz-box-shadow: inset 0 1px 0 0 #778589;
- box-shadow: inset 0 1px 0 0 #778589;
- cursor: pointer;
- background-color: #5c6c71;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5c6c71), color-stop(100%, #3e5961));
- background-image: -webkit-linear-gradient(top, #5c6c71, #3e5961);
- background-image: -moz-linear-gradient(top, #5c6c71, #3e5961);
- background-image: -ms-linear-gradient(top, #5c6c71, #3e5961);
- background-image: -o-linear-gradient(top, #5c6c71, #3e5961);
- background-image: linear-gradient(top, #5c6c71, #3e5961); }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active {
- border: 1px solid #3d5962;
- -webkit-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee;
- -moz-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee;
- box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"] {
- border: 1px solid #030d15;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 0 0 #215f8a;
- -moz-box-shadow: inset 0 1px 0 0 #215f8a;
- box-shadow: inset 0 1px 0 0 #215f8a;
- color: white;
- display: inline;
- font-size: 11px;
- font-weight: bold;
- background-color: #0f3550;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0f3550), color-stop(100%, #041623));
- background-image: -webkit-linear-gradient(top, #0f3550, #041623);
- background-image: -moz-linear-gradient(top, #0f3550, #041623);
- background-image: -ms-linear-gradient(top, #0f3550, #041623);
- background-image: -o-linear-gradient(top, #0f3550, #041623);
- background-image: linear-gradient(top, #0f3550, #041623);
- padding: 6px 18px 7px;
- text-shadow: 0 1px 0 #000203;
- -webkit-background-clip: padding-box;
- font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:hover {
- -webkit-box-shadow: inset 0 1px 0 0 #174362;
- -moz-box-shadow: inset 0 1px 0 0 #174362;
- box-shadow: inset 0 1px 0 0 #174362;
- cursor: pointer;
- background-color: #0c2739;
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0c2739), color-stop(100%, #030d15));
- background-image: -webkit-linear-gradient(top, #0c2739, #030d15);
- background-image: -moz-linear-gradient(top, #0c2739, #030d15);
- background-image: -ms-linear-gradient(top, #0c2739, #030d15);
- background-image: -o-linear-gradient(top, #0c2739, #030d15);
- background-image: linear-gradient(top, #0c2739, #030d15); }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active {
- border: 1px solid #030d15;
- -webkit-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee;
- -moz-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee;
- box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; }
- section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none; }
- section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper {
- border-bottom: 1px solid #021014;
- -webkit-box-shadow: 0 1px 0 #083e4b;
- -moz-box-shadow: 0 1px 0 #083e4b;
- box-shadow: 0 1px 0 #083e4b;
- zoom: 1;
- margin-bottom: 22.652px;
- margin-bottom: 22.652px;
- padding: 0 0 22.652px; }
- section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:before, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after {
- content: "";
- display: table; }
- section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after {
- clear: both; }
- section.tool-wrapper div#controlls-container div.graph-controls p {
- font-weight: bold;
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin: 0;
- text-shadow: 0 -1px 0 #021014;
- -webkit-font-smoothing: antialiased; }
- section.tool-wrapper div#controlls-container div.graph-controls ul {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin-bottom: 0; }
- section.tool-wrapper div#controlls-container div.graph-controls ul li {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin-bottom: 0; }
- section.tool-wrapper div#controlls-container div.graph-controls ul li input {
- margin-right: 5px; }
- section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen {
- display: block;
- float: left;
- margin-bottom: 0;
- margin-right: 20px;
- margin-top: 8px;
- text-align: right; }
- section.tool-wrapper div#controlls-container label {
- -webkit-border-radius: 2px;
- -moz-border-radius: 2px;
- -ms-border-radius: 2px;
- -o-border-radius: 2px;
- border-radius: 2px;
- color: #fff;
- font-weight: bold;
- padding: 3px;
- -webkit-font-smoothing: antialiased; }
- section.tool-wrapper div#controlls-container label[for="vinCheckbox"], section.tool-wrapper div#controlls-container label[for="vinRadioButton"] {
- color: #409fbf; }
- section.tool-wrapper div#controlls-container label[for="voutCheckbox"], section.tool-wrapper div#controlls-container label[for="voutRadioButton"] {
- color: #e1a600; }
- section.tool-wrapper div#controlls-container label[for="vrCheckbox"], section.tool-wrapper div#controlls-container label[for="vrRadioButton"] {
- color: #49c944; }
- section.tool-wrapper div#controlls-container label[for="vcCheckbox"], section.tool-wrapper div#controlls-container label[for="vcRadioButton"] {
- color: #e1a600; }
- section.tool-wrapper div#controlls-container label[for="vlCheckbox"], section.tool-wrapper div#controlls-container label[for="vlRadioButton"] {
- color: #a26784; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders {
- border-bottom: 1px solid #021014;
- -webkit-box-shadow: 0 1px 0 #083e4b;
- -moz-box-shadow: 0 1px 0 #083e4b;
- box-shadow: 0 1px 0 #083e4b;
- margin-bottom: 22.652px;
- padding: 0 0 22.652px; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders select#musicTypeSelect {
- font: 16px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin-bottom: 0; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders p {
- font-weight: bold;
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin: 0 11.326px 22.652px 0;
- text-shadow: 0 -1px 0 #021014;
- -webkit-font-smoothing: antialiased; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.slider-label {
- font-weight: bold;
- margin-bottom: 11.326px;
- text-shadow: 0 -1px 0 #021014;
- -webkit-font-smoothing: antialiased; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.slider {
- margin-bottom: 22.652px; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.slider.ui-slider-horizontal {
- background: #00232c;
- border: 1px solid #000b0d;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- height: 0.4em; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle {
- background: #637c84 url("../images/amplifier-slider-handle.png") center no-repeat;
- border: 1px solid #000b0d;
- -webkit-box-shadow: inset 0 1px 0 #8ba1a8;
- -moz-box-shadow: inset 0 1px 0 #8ba1a8;
- box-shadow: inset 0 1px 0 #8ba1a8;
- margin-top: -0.3em; }
- section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:hover, section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:active {
- background-color: #6e8992; }
-
-section.problem-set, div.course-wrapper section.course-content section.problems-wrapper, section.problems-wrapper {
- position: relative; }
- section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
- margin-top: 0;
- margin-bottom: 15px;
- width: 20.109%;
- padding-right: 2.717%;
- border-right: 1px dashed #ddd;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- vertical-align: top; }
- section.problem-set h2.problem-header section.staff, div.course-wrapper section.course-content section.problems-wrapper h2.problem-header section.staff, section.problems-wrapper h2.problem-header section.staff {
- margin-top: 30px;
- font-size: 80%; }
- @media screen and (max-width:1120px) {
- section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
- display: block;
- width: auto;
- border-right: 0; } }
- @media print {
- section.problem-set h2, div.course-wrapper section.course-content section.problems-wrapper h2, section.problems-wrapper h2 {
- display: block;
- width: auto;
- border-right: 0; } }
- section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
- display: table-cell;
- width: 77.174%;
- padding-left: 2.717%; }
- @media screen and (max-width:1120px) {
- section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
- display: block;
- width: auto;
- padding: 0; } }
- @media print {
- section.problem-set section.problem, div.course-wrapper section.course-content section.problems-wrapper section.problem, section.problems-wrapper section.problem {
- display: block;
- width: auto;
- padding: 0; }
- section.problem-set section.problem canvas, div.course-wrapper section.course-content section.problems-wrapper section.problem canvas, section.problems-wrapper section.problem canvas, section.problem-set section.problem img, div.course-wrapper section.course-content section.problems-wrapper section.problem img, section.problems-wrapper section.problem img {
- page-break-inside: avoid; } }
- section.problem-set section.problem div p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.status, section.problems-wrapper section.problem div p.status {
- text-indent: -9999px;
- margin: -1px 0 0 10px; }
- section.problem-set section.problem div.unanswered p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.unanswered p.status, section.problems-wrapper section.problem div.unanswered p.status {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/unanswered-icon.png") center center no-repeat;
- height: 14px;
- width: 14px; }
- section.problem-set section.problem div.correct p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.correct p.status, section.problems-wrapper section.problem div.correct p.status, section.problem-set section.problem div.ui-icon-check p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-check p.status, section.problems-wrapper section.problem div.ui-icon-check p.status {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/correct-icon.png") center center no-repeat;
- height: 20px;
- width: 25px; }
- section.problem-set section.problem div.correct input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.correct input, section.problems-wrapper section.problem div.correct input, section.problem-set section.problem div.ui-icon-check input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-check input, section.problems-wrapper section.problem div.ui-icon-check input {
- border-color: green; }
- section.problem-set section.problem div.incorrect p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.incorrect p.status, section.problems-wrapper section.problem div.incorrect p.status, section.problem-set section.problem div.ui-icon-close p.status, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-close p.status, section.problems-wrapper section.problem div.ui-icon-close p.status {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/incorrect-icon.png") center center no-repeat;
- height: 20px;
- width: 20px;
- text-indent: -9999px; }
- section.problem-set section.problem div.incorrect input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.incorrect input, section.problems-wrapper section.problem div.incorrect input, section.problem-set section.problem div.ui-icon-close input, div.course-wrapper section.course-content section.problems-wrapper section.problem div.ui-icon-close input, section.problems-wrapper section.problem div.ui-icon-close input {
- border-color: red; }
- section.problem-set section.problem div > span, div.course-wrapper section.course-content section.problems-wrapper section.problem div > span, section.problems-wrapper section.problem div > span {
- display: block;
- margin-bottom: 11.326px; }
- section.problem-set section.problem div p.answer, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer, section.problems-wrapper section.problem div p.answer {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- margin-bottom: 0;
- margin-left: 10px; }
- section.problem-set section.problem div p.answer:before, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer:before, section.problems-wrapper section.problem div p.answer:before {
- content: "Answer: ";
- font-weight: bold;
- display: inline; }
- section.problem-set section.problem div p.answer:empty:before, div.course-wrapper section.course-content section.problems-wrapper section.problem div p.answer:empty:before, section.problems-wrapper section.problem div p.answer:empty:before {
- display: none; }
- section.problem-set section.problem div div.equation, div.course-wrapper section.course-content section.problems-wrapper section.problem div div.equation, section.problems-wrapper section.problem div div.equation {
- clear: both;
- padding: 6px;
- background: #eee; }
- section.problem-set section.problem div div.equation span, div.course-wrapper section.course-content section.problems-wrapper section.problem div div.equation span, section.problems-wrapper section.problem div div.equation span {
- margin-bottom: 0; }
- section.problem-set section.problem div span.unanswered, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.unanswered, section.problems-wrapper section.problem div span.unanswered, section.problem-set section.problem div span.ui-icon-bullet, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-bullet, section.problems-wrapper section.problem div span.ui-icon-bullet {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/unanswered-icon.png") center center no-repeat;
- height: 14px;
- position: relative;
- top: 4px;
- width: 14px; }
- section.problem-set section.problem div span.correct, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.correct, section.problems-wrapper section.problem div span.correct, section.problem-set section.problem div span.ui-icon-check, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-check, section.problems-wrapper section.problem div span.ui-icon-check {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/correct-icon.png") center center no-repeat;
- height: 20px;
- position: relative;
- top: 6px;
- width: 25px; }
- section.problem-set section.problem div span.incorrect, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.incorrect, section.problems-wrapper section.problem div span.incorrect, section.problem-set section.problem div span.ui-icon-close, div.course-wrapper section.course-content section.problems-wrapper section.problem div span.ui-icon-close, section.problems-wrapper section.problem div span.ui-icon-close {
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- background: url("../images/incorrect-icon.png") center center no-repeat;
- height: 20px;
- width: 20px;
- position: relative;
- top: 6px; }
- section.problem-set section.problem ul, div.course-wrapper section.course-content section.problems-wrapper section.problem ul, section.problems-wrapper section.problem ul {
- list-style: disc outside none;
- margin-bottom: 22.652px;
- margin-left: .75em;
- margin-left: .75rem; }
- section.problem-set section.problem ol, div.course-wrapper section.course-content section.problems-wrapper section.problem ol, section.problems-wrapper section.problem ol {
- list-style: decimal outside none;
- margin-bottom: 22.652px;
- margin-left: .75em;
- margin-left: .75rem; }
- section.problem-set section.problem dl, div.course-wrapper section.course-content section.problems-wrapper section.problem dl, section.problems-wrapper section.problem dl {
- line-height: 1.4em; }
- section.problem-set section.problem dl dt, div.course-wrapper section.course-content section.problems-wrapper section.problem dl dt, section.problems-wrapper section.problem dl dt {
- font-weight: bold; }
- section.problem-set section.problem dl dd, div.course-wrapper section.course-content section.problems-wrapper section.problem dl dd, section.problems-wrapper section.problem dl dd {
- margin-bottom: 0; }
- section.problem-set section.problem dd, div.course-wrapper section.course-content section.problems-wrapper section.problem dd, section.problems-wrapper section.problem dd {
- margin-left: .5em;
- margin-left: .5rem; }
- section.problem-set section.problem li, div.course-wrapper section.course-content section.problems-wrapper section.problem li, section.problems-wrapper section.problem li {
- line-height: 1.4em;
- margin-bottom: 11.326px; }
- section.problem-set section.problem li:last-child, div.course-wrapper section.course-content section.problems-wrapper section.problem li:last-child, section.problems-wrapper section.problem li:last-child {
- margin-bottom: 0; }
- section.problem-set section.problem p, div.course-wrapper section.course-content section.problems-wrapper section.problem p, section.problems-wrapper section.problem p {
- margin-bottom: 22.652px; }
- section.problem-set section.problem table, div.course-wrapper section.course-content section.problems-wrapper section.problem table, section.problems-wrapper section.problem table {
- margin-bottom: 22.652px;
- width: 100%;
- border-collapse: collapse; }
- section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th {
- font-weight: bold;
- text-align: left; }
- section.problem-set section.problem table caption, div.course-wrapper section.course-content section.problems-wrapper section.problem table caption, section.problems-wrapper section.problem table caption, section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th, section.problem-set section.problem table td, div.course-wrapper section.course-content section.problems-wrapper section.problem table td, section.problems-wrapper section.problem table td {
- padding: .25em .75em .25em 0;
- padding: .25rem .75rem .25rem 0; }
- section.problem-set section.problem table caption, div.course-wrapper section.course-content section.problems-wrapper section.problem table caption, section.problems-wrapper section.problem table caption {
- background: #f1f1f1;
- margin-bottom: .75em;
- margin-bottom: .75rem;
- padding: .75em 0;
- padding: .75rem 0; }
- section.problem-set section.problem table tr, div.course-wrapper section.course-content section.problems-wrapper section.problem table tr, section.problems-wrapper section.problem table tr, section.problem-set section.problem table td, div.course-wrapper section.course-content section.problems-wrapper section.problem table td, section.problems-wrapper section.problem table td, section.problem-set section.problem table th, div.course-wrapper section.course-content section.problems-wrapper section.problem table th, section.problems-wrapper section.problem table th {
- vertical-align: middle; }
- section.problem-set section.problem hr, div.course-wrapper section.course-content section.problems-wrapper section.problem hr, section.problems-wrapper section.problem hr {
- background: #ddd;
- border: none;
- clear: both;
- color: #ddd;
- float: none;
- height: 1px;
- margin: 0 0 .75rem;
- width: 100%; }
- section.problem-set section.problem .hidden, div.course-wrapper section.course-content section.problems-wrapper section.problem .hidden, section.problems-wrapper section.problem .hidden {
- display: none;
- visibility: hidden; }
- section.problem-set section.problem input[type="email"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="email"], section.problems-wrapper section.problem input[type="email"], section.problem-set section.problem input[type="number"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="number"], section.problems-wrapper section.problem input[type="number"], section.problem-set section.problem input[type="password"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="password"], section.problems-wrapper section.problem input[type="password"], section.problem-set section.problem input[type="search"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="search"], section.problems-wrapper section.problem input[type="search"], section.problem-set section.problem input[type="tel"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="tel"], section.problems-wrapper section.problem input[type="tel"], section.problem-set section.problem input[type="text"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="text"], section.problems-wrapper section.problem input[type="text"], section.problem-set section.problem input[type="url"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="url"], section.problems-wrapper section.problem input[type="url"], section.problem-set section.problem input[type="color"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="color"], section.problems-wrapper section.problem input[type="color"], section.problem-set section.problem input[type="date"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="date"], section.problems-wrapper section.problem input[type="date"], section.problem-set section.problem input[type="datetime"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="datetime"], section.problems-wrapper section.problem input[type="datetime"], section.problem-set section.problem input[type="datetime-local"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="datetime-local"], section.problems-wrapper section.problem input[type="datetime-local"], section.problem-set section.problem input[type="month"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="month"], section.problems-wrapper section.problem input[type="month"], section.problem-set section.problem input[type="time"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="time"], section.problems-wrapper section.problem input[type="time"], section.problem-set section.problem input[type="week"], div.course-wrapper section.course-content section.problems-wrapper section.problem input[type="week"], section.problems-wrapper section.problem input[type="week"] {
- display: inline;
- width: auto; }
- section.problem-set section.problem center, div.course-wrapper section.course-content section.problems-wrapper section.problem center, section.problems-wrapper section.problem center {
- display: block;
- margin: 22.652px 0;
- border: 1px solid #ccc;
- padding: 22.652px; }
- section.problem-set section.action, div.course-wrapper section.course-content section.problems-wrapper section.action, section.problems-wrapper section.action {
- margin-top: 11.326px; }
- section.problem-set section.action input[type="button"], div.course-wrapper section.course-content section.problems-wrapper section.action input[type="button"], section.problems-wrapper section.action input[type="button"] {
- padding: 9.061px 22.652px;
- text-shadow: 0 -1px 0 #666666; }
-
-section.problems-wrapper {
- display: table;
- width: 100%; }
- @media screen and (max-width:1120px) {
- section.problems-wrapper {
- display: block;
- width: auto; } }
-
-div.info-wrapper section.updates > p {
- margin-bottom: 22.652px; }
-div.info-wrapper section.updates > ol {
- list-style: none; }
- div.info-wrapper section.updates > ol > li {
- border-bottom: 1px solid #e3e3e3;
- margin-bottom: 11.326px;
- padding-bottom: 11.326px;
- list-style-type: disk; }
- div.info-wrapper section.updates > ol > li:first-child {
- background: #f6efd4;
- border-bottom: 1px solid #eddfaa;
- margin: 0 -11.326px 22.652px;
- padding: 11.326px; }
- div.info-wrapper section.updates > ol > li ol, div.info-wrapper section.updates > ol > li ul {
- margin: 22.652px 0 0 22.652px;
- list-style-type: circle; }
- div.info-wrapper section.updates > ol > li h2 {
- float: left;
- margin: 0 2.024% 0 0;
- width: 20.109%; }
- div.info-wrapper section.updates > ol > li section.update-description {
- float: left;
- margin-bottom: 0;
- width: 77.174%; }
- div.info-wrapper section.updates > ol > li section.update-description li {
- margin-bottom: 11.326px; }
- div.info-wrapper section.updates > ol > li section.update-description p:last-child {
- margin-bottom: 0; }
-div.info-wrapper section.handouts {
- border-left: 1px solid #d3d3d3;
- -webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- -ms-border-radius: 0 4px 4px 0;
- -o-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
- border-right: 0; }
- div.info-wrapper section.handouts header {
- padding: 11.326px 16.989px; }
- div.info-wrapper section.handouts header h1 {
- font-size: 18px;
- margin: 0; }
- div.info-wrapper section.handouts header p {
- color: #666;
- font-size: 12px;
- margin-bottom: 0;
- margin-top: 4px; }
- div.info-wrapper section.handouts ol {
- background: none;
- list-style: none; }
- div.info-wrapper section.handouts ol li {
- background: none;
- border-bottom: 1px solid #d3d3d3;
- -webkit-box-shadow: 0 1px 0 #eeeeee;
- -moz-box-shadow: 0 1px 0 #eeeeee;
- box-shadow: 0 1px 0 #eeeeee;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- padding: 7px 16.989px;
- position: relative; }
- div.info-wrapper section.handouts ol li.expandable h4, div.info-wrapper section.handouts ol li.collapsable h4 {
- font-style: 14px;
- font-weight: normal;
- padding-left: 18px; }
- div.info-wrapper section.handouts ol li ul {
- background: none;
- margin: 7px -16.989px 0; }
- div.info-wrapper section.handouts ol li ul li {
- border-bottom: 0;
- border-top: 1px solid #d3d3d3;
- -webkit-box-shadow: inset 0 1px 0 #eeeeee;
- -moz-box-shadow: inset 0 1px 0 #eeeeee;
- box-shadow: inset 0 1px 0 #eeeeee;
- padding-left: 34.989px; }
- div.info-wrapper section.handouts ol li:hover {
- background-color: #e9e9e9; }
- div.info-wrapper section.handouts ol li div.hitarea {
- background-image: url("../images/treeview-default.gif");
- display: block;
- height: 100%;
- left: 16.989px;
- margin-left: 0;
- max-height: 20px;
- position: absolute;
- width: 100%; }
- div.info-wrapper section.handouts ol li div.hitarea:hover {
- opacity: 0.6;
- filter: alpha(opacity=60); }
- div.info-wrapper section.handouts ol li div.hitarea.expandable-hitarea {
- background-position: -80px 1px; }
- div.info-wrapper section.handouts ol li div.hitarea.collapsable-hitarea {
- background-position: -64px -21px; }
- div.info-wrapper section.handouts ol li h3 {
- border-bottom: 0;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- color: #999;
- font-size: 12px;
- font-weight: bold;
- text-transform: uppercase; }
- div.info-wrapper section.handouts ol li p {
- font-size: 14px;
- letter-spacing: 0;
- margin: 0;
- text-transform: none; }
- div.info-wrapper section.handouts ol li p a {
- padding-right: 8px; }
- div.info-wrapper section.handouts ol li p a:before {
- color: #ccc;
- content: "•";
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- padding-right: 8px; }
- div.info-wrapper section.handouts ol li p a:first-child:before {
- content: "";
- padding-right: 0; }
- div.info-wrapper section.handouts ol li a {
- color: #4d4d4d;
- display: -moz-inline-box;
- -moz-box-orient: vertical;
- display: inline-block;
- vertical-align: baseline;
- zoom: 1;
- *display: inline;
- *vertical-align: auto;
- text-decoration: none;
- -webkit-transition-property: all;
- -moz-transition-property: all;
- -ms-transition-property: all;
- -o-transition-property: all;
- transition-property: all;
- -webkit-transition-duration: 0.15s;
- -moz-transition-duration: 0.15s;
- -ms-transition-duration: 0.15s;
- -o-transition-duration: 0.15s;
- transition-duration: 0.15s;
- -webkit-transition-timing-function: ease-out;
- -moz-transition-timing-function: ease-out;
- -ms-transition-timing-function: ease-out;
- -o-transition-timing-function: ease-out;
- transition-timing-function: ease-out;
- -webkit-transition-delay: 0;
- -moz-transition-delay: 0;
- -ms-transition-delay: 0;
- -o-transition-delay: 0;
- transition-delay: 0; }
- div.info-wrapper section.handouts ol li a:hover {
- color: #993333; }
-
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden {
- display: none; }
-
-.ui-helper-hidden-accessible {
- position: absolute !important;
- clip: rect(1px 1px 1px 1px);
- clip: rect(1px, 1px, 1px, 1px); }
-
-.ui-helper-reset {
- margin: 0;
- padding: 0;
- border: 0;
- outline: 0;
- line-height: 1.3;
- text-decoration: none;
- font-size: 100%;
- list-style: none; }
-
-.ui-helper-clearfix:after {
- content: ".";
- display: block;
- height: 0;
- clear: both;
- visibility: hidden; }
-
-.ui-helper-clearfix {
- display: inline-block; }
-
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix {
- height: 1%; }
-
-.ui-helper-clearfix {
- display: block; }
-
-/* end clearfix */
-.ui-helper-zfix {
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- position: absolute;
- opacity: 0;
- filter: Alpha(Opacity=0); }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled {
- cursor: default !important; }
-
-/* Icons
-----------------------------------*/
-/* states and images */
-.ui-icon {
- display: block;
- text-indent: -99999px;
- overflow: hidden;
- background-repeat: no-repeat; }
-
-/* Misc visuals
-----------------------------------*/
-/* Overlays */
-.ui-widget-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%; }
-
-/*
- * jQuery UI CSS Framework 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=7fbcfd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=50&borderColorHeader=dae5c9&fcHeader=031634&iconColorHeader=031634&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=dae5c9&fcContent=031634&iconColorContent=adcc80&bgColorDefault=7fbcdf&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=100&borderColorDefault=dae5c9&fcDefault=7a994c&iconColorDefault=adcc80&bgColorHover=bddeff&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=7fbcdf&fcHover=7a994c&iconColorHover=adcc80&bgColorActive=023063&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=dae5c9&fcActive=dae5c9&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=adcc80&bgColorError=ffffff&bgTextureError=01_flat.png&bgImgOpacityError=55&borderColorError=fa720a&fcError=222222&iconColorError=fa720a&bgColorOverlay=eeeeee&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
- */
-/* Component containers
-----------------------------------*/
-.ui-widget {
- font-family: Helvetica, Arial, sans-serif;
- font-size: 1.1em; }
-
-.ui-widget .ui-widget {
- font-size: 1em; }
-
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button {
- font-family: Helvetica, Arial, sans-serif;
- font-size: 1em; }
-
-.ui-widget-content {
- border: 1px solid #dae5c9;
- background: white url(../images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;
- color: #031634; }
-
-.ui-widget-content a {
- color: #031634; }
-
-.ui-widget-header {
- border: 1px solid #dae5c9;
- background: #7fbcfd url(../images/ui-bg_highlight-soft_50_7fbcfd_1x100.png) 50% 50% repeat-x;
- color: #031634;
- font-weight: bold; }
-
-.ui-widget-header a {
- color: #031634; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
- border: 1px solid #dae5c9;
- background: #7fbcdf url(../images/ui-bg_highlight-soft_100_7fbcdf_1x100.png) 50% 50% repeat-x;
- font-weight: bold;
- color: #7a994c; }
-
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited {
- color: #7a994c;
- text-decoration: none; }
-
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus {
- border: 1px solid #7fbcdf;
- background: #bddeff url(../images/ui-bg_highlight-soft_25_bddeff_1x100.png) 50% 50% repeat-x;
- font-weight: bold;
- color: #7a994c; }
-
-.ui-state-hover a, .ui-state-hover a:hover {
- color: #7a994c;
- text-decoration: none; }
-
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
- border: 1px solid #dae5c9;
- background: #023063 url(../images/ui-bg_glass_65_023063_1x400.png) 50% 50% repeat-x;
- font-weight: bold;
- color: #dae5c9; }
-
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited {
- color: #dae5c9;
- text-decoration: none; }
-
-.ui-widget :active {
- outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {
- border: 1px solid #cccccc;
- background: white url(../images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;
- color: #444444; }
-
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a, .ui-widget-header .ui-state-highlight a {
- color: #444444; }
-
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {
- border: 1px solid #fa720a;
- background: white url(../images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x;
- color: #222222; }
-
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a {
- color: #222222; }
-
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text {
- color: #222222; }
-
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary {
- font-weight: bold; }
-
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary {
- opacity: .7;
- filter: Alpha(Opacity=70);
- font-weight: normal; }
-
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled {
- opacity: .35;
- filter: Alpha(Opacity=35);
- background-image: none; }
-
-/* Icons
-----------------------------------*/
-/* states and images */
-.ui-icon {
- width: 16px;
- height: 16px;
- background-image: url(../images/ui-icons_adcc80_256x240.png); }
-
-.ui-widget-content .ui-icon {
- background-image: url(../images/ui-icons_adcc80_256x240.png); }
-
-.ui-widget-header .ui-icon {
- background-image: url(../images/ui-icons_031634_256x240.png); }
-
-.ui-state-default .ui-icon {
- background-image: url(../images/ui-icons_adcc80_256x240.png); }
-
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {
- background-image: url(../images/ui-icons_adcc80_256x240.png); }
-
-.ui-state-active .ui-icon {
- background-image: url(../images/ui-icons_454545_256x240.png); }
-
-.ui-state-highlight .ui-icon {
- background-image: url(../images/ui-icons_adcc80_256x240.png); }
-
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {
- background-image: url(../images/ui-icons_fa720a_256x240.png); }
-
-/* positioning */
-.ui-icon-carat-1-n {
- background-position: 0 0; }
-
-.ui-icon-carat-1-ne {
- background-position: -16px 0; }
-
-.ui-icon-carat-1-e {
- background-position: -32px 0; }
-
-.ui-icon-carat-1-se {
- background-position: -48px 0; }
-
-.ui-icon-carat-1-s {
- background-position: -64px 0; }
-
-.ui-icon-carat-1-sw {
- background-position: -80px 0; }
-
-.ui-icon-carat-1-w {
- background-position: -96px 0; }
-
-.ui-icon-carat-1-nw {
- background-position: -112px 0; }
-
-.ui-icon-carat-2-n-s {
- background-position: -128px 0; }
-
-.ui-icon-carat-2-e-w {
- background-position: -144px 0; }
-
-.ui-icon-triangle-1-n {
- background-position: 0 -16px; }
-
-.ui-icon-triangle-1-ne {
- background-position: -16px -16px; }
-
-.ui-icon-triangle-1-e {
- background-position: -32px -16px; }
-
-.ui-icon-triangle-1-se {
- background-position: -48px -16px; }
-
-.ui-icon-triangle-1-s {
- background-position: -64px -16px; }
-
-.ui-icon-triangle-1-sw {
- background-position: -80px -16px; }
-
-.ui-icon-triangle-1-w {
- background-position: -96px -16px; }
-
-.ui-icon-triangle-1-nw {
- background-position: -112px -16px; }
-
-.ui-icon-triangle-2-n-s {
- background-position: -128px -16px; }
-
-.ui-icon-triangle-2-e-w {
- background-position: -144px -16px; }
-
-.ui-icon-arrow-1-n {
- background-position: 0 -32px; }
-
-.ui-icon-arrow-1-ne {
- background-position: -16px -32px; }
-
-.ui-icon-arrow-1-e {
- background-position: -32px -32px; }
-
-.ui-icon-arrow-1-se {
- background-position: -48px -32px; }
-
-.ui-icon-arrow-1-s {
- background-position: -64px -32px; }
-
-.ui-icon-arrow-1-sw {
- background-position: -80px -32px; }
-
-.ui-icon-arrow-1-w {
- background-position: -96px -32px; }
-
-.ui-icon-arrow-1-nw {
- background-position: -112px -32px; }
-
-.ui-icon-arrow-2-n-s {
- background-position: -128px -32px; }
-
-.ui-icon-arrow-2-ne-sw {
- background-position: -144px -32px; }
-
-.ui-icon-arrow-2-e-w {
- background-position: -160px -32px; }
-
-.ui-icon-arrow-2-se-nw {
- background-position: -176px -32px; }
-
-.ui-icon-arrowstop-1-n {
- background-position: -192px -32px; }
-
-.ui-icon-arrowstop-1-e {
- background-position: -208px -32px; }
-
-.ui-icon-arrowstop-1-s {
- background-position: -224px -32px; }
-
-.ui-icon-arrowstop-1-w {
- background-position: -240px -32px; }
-
-.ui-icon-arrowthick-1-n {
- background-position: 0 -48px; }
-
-.ui-icon-arrowthick-1-ne {
- background-position: -16px -48px; }
-
-.ui-icon-arrowthick-1-e {
- background-position: -32px -48px; }
-
-.ui-icon-arrowthick-1-se {
- background-position: -48px -48px; }
-
-.ui-icon-arrowthick-1-s {
- background-position: -64px -48px; }
-
-.ui-icon-arrowthick-1-sw {
- background-position: -80px -48px; }
-
-.ui-icon-arrowthick-1-w {
- background-position: -96px -48px; }
-
-.ui-icon-arrowthick-1-nw {
- background-position: -112px -48px; }
-
-.ui-icon-arrowthick-2-n-s {
- background-position: -128px -48px; }
-
-.ui-icon-arrowthick-2-ne-sw {
- background-position: -144px -48px; }
-
-.ui-icon-arrowthick-2-e-w {
- background-position: -160px -48px; }
-
-.ui-icon-arrowthick-2-se-nw {
- background-position: -176px -48px; }
-
-.ui-icon-arrowthickstop-1-n {
- background-position: -192px -48px; }
-
-.ui-icon-arrowthickstop-1-e {
- background-position: -208px -48px; }
-
-.ui-icon-arrowthickstop-1-s {
- background-position: -224px -48px; }
-
-.ui-icon-arrowthickstop-1-w {
- background-position: -240px -48px; }
-
-.ui-icon-arrowreturnthick-1-w {
- background-position: 0 -64px; }
-
-.ui-icon-arrowreturnthick-1-n {
- background-position: -16px -64px; }
-
-.ui-icon-arrowreturnthick-1-e {
- background-position: -32px -64px; }
-
-.ui-icon-arrowreturnthick-1-s {
- background-position: -48px -64px; }
-
-.ui-icon-arrowreturn-1-w {
- background-position: -64px -64px; }
-
-.ui-icon-arrowreturn-1-n {
- background-position: -80px -64px; }
-
-.ui-icon-arrowreturn-1-e {
- background-position: -96px -64px; }
-
-.ui-icon-arrowreturn-1-s {
- background-position: -112px -64px; }
-
-.ui-icon-arrowrefresh-1-w {
- background-position: -128px -64px; }
-
-.ui-icon-arrowrefresh-1-n {
- background-position: -144px -64px; }
-
-.ui-icon-arrowrefresh-1-e {
- background-position: -160px -64px; }
-
-.ui-icon-arrowrefresh-1-s {
- background-position: -176px -64px; }
-
-.ui-icon-arrow-4 {
- background-position: 0 -80px; }
-
-.ui-icon-arrow-4-diag {
- background-position: -16px -80px; }
-
-.ui-icon-extlink {
- background-position: -32px -80px; }
-
-.ui-icon-newwin {
- background-position: -48px -80px; }
-
-.ui-icon-refresh {
- background-position: -64px -80px; }
-
-.ui-icon-shuffle {
- background-position: -80px -80px; }
-
-.ui-icon-transfer-e-w {
- background-position: -96px -80px; }
-
-.ui-icon-transferthick-e-w {
- background-position: -112px -80px; }
-
-.ui-icon-folder-collapsed {
- background-position: 0 -96px; }
-
-.ui-icon-folder-open {
- background-position: -16px -96px; }
-
-.ui-icon-document {
- background-position: -32px -96px; }
-
-.ui-icon-document-b {
- background-position: -48px -96px; }
-
-.ui-icon-note {
- background-position: -64px -96px; }
-
-.ui-icon-mail-closed {
- background-position: -80px -96px; }
-
-.ui-icon-mail-open {
- background-position: -96px -96px; }
-
-.ui-icon-suitcase {
- background-position: -112px -96px; }
-
-.ui-icon-comment {
- background-position: -128px -96px; }
-
-.ui-icon-person {
- background-position: -144px -96px; }
-
-.ui-icon-print {
- background-position: -160px -96px; }
-
-.ui-icon-trash {
- background-position: -176px -96px; }
-
-.ui-icon-locked {
- background-position: -192px -96px; }
-
-.ui-icon-unlocked {
- background-position: -208px -96px; }
-
-.ui-icon-bookmark {
- background-position: -224px -96px; }
-
-.ui-icon-tag {
- background-position: -240px -96px; }
-
-.ui-icon-home {
- background-position: 0 -112px; }
-
-.ui-icon-flag {
- background-position: -16px -112px; }
-
-.ui-icon-calendar {
- background-position: -32px -112px; }
-
-.ui-icon-cart {
- background-position: -48px -112px; }
-
-.ui-icon-pencil {
- background-position: -64px -112px; }
-
-.ui-icon-clock {
- background-position: -80px -112px; }
-
-.ui-icon-disk {
- background-position: -96px -112px; }
-
-.ui-icon-calculator {
- background-position: -112px -112px; }
-
-.ui-icon-zoomin {
- background-position: -128px -112px; }
-
-.ui-icon-zoomout {
- background-position: -144px -112px; }
-
-.ui-icon-search {
- background-position: -160px -112px; }
-
-.ui-icon-wrench {
- background-position: -176px -112px; }
-
-.ui-icon-gear {
- background-position: -192px -112px; }
-
-.ui-icon-heart {
- background-position: -208px -112px; }
-
-.ui-icon-star {
- background-position: -224px -112px; }
-
-.ui-icon-link {
- background-position: -240px -112px; }
-
-.ui-icon-cancel {
- background-position: 0 -128px; }
-
-.ui-icon-plus {
- background-position: -16px -128px; }
-
-.ui-icon-plusthick {
- background-position: -32px -128px; }
-
-.ui-icon-minus {
- background-position: -48px -128px; }
-
-.ui-icon-minusthick {
- background-position: -64px -128px; }
-
-.ui-icon-close {
- background-position: -80px -128px; }
-
-.ui-icon-closethick {
- background-position: -96px -128px; }
-
-.ui-icon-key {
- background-position: -112px -128px; }
-
-.ui-icon-lightbulb {
- background-position: -128px -128px; }
-
-.ui-icon-scissors {
- background-position: -144px -128px; }
-
-.ui-icon-clipboard {
- background-position: -160px -128px; }
-
-.ui-icon-copy {
- background-position: -176px -128px; }
-
-.ui-icon-contact {
- background-position: -192px -128px; }
-
-.ui-icon-image {
- background-position: -208px -128px; }
-
-.ui-icon-video {
- background-position: -224px -128px; }
-
-.ui-icon-script {
- background-position: -240px -128px; }
-
-.ui-icon-alert {
- background-position: 0 -144px; }
-
-.ui-icon-info {
- background-position: -16px -144px; }
-
-.ui-icon-notice {
- background-position: -32px -144px; }
-
-.ui-icon-help {
- background-position: -48px -144px; }
-
-.ui-icon-check {
- background-position: -64px -144px; }
-
-.ui-icon-bullet {
- background-position: -80px -144px; }
-
-.ui-icon-radio-off {
- background-position: -96px -144px; }
-
-.ui-icon-radio-on {
- background-position: -112px -144px; }
-
-.ui-icon-pin-w {
- background-position: -128px -144px; }
-
-.ui-icon-pin-s {
- background-position: -144px -144px; }
-
-.ui-icon-play {
- background-position: 0 -160px; }
-
-.ui-icon-pause {
- background-position: -16px -160px; }
-
-.ui-icon-seek-next {
- background-position: -32px -160px; }
-
-.ui-icon-seek-prev {
- background-position: -48px -160px; }
-
-.ui-icon-seek-end {
- background-position: -64px -160px; }
-
-.ui-icon-seek-start {
- background-position: -80px -160px; }
-
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first {
- background-position: -80px -160px; }
-
-.ui-icon-stop {
- background-position: -96px -160px; }
-
-.ui-icon-eject {
- background-position: -112px -160px; }
-
-.ui-icon-volume-off {
- background-position: -128px -160px; }
-
-.ui-icon-volume-on {
- background-position: -144px -160px; }
-
-.ui-icon-power {
- background-position: 0 -176px; }
-
-.ui-icon-signal-diag {
- background-position: -16px -176px; }
-
-.ui-icon-signal {
- background-position: -32px -176px; }
-
-.ui-icon-battery-0 {
- background-position: -48px -176px; }
-
-.ui-icon-battery-1 {
- background-position: -64px -176px; }
-
-.ui-icon-battery-2 {
- background-position: -80px -176px; }
-
-.ui-icon-battery-3 {
- background-position: -96px -176px; }
-
-.ui-icon-circle-plus {
- background-position: 0 -192px; }
-
-.ui-icon-circle-minus {
- background-position: -16px -192px; }
-
-.ui-icon-circle-close {
- background-position: -32px -192px; }
-
-.ui-icon-circle-triangle-e {
- background-position: -48px -192px; }
-
-.ui-icon-circle-triangle-s {
- background-position: -64px -192px; }
-
-.ui-icon-circle-triangle-w {
- background-position: -80px -192px; }
-
-.ui-icon-circle-triangle-n {
- background-position: -96px -192px; }
-
-.ui-icon-circle-arrow-e {
- background-position: -112px -192px; }
-
-.ui-icon-circle-arrow-s {
- background-position: -128px -192px; }
-
-.ui-icon-circle-arrow-w {
- background-position: -144px -192px; }
-
-.ui-icon-circle-arrow-n {
- background-position: -160px -192px; }
-
-.ui-icon-circle-zoomin {
- background-position: -176px -192px; }
-
-.ui-icon-circle-zoomout {
- background-position: -192px -192px; }
-
-.ui-icon-circle-check {
- background-position: -208px -192px; }
-
-.ui-icon-circlesmall-plus {
- background-position: 0 -208px; }
-
-.ui-icon-circlesmall-minus {
- background-position: -16px -208px; }
-
-.ui-icon-circlesmall-close {
- background-position: -32px -208px; }
-
-.ui-icon-squaresmall-plus {
- background-position: -48px -208px; }
-
-.ui-icon-squaresmall-minus {
- background-position: -64px -208px; }
-
-.ui-icon-squaresmall-close {
- background-position: -80px -208px; }
-
-.ui-icon-grip-dotted-vertical {
- background-position: 0 -224px; }
-
-.ui-icon-grip-dotted-horizontal {
- background-position: -16px -224px; }
-
-.ui-icon-grip-solid-vertical {
- background-position: -32px -224px; }
-
-.ui-icon-grip-solid-horizontal {
- background-position: -48px -224px; }
-
-.ui-icon-gripsmall-diagonal-se {
- background-position: -64px -224px; }
-
-.ui-icon-grip-diagonal-se {
- background-position: -80px -224px; }
-
-/* Misc visuals
-----------------------------------*/
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
- -moz-border-radius-topleft: 2px;
- -webkit-border-top-left-radius: 2px;
- -khtml-border-top-left-radius: 2px;
- border-top-left-radius: 2px; }
-
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
- -moz-border-radius-topright: 2px;
- -webkit-border-top-right-radius: 2px;
- -khtml-border-top-right-radius: 2px;
- border-top-right-radius: 2px; }
-
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
- -moz-border-radius-bottomleft: 2px;
- -webkit-border-bottom-left-radius: 2px;
- -khtml-border-bottom-left-radius: 2px;
- border-bottom-left-radius: 2px; }
-
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
- -moz-border-radius-bottomright: 2px;
- -webkit-border-bottom-right-radius: 2px;
- -khtml-border-bottom-right-radius: 2px;
- border-bottom-right-radius: 2px; }
-
-/* Overlays */
-.ui-widget-overlay {
- background: #eeeeee url(../images/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x;
- opacity: .80;
- filter: Alpha(Opacity=80); }
-
-.ui-widget-shadow {
- margin: -4px 0 0 -4px;
- padding: 4px;
- background: #aaaaaa url(../images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
- opacity: .60;
- filter: Alpha(Opacity=60);
- -moz-border-radius: 0px;
- -khtml-border-radius: 0px;
- -webkit-border-radius: 0px;
- border-radius: 0px; }
-
- /*
-* jQuery UI Resizable 1.8.16
-*
-* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*
-* http://docs.jquery.com/UI/Resizable#theming
-*/
-.ui-resizable {
- position: relative; }
-
-.ui-resizable-handle {
- position: absolute;
- font-size: 0.1px;
- z-index: 99999;
- display: block; }
-
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle {
- display: none; }
-
-.ui-resizable-n {
- cursor: n-resize;
- height: 7px;
- width: 100%;
- top: -5px;
- left: 0; }
-
-.ui-resizable-s {
- cursor: s-resize;
- height: 7px;
- width: 100%;
- bottom: -5px;
- left: 0; }
-
-.ui-resizable-e {
- cursor: e-resize;
- width: 7px;
- right: -5px;
- top: 0;
- height: 100%; }
-
-.ui-resizable-w {
- cursor: w-resize;
- width: 7px;
- left: -5px;
- top: 0;
- height: 100%; }
-
-.ui-resizable-se {
- cursor: se-resize;
- width: 12px;
- height: 12px;
- right: 1px;
- bottom: 1px; }
-
-.ui-resizable-sw {
- cursor: sw-resize;
- width: 9px;
- height: 9px;
- left: -5px;
- bottom: -5px; }
-
-.ui-resizable-nw {
- cursor: nw-resize;
- width: 9px;
- height: 9px;
- left: -5px;
- top: -5px; }
-
-.ui-resizable-ne {
- cursor: ne-resize;
- width: 9px;
- height: 9px;
- right: -5px;
- top: -5px; }
-
- /*
-* jQuery UI Selectable 1.8.16
-*
-* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*
-* http://docs.jquery.com/UI/Selectable#theming
-*/
-.ui-selectable-helper {
- position: absolute;
- z-index: 100;
- border: 1px dotted black; }
-
-/*
- * jQuery UI Accordion 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion {
- width: 100%; }
-
-.ui-accordion .ui-accordion-header {
- cursor: pointer;
- position: relative;
- margin-top: 1px;
- zoom: 1; }
-
-.ui-accordion .ui-accordion-li-fix {
- display: inline; }
-
-.ui-accordion .ui-accordion-header-active {
- border-bottom: 0 !important; }
-
-.ui-accordion .ui-accordion-header a {
- display: block;
- font-size: 1em;
- padding: .5em .5em .5em .7em; }
-
-.ui-accordion-icons .ui-accordion-header a {
- padding-left: 2.2em; }
-
-.ui-accordion .ui-accordion-header .ui-icon {
- position: absolute;
- left: .5em;
- top: 50%;
- margin-top: -8px; }
-
-.ui-accordion .ui-accordion-content {
- padding: 1em 2.2em;
- border-top: 0;
- margin-top: -2px;
- position: relative;
- margin-bottom: 2px;
- overflow: auto;
- display: none;
- zoom: 1; }
-
-.ui-accordion .ui-accordion-content-active {
- display: block; }
-
-/*
- * jQuery UI Autocomplete 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete {
- position: absolute;
- cursor: default; }
-
-/* workarounds */
-* html .ui-autocomplete {
- width: 1px; }
-
-/* without this, the menu expands to 100% in IE6 */
-/*
- * jQuery UI Menu 1.8.16
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
- list-style: none;
- padding: 2px;
- margin: 0;
- display: block;
- float: left; }
-
-.ui-menu .ui-menu {
- margin-top: -3px; }
-
-.ui-menu .ui-menu-item {
- margin: 0;
- padding: 0;
- zoom: 1;
- float: left;
- clear: left;
- width: 100%; }
-
-.ui-menu .ui-menu-item a {
- text-decoration: none;
- display: block;
- padding: .2em .4em;
- line-height: 1.5;
- zoom: 1; }
-
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
- font-weight: normal;
- margin: -1px; }
-
-/*
- * jQuery UI Button 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button {
- display: inline-block;
- position: relative;
- padding: 0;
- margin-right: .1em;
- text-decoration: none !important;
- cursor: pointer;
- text-align: center;
- zoom: 1;
- overflow: visible; }
-
-/* the overflow property removes extra width in IE */
-.ui-button-icon-only {
- width: 2.2em; }
-
-/* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only {
- width: 2.4em; }
-
-/* button elements seem to need a little more width */
-.ui-button-icons-only {
- width: 3.4em; }
-
-button.ui-button-icons-only {
- width: 3.7em; }
-
-/*button text element */
-.ui-button .ui-button-text {
- display: block;
- line-height: 1.4; }
-
-.ui-button-text-only .ui-button-text {
- padding: .4em 1em; }
-
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text {
- padding: .4em;
- text-indent: -9999999px; }
-
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text {
- padding: .4em 1em .4em 2.1em; }
-
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text {
- padding: .4em 2.1em .4em 1em; }
-
-.ui-button-text-icons .ui-button-text {
- padding-left: 2.1em;
- padding-right: 2.1em; }
-
-/* no icon support for input elements, provide padding by default */
-input.ui-button {
- padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon {
- position: absolute;
- top: 50%;
- margin-top: -8px; }
-
-.ui-button-icon-only .ui-icon {
- left: 50%;
- margin-left: -8px; }
-
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary {
- left: .5em; }
-
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary {
- right: .5em; }
-
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary {
- right: .5em; }
-
-/*button sets*/
-.ui-buttonset {
- margin-right: 7px; }
-
-.ui-buttonset .ui-button {
- margin-left: 0;
- margin-right: -0.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner {
- border: 0;
- padding: 0; }
-
-/* reset extra padding in Firefox */
-/*
- * jQuery UI Dialog 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog {
- position: absolute;
- padding: .2em;
- width: 300px;
- overflow: hidden; }
-
-.ui-dialog .ui-dialog-titlebar {
- padding: .4em 1em;
- position: relative; }
-
-.ui-dialog .ui-dialog-title {
- float: left;
- margin: .1em 16px .1em 0; }
-
-.ui-dialog .ui-dialog-titlebar-close {
- position: absolute;
- right: .3em;
- top: 50%;
- width: 19px;
- margin: -10px 0 0 0;
- padding: 1px;
- height: 18px; }
-
-.ui-dialog .ui-dialog-titlebar-close span {
- display: block;
- margin: 1px; }
-
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus {
- padding: 0; }
-
-.ui-dialog .ui-dialog-content {
- position: relative;
- border: 0;
- padding: .5em 1em;
- background: none;
- overflow: auto;
- zoom: 1; }
-
-.ui-dialog .ui-dialog-buttonpane {
- text-align: left;
- border-width: 1px 0 0 0;
- background-image: none;
- margin: .5em 0 0 0;
- padding: .3em 1em .5em .4em; }
-
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
- float: right; }
-
-.ui-dialog .ui-dialog-buttonpane button {
- margin: .5em .4em .5em 0;
- cursor: pointer; }
-
-.ui-dialog .ui-resizable-se {
- width: 14px;
- height: 14px;
- right: 3px;
- bottom: 3px; }
-
-.ui-draggable .ui-dialog-titlebar {
- cursor: move; }
-
-/*
- * jQuery UI Slider 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider {
- position: relative;
- text-align: left; }
-
-.ui-slider .ui-slider-handle {
- position: absolute;
- z-index: 2;
- width: 1.2em;
- height: 1.2em;
- cursor: default; }
-
-.ui-slider .ui-slider-range {
- position: absolute;
- z-index: 1;
- font-size: .7em;
- display: block;
- border: 0;
- background-position: 0 0; }
-
-.ui-slider-horizontal {
- height: .8em; }
-
-.ui-slider-horizontal .ui-slider-handle {
- top: -0.3em;
- margin-left: -0.6em; }
-
-.ui-slider-horizontal .ui-slider-range {
- top: 0;
- height: 100%; }
-
-.ui-slider-horizontal .ui-slider-range-min {
- left: 0; }
-
-.ui-slider-horizontal .ui-slider-range-max {
- right: 0; }
-
-.ui-slider-vertical {
- width: .8em;
- height: 100px; }
-
-.ui-slider-vertical .ui-slider-handle {
- left: -0.3em;
- margin-left: 0;
- margin-bottom: -0.6em; }
-
-.ui-slider-vertical .ui-slider-range {
- left: 0;
- width: 100%; }
-
-.ui-slider-vertical .ui-slider-range-min {
- bottom: 0; }
-
-.ui-slider-vertical .ui-slider-range-max {
- top: 0; }
-
- /*
-* jQuery UI Tabs 1.8.16
-*
-* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*
-* http://docs.jquery.com/UI/Tabs#theming
-*/
-.ui-tabs {
- position: relative;
- padding: .2em;
- zoom: 1; }
-
-/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav {
- margin: 0;
- padding: .2em .2em 0; }
-
-.ui-tabs .ui-tabs-nav li {
- list-style: none;
- float: left;
- position: relative;
- top: 1px;
- margin: 0 .2em 1px 0;
- border-bottom: 0 !important;
- padding: 0;
- white-space: nowrap; }
-
-.ui-tabs .ui-tabs-nav li a {
- float: left;
- padding: .5em 1em;
- text-decoration: none; }
-
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
- margin-bottom: 0;
- padding-bottom: 1px; }
-
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a {
- cursor: text; }
-
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a {
- cursor: pointer; }
-
-/* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel {
- display: block;
- border-width: 0;
- padding: 1em 1.4em;
- background: none; }
-
-.ui-tabs .ui-tabs-hide {
- display: none !important; }
-
-/*
- * jQuery UI Datepicker 1.8.16
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker {
- width: 17em;
- padding: .2em .2em 0;
- display: none; }
-
-.ui-datepicker .ui-datepicker-header {
- position: relative;
- padding: .2em 0; }
-
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next {
- position: absolute;
- top: 2px;
- width: 1.8em;
- height: 1.8em; }
-
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover {
- top: 1px; }
-
-.ui-datepicker .ui-datepicker-prev {
- left: 2px; }
-
-.ui-datepicker .ui-datepicker-next {
- right: 2px; }
-
-.ui-datepicker .ui-datepicker-prev-hover {
- left: 1px; }
-
-.ui-datepicker .ui-datepicker-next-hover {
- right: 1px; }
-
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span {
- display: block;
- position: absolute;
- left: 50%;
- margin-left: -8px;
- top: 50%;
- margin-top: -8px; }
-
-.ui-datepicker .ui-datepicker-title {
- margin: 0 2.3em;
- line-height: 1.8em;
- text-align: center; }
-
-.ui-datepicker .ui-datepicker-title select {
- font-size: 1em;
- margin: 1px 0; }
-
-.ui-datepicker select.ui-datepicker-month-year {
- width: 100%; }
-
-.ui-datepicker select.ui-datepicker-month,
-.ui-datepicker select.ui-datepicker-year {
- width: 49%; }
-
-.ui-datepicker table {
- width: 100%;
- font-size: .9em;
- border-collapse: collapse;
- margin: 0 0 .4em; }
-
-.ui-datepicker th {
- padding: .7em .3em;
- text-align: center;
- font-weight: bold;
- border: 0; }
-
-.ui-datepicker td {
- border: 0;
- padding: 1px; }
-
-.ui-datepicker td span, .ui-datepicker td a {
- display: block;
- padding: .2em;
- text-align: right;
- text-decoration: none; }
-
-.ui-datepicker .ui-datepicker-buttonpane {
- background-image: none;
- margin: .7em 0 0 0;
- padding: 0 .2em;
- border-left: 0;
- border-right: 0;
- border-bottom: 0; }
-
-.ui-datepicker .ui-datepicker-buttonpane button {
- float: right;
- margin: .5em .2em .4em;
- cursor: pointer;
- padding: .2em .6em .3em .6em;
- width: auto;
- overflow: visible; }
-
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
- float: left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi {
- width: auto; }
-
-.ui-datepicker-multi .ui-datepicker-group {
- float: left; }
-
-.ui-datepicker-multi .ui-datepicker-group table {
- width: 95%;
- margin: 0 auto .4em; }
-
-.ui-datepicker-multi-2 .ui-datepicker-group {
- width: 50%; }
-
-.ui-datepicker-multi-3 .ui-datepicker-group {
- width: 33.3%; }
-
-.ui-datepicker-multi-4 .ui-datepicker-group {
- width: 25%; }
-
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header {
- border-left-width: 0; }
-
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
- border-left-width: 0; }
-
-.ui-datepicker-multi .ui-datepicker-buttonpane {
- clear: left; }
-
-.ui-datepicker-row-break {
- clear: both;
- width: 100%;
- font-size: 0em; }
-
-/* RTL support */
-.ui-datepicker-rtl {
- direction: rtl; }
-
-.ui-datepicker-rtl .ui-datepicker-prev {
- right: 2px;
- left: auto; }
-
-.ui-datepicker-rtl .ui-datepicker-next {
- left: 2px;
- right: auto; }
-
-.ui-datepicker-rtl .ui-datepicker-prev:hover {
- right: 1px;
- left: auto; }
-
-.ui-datepicker-rtl .ui-datepicker-next:hover {
- left: 1px;
- right: auto; }
-
-.ui-datepicker-rtl .ui-datepicker-buttonpane {
- clear: right; }
-
-.ui-datepicker-rtl .ui-datepicker-buttonpane button {
- float: left; }
-
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current {
- float: right; }
-
-.ui-datepicker-rtl .ui-datepicker-group {
- float: right; }
-
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header {
- border-right-width: 0;
- border-left-width: 1px; }
-
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
- border-right-width: 0;
- border-left-width: 1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
- display: none;
- /*sorry for IE5*/
- display/**/: block;
- /*sorry for IE5*/
- position: absolute;
- /*must have*/
- z-index: -1;
- /*must have*/
- filter: mask();
- /*must have*/
- top: -4px;
- /*must have*/
- left: -4px;
- /*must have*/
- width: 200px;
- /*must have*/
- height: 200px;
- /*must have*/ }
-
-/*
-* jQuery UI Progressbar 1.8.16
-*
-* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*
-* http://docs.jquery.com/UI/Progressbar#theming
-*/
-.ui-progressbar {
- height: 2em;
- text-align: left; }
-
-.ui-progressbar .ui-progressbar-value {
- margin: -1px;
- height: 100%; }
-
-.ui-tooltip, .qtip {
- position: absolute;
- left: -28000px;
- top: -28000px;
- display: none;
- max-width: 280px;
- min-width: 50px;
- font-size: 10.5px;
- line-height: 12px; }
-
-.ui-tooltip-fluid {
- display: block;
- visibility: hidden;
- position: static!important;
- float: left!important; }
-
-.ui-tooltip-content {
- position: relative;
- padding: 5px 9px;
- overflow: hidden;
- border: 1px solid #000001;
- text-align: left;
- word-wrap: break-word;
- overflow: hidden; }
-
-.ui-tooltip-titlebar {
- position: relative;
- min-height: 14px;
- padding: 5px 35px 5px 10px;
- overflow: hidden;
- border: 1px solid #000001;
- border-width: 1px 1px 0;
- font-weight: bold; }
-
-.ui-tooltip-titlebar + .ui-tooltip-content {
- border-top-width: 0!important; }
-
-/*Default close button class */
-.ui-tooltip-titlebar .ui-state-default {
- position: absolute;
- right: 4px;
- top: 50%;
- margin-top: -9px;
- cursor: pointer;
- outline: medium none;
- border-width: 1px;
- border-style: solid; }
-
-* html .ui-tooltip-titlebar .ui-state-default {
- top: 16px; }
-
-.ui-tooltip-titlebar .ui-icon, .ui-tooltip-icon .ui-icon {
- display: block;
- text-indent: -1000em; }
-
-.ui-tooltip-icon, .ui-tooltip-icon .ui-icon {
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- border-radius: 3px; }
-
-.ui-tooltip-icon .ui-icon {
- width: 18px;
- height: 14px;
- text-align: center;
- text-indent: 0;
- font: normal bold 10px/13px Tahoma, sans-serif;
- color: inherit;
- background: transparent none no-repeat -100em -100em; }
-
-/*Default tooltip style */
-.ui-tooltip-default .ui-tooltip-titlebar, .ui-tooltip-default .ui-tooltip-content {
- border-color: #F1D031;
- background-color: #FFFFA3;
- color: #555; }
-
-.ui-tooltip-default .ui-tooltip-titlebar {
- background-color: #FFEF93; }
-
-.ui-tooltip-default .ui-tooltip-icon {
- border-color: #CCC;
- background: #F1F1F1;
- color: #777; }
-
-.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover {
- border-color: #AAA;
- color: #111; }
-
-div.book-wrapper section.book-sidebar {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box; }
- div.book-wrapper section.book-sidebar ul#booknav {
- font-size: 12px; }
- div.book-wrapper section.book-sidebar ul#booknav a {
- color: #000; }
- div.book-wrapper section.book-sidebar ul#booknav a:hover {
- color: #666; }
- div.book-wrapper section.book-sidebar ul#booknav li {
- background: none;
- padding-left: 30px; }
- div.book-wrapper section.book-sidebar ul#booknav li div.hitarea {
- background-image: url("../images/treeview-default.gif");
- margin-left: -22px;
- position: relative;
- top: 4px; }
- div.book-wrapper section.book-sidebar ul#booknav li div.hitarea:hover {
- filter: alpha(opacity=60);
- opacity: 0.6; }
- div.book-wrapper section.book-sidebar ul#booknav li ul {
- background: none; }
- div.book-wrapper section.book-sidebar ul#booknav > li {
- border-bottom: 1px solid #d3d3d3;
- -webkit-box-shadow: 0 1px 0 #eeeeee;
- -moz-box-shadow: 0 1px 0 #eeeeee;
- box-shadow: 0 1px 0 #eeeeee;
- padding: 7px 7px 7px 30px; }
-div.book-wrapper section.book nav a {
- padding: 0 22.652px; }
-div.book-wrapper section.book nav ul li {
- background-color: #f2e9c3; }
- div.book-wrapper section.book nav ul li.last {
- display: block;
- float: left; }
- div.book-wrapper section.book nav ul li.last a {
- border-left: 0;
- border-right: 1px solid #e4d080;
- -webkit-box-shadow: inset -1px 0 0 #faf7e9;
- -moz-box-shadow: inset -1px 0 0 #faf7e9;
- box-shadow: inset -1px 0 0 #faf7e9; }
- div.book-wrapper section.book nav ul li.next {
- display: block;
- float: right; }
- div.book-wrapper section.book nav ul li:hover {
- background: none; }
-div.book-wrapper section.book nav.bottom-nav {
- border-bottom: 0;
- border-top: 1px solid #EDDFAA;
- margin-bottom: -22.652px;
- margin-top: 22.652px; }
-div.book-wrapper section.book section.page {
- text-align: center; }
- div.book-wrapper section.book section.page img {
- border: 1px solid #dddddd;
- max-width: 100%; }
-div.book-wrapper.closed section.book-sidebar {
- width: 3.077%; }
- div.book-wrapper.closed section.book-sidebar header#open_close_accordion {
- padding: 0; }
- div.book-wrapper.closed section.book-sidebar header#open_close_accordion a {
- background-image: url("../images/slide-right-icon.png"); }
- div.book-wrapper.closed section.book-sidebar header#open_close_accordion h2 {
- padding: 0;
- visibility: hidden;
- width: 10px; }
- div.book-wrapper.closed section.book-sidebar ul#booknav {
- max-height: 100px;
- overflow: hidden;
- padding: 0;
- visibility: hidden;
- width: 10px; }
-div.book-wrapper.closed section.course-content {
- width: 97.773%; }