diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py
index 2f22ba400f8c01916ae186d7538dc7e8fc56c474..7d37c193a5fd77ff469f5709092e7dab3b0178bd 100644
--- a/cms/djangoapps/models/settings/course_metadata.py
+++ b/cms/djangoapps/models/settings/course_metadata.py
@@ -78,6 +78,9 @@ class CourseMetadata(object):
         if not settings.FEATURES.get('ENABLE_TEAMS'):
             filtered_list.append('teams_configuration')
 
+        if not settings.FEATURES.get('ENABLE_VIDEO_BUMPER'):
+            filtered_list.append('video_bumper')
+
         return filtered_list
 
     @classmethod
diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py
index df8d0b73b16a7be929fcbb3c6f804e0a5d12475b..dcd120abf18acf4455d2e8c92a2fee489f8bbca9 100644
--- a/cms/envs/bok_choy.py
+++ b/cms/envs/bok_choy.py
@@ -74,6 +74,9 @@ FEATURES['ENABLE_TEAMS'] = True
 # Enable custom content licensing
 FEATURES['LICENSING'] = True
 
+FEATURES['ENABLE_MOBILE_REST_API'] = True  # Enable video bumper in Studio
+FEATURES['ENABLE_VIDEO_BUMPER'] = True  # Enable video bumper in Studio settings
+
 ########################### Entrance Exams #################################
 FEATURES['ENTRANCE_EXAMS'] = True
 
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 39a3008c307508d060c4a05b8ad95e345c4f88e9..f8d9e27354ce5985a9f64c36bdfa1dbe439cfbad 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -163,6 +163,13 @@ FEATURES = {
 
     # Teams feature
     'ENABLE_TEAMS': False,
+
+    # Show video bumper in Studio
+    'ENABLE_VIDEO_BUMPER': False,
+
+    # How many seconds to show the bumper again, default is 7 days:
+    'SHOW_BUMPER_PERIODICITY': 7 * 24 * 3600,
+
 }
 
 ENABLE_JASMINE = False
@@ -645,6 +652,8 @@ YOUTUBE = {
             'v': 'set_youtube_id_of_11_symbols_here',
         },
     },
+
+    'IMAGE_API': 'http://img.youtube.com/vi/{youtube_id}/0.jpg',  # /maxresdefault.jpg for 1920*1080
 }
 
 ############################# VIDEO UPLOAD PIPELINE #############################
diff --git a/common/lib/xmodule/xmodule/css/video/accessible_menu.scss b/common/lib/xmodule/xmodule/css/video/accessible_menu.scss
index 3c283df770677eaf5dbb5f13960864a13a5e762f..05739ef2ade412cd806118d0a34b49dd1636a55c 100644
--- a/common/lib/xmodule/xmodule/css/video/accessible_menu.scss
+++ b/common/lib/xmodule/xmodule/css/video/accessible_menu.scss
@@ -22,7 +22,7 @@ $a11y--blue-s1: saturate($blue,15%);
   }
 
   .a11y-menu-list {
-    @extend %ui-depth1;
+    @extend %ui-depth3;
     top: 100%;
     margin: 0;
     padding: 0;
diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss
index 8bbfdd1b2588959c94b70b656d766ddc4f3100bf..eb7ae8414968085a80d939dc9c6da002025f486f 100644
--- a/common/lib/xmodule/xmodule/css/video/display.scss
+++ b/common/lib/xmodule/xmodule/css/video/display.scss
@@ -27,6 +27,23 @@ div.video {
     }
   }
 
+  // CASE: video pre-roll state
+  &.is-pre-roll {
+    .slider {
+      visibility: hidden;
+    }
+
+    .video-player {
+      position: relative;
+      &:before {
+        display: block;
+        content: "";
+        width: 100%;
+        padding-top: 55%;
+      }
+    }
+  }
+
   div.tc-wrapper {
     @include clearfix();
     position: relative;
@@ -169,6 +186,7 @@ div.video {
       }
 
       object, iframe, video {
+        display: block;
         border: none;
         width: 100%;
       }
@@ -282,7 +300,7 @@ div.video {
         }
       }
 
-      ul.vcr {
+      .vcr {
         float: left;
         list-style: none;
         margin: 0 lh() 0 0;
@@ -293,49 +311,52 @@ div.video {
           font-size: em(14);
         }
 
-        li {
+        .video_control {
+          @extend %video-button;
           float: left;
-          margin-bottom: 0;
+          background-image: url('../images/vcr.png');
+          background-position: 15px 15px ;
+          background-repeat: no-repeat;
+          border-left: none;
+          padding: 0 lh(.75);
+          width: 14px;
 
-          a {
-            @extend %video-button;
-            background-image: url('../images/vcr.png');
-            background-position: 15px 15px ;
-            background-repeat: no-repeat;
-            border-left: none;
-            box-shadow: 1px 0 0 #555;
-            padding: 0 lh(.75);
-            width: 14px;
-
-            &:focus {
-              @extend %ui-depth4;
-              position: relative;
-              outline: $white dotted thin;
-              outline-offset: -2px;
-            }
+          &:focus {
+            @extend %ui-depth4;
+            position: relative;
+            outline: $white dotted thin;
+            outline-offset: -2px;
+          }
 
-            &:empty {
-              height: 46px;
-              background-position: 15px 15px;
-            }
+          &:empty {
+            height: 46px;
+            background-position: 15px 15px;
+          }
 
-            &.play {
-              background-position: 17px -114px;
-            }
+          &.play {
+            background-position: 17px -114px;
+          }
 
-            &.pause {
-              background-position: 16px -50px;
-            }
+          &.pause {
+            background-position: 16px -50px;
           }
 
-          div.vidtime {
-            font-weight: bold;
-            line-height: 46px; //height of play pause buttons
-            -webkit-font-smoothing: antialiased;
-            padding-left: lh(.75);
-            @media (max-width: 1120px) {
-              padding-left: lh(0.5);
-            }
+          &.skip {
+            background-image: none;
+            text-indent: 0;
+            width: initial;
+            white-space: nowrap;
+          }
+        }
+
+        div.vidtime {
+          @extend %t-strong;
+          float: left;
+          line-height: 46px; //height of play pause buttons
+          -webkit-font-smoothing: antialiased;
+          padding-left: lh(.75);
+          @media (max-width: 1120px) {
+            padding-left: lh(0.5);
           }
         }
       }
@@ -504,11 +525,14 @@ div.video {
             background-image: url('../images/volume.png');
             background-position: 10px center;
             background-repeat: no-repeat;
-            border-left: none;
             width: 30px;
             height: 46px;
           }
 
+          &:not(:first-child) > a {
+            border-left: none;
+          }
+
           .volume-slider-container {
             @include transition(none);
             @extend %ui-depth1;
@@ -686,8 +710,7 @@ div.video {
     }
 
     ol.subtitles {
-        width: 0;
-        height: 0;
+        @extend .is-hidden;
     }
 
     ol.subtitles.html5 {
@@ -792,13 +815,38 @@ div.video {
   &.is-touch {
     div.tc-wrapper {
       article.video-wrapper {
-        object, iframe, video{
+        object, iframe, video {
           width: 100%;
           height: 100%;
         }
       }
     }
   }
+
+  .video-pre-roll {
+    @extend %ui-depth3;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-position: 50% 50%;
+    background-repeat: no-repeat;
+    background-size: 100%;
+    background-color: $black;
+
+    &.is-html5 {
+      background-size: 15%;
+    }
+
+    .btn-play {
+      text-indent: -999px;
+      overflow: hidden;
+      border: none;
+      box-shadow: none;
+      line-height: 0;
+    }
+  }
 }
 
 
diff --git a/common/lib/xmodule/xmodule/js/fixtures/poster.jpg b/common/lib/xmodule/xmodule/js/fixtures/poster.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7f987f944e2dc670f2687b216cdead3579effc8d
Binary files /dev/null and b/common/lib/xmodule/xmodule/js/fixtures/poster.jpg differ
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video.html b/common/lib/xmodule/xmodule/js/fixtures/video.html
index e1fe11ae4736ccd83c9fb890fb553213568a85a5..dabb3801b97fb7e4c8e0862a18744a3f91b99033 100644
--- a/common/lib/xmodule/xmodule/js/fixtures/video.html
+++ b/common/lib/xmodule/xmodule/js/fixtures/video.html
@@ -4,22 +4,7 @@
       <div
         id="video_id"
         class="video closed"
-        data-streams="0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl"
-        data-show-captions="true"
-        data-save-state-url="/save_user_state"
-        data-speed="1.5"
-        data-start=""
-        data-end=""
-        data-saved-video-position="0"
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-api-url="www.youtube.com/iframe_api"
-        data-yt-test-url="gdata.youtube.com/feeds/api/videos/"
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": "[]", "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="focus_grabber first"></div>
 
@@ -35,35 +20,11 @@
             <section class="video-controls is-hidden">
               <div class="slider"></div>
               <div>
-                <ul class="vcr">
-                  <li><a class="video_control" href="#" title="Play" role="button" aria-disabled="false"></a></li>
-                  <li><div class="vidtime">0:00 / 0:00</div></li>
-                </ul>
-                <div class="secondary-controls">
-                  <div class="speeds">
-                    <a class="speed-button" href="#" title="Speeds" role="button" aria-disabled="false">
-                      <span class="label">Speed</span>
-                      <span class="value"></span>
-                    </a>
-                    <ol class="video-speeds"></ol>
-                  </div>
-                  <div class="volume">
-                    <a href="#" title="Volume" role="button" aria-disabled="false"></a>
-                    <div class="volume-slider-container">
-                      <div class="volume-slider"></div>
-                    </div>
-                  </div>
-                  <a href="#" class="add-fullscreen" title="Fill browser" role="button" aria-disabled="false">Fill Browser</a>
-                  <a href="#" class="quality-control is-hidden" title="HD off" role="button" aria-disabled="false">HD off</a>
-                  <div class="lang menu-container">
-                    <a href="#" class="hide-subtitles" title="Turn off captions" role="button" aria-disabled="false">Captions</a>
-                  </div>
-                </div>
+                <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                <div class="secondary-controls"></div>
               </div>
             </section>
           </article>
-
-          <ol class="subtitles"><li></li></ol>
         </div>
 
         <div class="focus_grabber last"></div>
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_all.html b/common/lib/xmodule/xmodule/js/fixtures/video_all.html
index 1b0727d3d797937927a55b7b313a2da2d6e002c5..617d9583576084cba5e7385c14a3a1b493a788ef 100644
--- a/common/lib/xmodule/xmodule/js/fixtures/video_all.html
+++ b/common/lib/xmodule/xmodule/js/fixtures/video_all.html
@@ -4,23 +4,7 @@
       <div
         id="video_id"
         class="video closed"
-        data-show-captions="true"
-        data-save-state-url="/save_user_state"
-        data-speed="1.5"
-        data-start=""
-        data-end=""
-        data-saved-video-position="0"
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-sub="Z5KLxerq05Y"
-        data-sources='["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"]'
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-api-url="www.youtube.com/iframe_api"
-        data-yt-test-url="gdata.youtube.com/feeds/api/videos/"
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="focus_grabber first"></div>
 
@@ -36,35 +20,11 @@
             <section class="video-controls is-hidden">
               <div class="slider"></div>
               <div>
-                <ul class="vcr">
-                  <li><a class="video_control" href="#" title="Play" role="button" aria-disabled="false"></a></li>
-                  <li><div class="vidtime">0:00 / 0:00</div></li>
-                </ul>
-                <div class="secondary-controls">
-                  <div class="speeds">
-                    <a class="speed-button" href="#" title="Speeds" role="button" aria-disabled="false">
-                      <span class="label">Speed</span>
-                      <span class="value"></span>
-                    </a>
-                    <ol class="video-speeds"></ol>
-                  </div>
-                  <div class="volume">
-                    <a href="#" title="Volume" role="button" aria-disabled="false"></a>
-                    <div class="volume-slider-container">
-                      <div class="volume-slider"></div>
-                    </div>
-                  </div>
-                  <a href="#" class="add-fullscreen" title="Fill browser" role="button" aria-disabled="false">Fill Browser</a>
-                  <a href="#" class="quality-control is-hidden" title="HD off" role="button" aria-disabled="false">HD off</a>
-                  <div class="lang menu-container">
-                    <a href="#" class="hide-subtitles" title="Turn off captions" role="button" aria-disabled="false">Captions</a>
-                  </div>
-                </div>
+                <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                <div class="secondary-controls"></div>
               </div>
             </section>
           </article>
-
-          <ol class="subtitles"><li></li></ol>
         </div>
 
         <div class="focus_grabber last"></div>
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_html5.html b/common/lib/xmodule/xmodule/js/fixtures/video_html5.html
index 678803a90ddeee2a4c72b3624438aa4c1e2d8d93..47be4f04fcb9461ac235f8b6eaed668d0cef4a9f 100644
--- a/common/lib/xmodule/xmodule/js/fixtures/video_html5.html
+++ b/common/lib/xmodule/xmodule/js/fixtures/video_html5.html
@@ -4,23 +4,7 @@
       <div
         id="video_id"
         class="video closed"
-        data-show-captions="true"
-        data-save-state-url="/save_user_state"
-        data-speed="1.5"
-        data-start=""
-        data-end=""
-        data-saved-video-position="0"
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-sub="Z5KLxerq05Y"
-        data-sources='["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"]'
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-api-url="www.youtube.com/iframe_api"
-        data-yt-test-url="gdata.youtube.com/feeds/api/videos/"
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/", "source": "", "html5_sources": ["http://youtu.be/3_yD_cEKoCk.mp4"]}'
       >
         <div class="focus_grabber first"></div>
 
@@ -33,8 +17,6 @@
             </section>
             <section class="video-controls is-hidden"></section>
           </article>
-
-          <ol class="subtitles"><li></li></ol>
         </div>
 
         <div class="focus_grabber last"></div>
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html b/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html
index a34df976bfb695724d7f997ad4f471d3102b6e58..77017d403dd16084d8c8e11544b73c046d6b28a1 100644
--- a/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html
+++ b/common/lib/xmodule/xmodule/js/fixtures/video_no_captions.html
@@ -4,22 +4,7 @@
       <div
         id="video_id"
         class="video closed"
-        data-streams="0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl"
-        data-show-captions="false"
-        data-save-state-url="/save_user_state"
-        data-speed="1.5"
-        data-start=""
-        data-end=""
-        data-saved-video-position="0"
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-api-url="www.youtube.com/iframe_api"
-        data-yt-test-url="gdata.youtube.com/feeds/api/videos/"
-        data-autohide-html5="True"
+        data-metadata='{"streams":"0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "showCaptions": false, "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "speed": "1.5", "startTime": "", "end": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="focus_grabber first"></div>
 
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html b/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html
new file mode 100644
index 0000000000000000000000000000000000000000..22bd2062689fdf203f788cfab7f81dd4cf5d8eaf
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/fixtures/video_with_bumper.html
@@ -0,0 +1,36 @@
+<div class="course-content">
+  <div id="video_example">
+    <div id="example">
+      <div
+        id="video_id"
+        class="video closed"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
+        data-bumper-metadata='{"transcriptLanguage": "en", "showCaptions": "true", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "transcriptTranslationUrl": "/transcript/translation/__lang__/?is_bumper=1", "transcriptAvailableTranslationsUrl": "/transcript/available_translations/?is_bumper=1", "streams": "", "saveStateUrl": "/save_user_state"}'
+        data-poster='{"url": "xmodule/include/fixtures/poster.jpg", "type": "youtube"}'
+      >
+        <div class="focus_grabber first"></div>
+
+        <div class="tc-wrapper">
+          <article class="video-wrapper">
+            <span tabindex="0" class="spinner" aria-hidden="false" aria-label="${_('Loading video player')}"></span>
+            <span tabindex="-1" class="btn-play is-hidden" aria-hidden="true" aria-label="${_('Play video')}"></span>
+            <div class="video-player-pre"></div>
+            <section class="video-player">
+              <iframe id="id"></iframe>
+            </section>
+            <div class="video-player-post"></div>
+            <section class="video-controls is-hidden">
+              <div class="slider"></div>
+              <div>
+                <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                <div class="secondary-controls"></div>
+              </div>
+            </section>
+          </article>
+        </div>
+
+        <div class="focus_grabber last"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html b/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html
index 8086c2b2691af07ace19552217f92ddb54088dbe..8842b1e5926f6c5e45dd0e97cbb2d632a5fd1b01 100644
--- a/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html
+++ b/common/lib/xmodule/xmodule/js/fixtures/video_yt_multiple.html
@@ -4,22 +4,7 @@
       <div
         id="video_id1"
         class="video closed"
-        data-streams="0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl"
-        data-show-captions="true"
-        data-save-state-url="/save_user_state"
-        data-speed="1.5"
-        data-start=""
-        data-end=""
-        data-saved-video-position="0"
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-api-url="www.youtube.com/iframe_api"
-        data-yt-test-url="gdata.youtube.com/feeds/api/videos/"
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="focus_grabber first"></div>
 
@@ -35,35 +20,11 @@
             <section class="video-controls is-hidden">
               <div class="slider"></div>
               <div>
-                <ul class="vcr">
-                  <li><a class="video_control" href="#" title="Play" role="button" aria-disabled="false"></a></li>
-                  <li><div class="vidtime">0:00 / 0:00</div></li>
-                </ul>
-                <div class="secondary-controls">
-                  <div class="speeds">
-                    <a class="speed-button" href="#" title="Speeds" role="button" aria-disabled="false">
-                      <span class="label">Speed</span>
-                      <span class="value"></span>
-                    </a>
-                    <ol class="video-speeds"></ol>
-                  </div>
-                  <div class="volume">
-                    <a href="#" title="Volume" role="button" aria-disabled="false"></a>
-                    <div class="volume-slider-container">
-                      <div class="volume-slider"></div>
-                    </div>
-                  </div>
-                  <a href="#" class="add-fullscreen" title="Fill browser" role="button" aria-disabled="false">Fill Browser</a>
-                  <a href="#" class="quality-control is-hidden" title="HD off" role="button" aria-disabled="false">HD off</a>
-                  <div class="lang menu-container">
-                    <a href="#" class="hide-subtitles" title="Turn off captions" role="button" aria-disabled="false">Captions</a>
-                  </div>
-                </div>
+                <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                <div class="secondary-controls"></div>
               </div>
             </section>
           </article>
-
-          <ol class="subtitles"><li></li></ol>
         </div>
 
         <div class="focus_grabber last"></div>
@@ -77,20 +38,7 @@
       <div
         id="video_id2"
         class="video"
-        data-streams="0.75:7tqY6eQzVhE,1.0:cogebirgzzM"
-        data-show-captions="true"
-        data-speed="1.0"
-        data-start=""
-        data-end=""
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
-
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="tc-wrapper">
           <article class="video-wrapper">
@@ -102,30 +50,8 @@
             <section class="video-controls">
               <div class="slider"></div>
               <div>
-                <ul class="vcr">
-                  <li><a class="video_control" href="#" title="Play"></a></li>
-                  <li><div class="vidtime">0:00 / 0:00</div></li>
-                </ul>
-                <div class="secondary-controls">
-                  <div class="speeds">
-                    <a class="speed-button" href="#" title="Speeds" role="button" aria-disabled="false">
-                      <span class="label">Speed</span>
-                      <span class="value"></span>
-                    </a>
-                    <ol class="video-speeds"></ol>
-                  </div>
-                  <div class="volume">
-                    <a href="#"></a>
-                    <div class="volume-slider-container">
-                      <div class="volume-slider"></div>
-                    </div>
-                  </div>
-                  <a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>
-                  <a href="#" class="quality-control is-hidden" title="HD">HD</a>
-                  <div class="lang menu-container">
-                    <a href="#" class="hide-subtitles" title="Turn off captions" role="button" aria-disabled="false">Captions</a>
-                  </div>
-                </div>
+                <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                <div class="secondary-controls"></div>
               </div>
             </section>
           </article>
@@ -142,20 +68,7 @@
       <div
         id="video_id3"
         class="video"
-        data-streams="0.75:7tqY6eQzVhE,1.0:cogebirgzzM"
-        data-show-captions="true"
-        data-speed="1.0"
-        data-start=""
-        data-end=""
-        data-transcript-language="en"
-        data-transcript-languages='{"en": "English", "de": "Deutsch", "zh": "普通话"}'
-        data-transcript-translation-url="/transcript/translation"
-        data-transcript-available-translations-url="/transcript/available_translations"
-        data-autoplay="False"
-        data-yt-test-timeout="1500"
-        data-yt-test-url="https://gdata.youtube.com/feeds/api/videos/"
-
-        data-autohide-html5="True"
+        data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytTestUrl": "gdata.youtube.com/feeds/api/videos/"}'
       >
         <div class="tc-wrapper">
           <article class="video-wrapper">
diff --git a/common/lib/xmodule/xmodule/js/spec/helper.js b/common/lib/xmodule/xmodule/js/spec/helper.js
index f188c9c639eac6660f8a687173d0cc92de0d48b7..97d422d5d8917cf8aae6e3e8240d19a5f1ab3523 100644
--- a/common/lib/xmodule/xmodule/js/spec/helper.js
+++ b/common/lib/xmodule/xmodule/js/spec/helper.js
@@ -206,6 +206,9 @@
             },
             toBeInArray: function (array) {
                 return $.inArray(this.actual, array) > -1;
+            },
+            toBeFocused: function () {
+                return $(this.actual)[0] === $(this.actual)[0].ownerDocument.activeElement;
             }
         });
 
@@ -239,12 +242,11 @@
             loadFixtures('video_all.html');
         }
 
-        // If `params` is an object, assign it's properties as data attributes
+        // If `params` is an object, assign its properties as data attributes
         // to the main video DIV element.
         if (_.isObject(params)) {
-            $('#example')
-                .find('#video_id')
-                .data(params);
+            var metadata = _.extend($('#video_id').data('metadata'), params);
+            $('#video_id').data('metadata', metadata);
         }
 
         jasmine.stubRequests();
diff --git a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
index 72fc269fd8ad755169c80e7057c740866227ec14..7cefab5e4999dcf7aa058a5c15da93053e77d60e 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js
@@ -1,6 +1,6 @@
 (function (undefined) {
     describe('Video', function () {
-        var oldOTBD;
+        var oldOTBD, state;
 
         beforeEach(function () {
             jasmine.stubRequests();
@@ -17,11 +17,12 @@
                 beforeEach(function () {
                     loadFixtures('video.html');
                     $.cookie.andReturn('0.50');
+                    this.state = jasmine.initializePlayerYouTube('video_html5.html');
                 });
 
                 describe('by default', function () {
-                    beforeEach(function () {
-                        this.state = new window.Video('#example');
+                    afterEach(function () {
+                        this.state.videoPlayer.destroy();
                     });
 
                     it('check videoType', function () {
@@ -54,19 +55,16 @@
                 var state;
 
                 beforeEach(function () {
-                    loadFixtures('video_html5.html');
                     $.cookie.andReturn('0.75');
+                    state = jasmine.initializePlayer('video_html5.html');
                 });
 
-                describe('by default', function () {
-                    beforeEach(function () {
-                        state = new window.Video('#example');
-                    });
-
-                    afterEach(function () {
-                        state = undefined;
-                    });
+                afterEach(function () {
+                    state.videoPlayer.destroy();
+                    state = undefined;
+                });
 
+                describe('by default', function () {
                     it('check videoType', function () {
                         expect(state.videoType).toEqual('html5');
                     });
@@ -95,14 +93,6 @@
                 // the stand alone HTML5 player object is already loaded, so no
                 // further testing in that case is required.
                 describe('HTML5 API is available', function () {
-                    beforeEach(function () {
-                        state = new Video('#example');
-                    });
-
-                    afterEach(function () {
-                        state = null;
-                    });
-
                     it('create the Video Player', function () {
                         expect(state.videoPlayer.player).not.toBeUndefined();
                     });
@@ -113,8 +103,11 @@
         describe('YouTube API is not loaded', function () {
             beforeEach(function () {
                 window.YT = undefined;
+                state = jasmine.initializePlayerYouTube();
+            })
 
-                state = jasmine.initializePlayerYouTube('video.html');
+            afterEach(function () {
+                state.videoPlayer.destroy();
             });
 
             it('callback, to be called after YouTube API loads, exists and is called', function () {
@@ -159,9 +152,8 @@
                 }
             ];
 
-            beforeEach(function () {
-                loadFixtures('video.html');
-
+            afterEach(function () {
+                state.videoPlayer.destroy();
             });
 
             $.each(miniTestSuite, function (index, test) {
@@ -172,13 +164,10 @@
 
             function itFabrique(itDescription, data, expectData) {
                 it(itDescription, function () {
-                    $('#example').find('.video')
-                        .data({
-                            'start': data.start,
-                            'end': data.end
-                        });
-
-                    state = new Video('#example');
+                    state = jasmine.initializePlayer('video.html', {
+                        'start': data.start,
+                        'end': data.end
+                    });
 
                     expect(state.config.startTime).toBe(expectData.start);
                     expect(state.config.endTime).toBe(expectData.end);
@@ -238,26 +227,5 @@
                 expect(numAjaxCalls).toBe(1);
             });
         });
-
-        describe('log', function () {
-            beforeEach(function () {
-                loadFixtures('video_html5.html');
-                state = new Video('#example');
-                spyOn(Logger, 'log');
-                state.videoPlayer.log('someEvent', {
-                    currentTime: 25,
-                    speed: '1.0'
-                });
-            });
-
-            it('call the logger with valid extra parameters', function () {
-                expect(Logger.log).toHaveBeenCalledWith('someEvent', {
-                    id: 'id',
-                    code: 'html5',
-                    currentTime: 25,
-                    speed: '1.0'
-                });
-            });
-        });
     });
 }).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
index baefb4dea1cc46dd74e001176f33c4864df58a3b..b22cdd375efde43d2e59eaa5fb64e0a03cf90cd4 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js
@@ -10,8 +10,8 @@
 
         afterEach(function () {
             state.storage.clear();
+            state.videoPlayer.destroy();
             $.fn.scrollTo.reset();
-            $('.subtitles').remove();
             $('source').remove();
             window.onTouchBasedDevice = oldOTBD;
         });
diff --git a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js
index e08ba56a7516cfaa844f7105e952fa6c1a3512e0..f3194b8bce3a13223e08be0409ea929e60e425bd 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js
@@ -12,158 +12,6 @@ function (Initialize) {
             state = {};
         });
 
-        describe('saveState function', function () {
-            var videoPlayerCurrentTime, newCurrentTime, speed;
-
-            // We make sure that `currentTime` is a float. We need to test
-            // that Math.round() is called.
-            videoPlayerCurrentTime = 3.1242;
-
-            // We have two times, because one is  stored in
-            // `videoPlayer.currentTime`, and the other is passed directly to
-            // `saveState` in `data` object. In each case, there is different
-            // code that handles these times. They have to be different for
-            // test completeness sake. Also, make sure it is float, as is the
-            // time above.
-            newCurrentTime = 5.4;
-
-            speed = '0.75';
-
-            beforeEach(function () {
-                state = {
-                    videoPlayer: {
-                        currentTime: videoPlayerCurrentTime
-                    },
-                    storage: {
-                        setItem: jasmine.createSpy()
-                    },
-                    config: {
-                        saveStateUrl: 'http://example.com/save_user_state'
-                    }
-                };
-
-                spyOn($, 'ajax');
-                spyOn(Time, 'formatFull').andCallThrough();
-            });
-
-            it('data is not an object, async is true', function () {
-                itSpec({
-                    asyncVal: true,
-                    speedVal: undefined,
-                    positionVal: videoPlayerCurrentTime,
-                    data: undefined,
-                    ajaxData: {
-                        saved_video_position: Time.formatFull(Math.round(videoPlayerCurrentTime))
-                    }
-                });
-            });
-
-            it('data contains speed, async is false', function () {
-                itSpec({
-                    asyncVal: false,
-                    speedVal: speed,
-                    positionVal: undefined,
-                    data: {
-                        speed: speed
-                    },
-                    ajaxData: {
-                        speed: speed
-                    }
-                });
-            });
-
-            it('data contains float position, async is true', function () {
-                itSpec({
-                    asyncVal: true,
-                    speedVal: undefined,
-                    positionVal: newCurrentTime,
-                    data: {
-                        saved_video_position: newCurrentTime
-                    },
-                    ajaxData: {
-                        saved_video_position: Time.formatFull(Math.round(newCurrentTime))
-                    }
-                });
-            });
-
-            it('data contains speed and rounded position, async is false', function () {
-                itSpec({
-                    asyncVal: false,
-                    speedVal: speed,
-                    positionVal: Math.round(newCurrentTime),
-                    data: {
-                        speed: speed,
-                        saved_video_position: Math.round(newCurrentTime)
-                    },
-                    ajaxData: {
-                        speed: speed,
-                        saved_video_position: Time.formatFull(Math.round(newCurrentTime))
-                    }
-                });
-            });
-
-            it('data contains empty object, async is true', function () {
-                itSpec({
-                    asyncVal: true,
-                    speedVal: undefined,
-                    positionVal: undefined,
-                    data: {},
-                    ajaxData: {}
-                });
-            });
-
-            it('data contains position 0, async is true', function () {
-                itSpec({
-                    asyncVal: true,
-                    speedVal: undefined,
-                    positionVal: 0,
-                    data: {
-                        saved_video_position: 0
-                    },
-                    ajaxData: {
-                        saved_video_position: Time.formatFull(Math.round(0))
-                    }
-                });
-            });
-
-            return;
-
-            function itSpec(value) {
-                var asyncVal    = value.asyncVal,
-                    speedVal    = value.speedVal,
-                    positionVal = value.positionVal,
-                    data        = value.data,
-                    ajaxData    = value.ajaxData;
-
-                Initialize.prototype.saveState.call(state, asyncVal, data);
-
-                if (speedVal) {
-                    expect(state.storage.setItem).toHaveBeenCalledWith(
-                        'speed',
-                        speedVal,
-                        true
-                    );
-                }
-                if (positionVal) {
-                    expect(state.storage.setItem).toHaveBeenCalledWith(
-                        'savedVideoPosition',
-                        positionVal,
-                        true
-                    );
-                    expect(Time.formatFull).toHaveBeenCalledWith(
-                        positionVal
-                    );
-                }
-                expect($.ajax).toHaveBeenCalledWith({
-                    url: state.config.saveStateUrl,
-                    type: 'POST',
-                    async: asyncVal,
-                    dataType: 'json',
-                    data: ajaxData
-                });
-            }
-        });
-
         describe('getCurrentLanguage', function () {
             var msg;
 
@@ -356,20 +204,12 @@ function (Initialize) {
 
                 describe('when new speed is available', function () {
                     beforeEach(function () {
-                        Initialize.prototype.setSpeed.call(state, '0.75', true);
+                        Initialize.prototype.setSpeed.call(state, '0.75');
                     });
 
                     it('set new speed', function () {
                         expect(state.speed).toEqual('0.75');
                     });
-
-                    it('save setting for new speed', function () {
-                        expect(state.storage.setItem.calls[0].args)
-                            .toEqual(['speed', '0.75', true]);
-
-                        expect(state.storage.setItem.calls[1].args)
-                            .toEqual(['general_speed', '0.75']);
-                    });
                 });
 
                 describe('when new speed is not available', function () {
@@ -390,7 +230,7 @@ function (Initialize) {
                     };
 
                     $.each(map, function(key, expected) {
-                        Initialize.prototype.setSpeed.call(state, key, true);
+                        Initialize.prototype.setSpeed.call(state, key);
                         expect(state.speed).toBe(expected);
                     });
                 });
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js
index feb332122cf7cf386e24acdef84d6998f80bc361..a790f8ecaee8bc29cad84c02ead5d5d4453849d5 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js
@@ -5,6 +5,7 @@
         afterEach(function () {
             $('source').remove();
             state.storage.clear();
+            state.videoPlayer.destroy();
         });
 
         describe('constructor', function () {
@@ -56,24 +57,6 @@
                     });
                     */
                 });
-
-                it('add ARIA attributes to button, menu, and menu items links',
-                   function () {
-                    expect(button).toHaveAttrs({
-                        'role': 'button',
-                        'title': '.srt',
-                        'aria-disabled': 'false'
-                    });
-
-                    expect(menuList).toHaveAttr('role', 'menu');
-
-                    menuItemsLinks.each(function(){
-                        expect($(this)).toHaveAttrs({
-                            'role': 'menuitem',
-                            'aria-disabled': 'false'
-                        });
-                    });
-                });
             });
 
             describe('when running', function () {
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a355e918d2c288ba9dcb921c7eb4fa290c412ce
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js
@@ -0,0 +1,109 @@
+(function (WAIT_TIMEOUT) {
+    'use strict';
+    describe('VideoBumper', function () {
+        var state, oldOTBD, waitForPlaying;
+
+        waitForPlaying = function (state) {
+            waitsFor(function () {
+                return state.el.hasClass('is-playing');
+            }, 'Player is not playing.', WAIT_TIMEOUT);
+        };
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+            state = jasmine.initializePlayer('video_with_bumper.html');
+            $('.poster .btn-play').click();
+            jasmine.Clock.useMock();
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            if (state.bumperState && state.bumperState.videoPlayer) {
+                state.bumperState.videoPlayer.destroy();
+            }
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        it('can render the bumper video', function () {
+            expect($('.is-bumper')).toExist();
+        });
+
+        it('can show the main video on error', function () {
+            state.el.trigger('error');
+            jasmine.Clock.tick(20);
+            expect($('.is-bumper')).not.toExist();
+            waitForPlaying(state);
+        });
+
+        it('can show the main video once bumper ends', function () {
+            state.el.trigger('ended');
+            jasmine.Clock.tick(20);
+            expect($('.is-bumper')).not.toExist();
+            waitForPlaying(state);
+        });
+
+        it('can show the main video on skip', function () {
+            state.bumperState.videoBumper.skip();
+            jasmine.Clock.tick(20);
+            expect($('.is-bumper')).not.toExist();
+            waitForPlaying(state);
+        });
+
+        it('can stop the bumper video playing if it is too long', function () {
+            state.el.trigger('timeupdate', [state.bumperState.videoBumper.maxBumperDuration + 1]);
+            jasmine.Clock.tick(20);
+            expect($('.is-bumper')).not.toExist();
+            waitForPlaying(state);
+        });
+
+        it('can save appropriate states correctly on ended', function () {
+            var saveState = jasmine.createSpy('saveState');
+            state.bumperState.videoSaveStatePlugin.saveState = saveState;
+            state.el.trigger('ended');
+            jasmine.Clock.tick(20);
+            expect(saveState).toHaveBeenCalledWith(true, {
+                bumper_last_view_date: true});
+        });
+
+        it('can save appropriate states correctly on skip', function () {
+            var saveState = jasmine.createSpy('saveState');
+            state.bumperState.videoSaveStatePlugin.saveState = saveState;
+            state.bumperState.videoBumper.skip();
+            expect(state.storage.getItem('isBumperShown')).toBeTruthy();
+            jasmine.Clock.tick(20);
+            expect(saveState).toHaveBeenCalledWith(true, {
+                bumper_last_view_date: true});
+        });
+
+         it('can save appropriate states correctly on error', function () {
+            var saveState = jasmine.createSpy('saveState');
+            state.bumperState.videoSaveStatePlugin.saveState = saveState;
+            state.el.trigger('error');
+            expect(state.storage.getItem('isBumperShown')).toBeTruthy();
+            jasmine.Clock.tick(20);
+            expect(saveState).toHaveBeenCalledWith(true, {
+                bumper_last_view_date: true});
+        });
+
+        it('can save appropriate states correctly on skip and do not show again', function () {
+            var saveState = jasmine.createSpy('saveState');
+            state.bumperState.videoSaveStatePlugin.saveState = saveState;
+            state.bumperState.videoBumper.skipAndDoNotShowAgain();
+            expect(state.storage.getItem('isBumperShown')).toBeTruthy();
+            jasmine.Clock.tick(20);
+            expect(saveState).toHaveBeenCalledWith(true, {
+                bumper_last_view_date: true, bumper_do_not_show_again: true});
+        });
+
+        it('can destroy itself', function () {
+            state.bumperState.videoBumper.destroy();
+            expect(state.videoBumper).toBeUndefined();
+        });
+    });
+}).call(this, window.WAIT_TIMEOUT);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
index 39778d7ba6ca5512847d5bebe9490783effff260..f269bde541a2fba11382604ebf5dc068d0a085f0 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
@@ -11,14 +11,13 @@
         });
 
         afterEach(function () {
-            $('.subtitles').remove();
-
             // `source` tags should be removed to avoid memory leak bug that we
             // had before. Removing of `source` tag, not `video` tag, stops
             // loading video source and clears the memory.
             $('source').remove();
             $.fn.scrollTo.reset();
             state.storage.clear();
+            state.videoPlayer.destroy();
 
             window.onTouchBasedDevice = oldOTBD;
         });
@@ -121,11 +120,6 @@
                     });
                 });
 
-                it('bind the hide caption button', function () {
-                    state = jasmine.initializePlayer();
-                    expect($('.hide-subtitles')).toHandle('click');
-                });
-
                 it('bind the mouse movement', function () {
                     state = jasmine.initializePlayer();
                     expect($('.subtitles')).toHandle('mouseover');
@@ -143,6 +137,27 @@
 
             });
 
+            it('can destroy itself', function () {
+                spyOn($, 'ajaxWithPrefix');
+                state = jasmine.initializePlayer();
+                var plugin = state.videoCaption;
+
+                spyOn($.fn, 'off').andCallThrough();
+                state.videoCaption.destroy();
+
+                expect(state.videoCaption).toBeUndefined();
+                expect($.fn.off).toHaveBeenCalledWith({
+                    'caption:fetch': plugin.fetchCaption,
+                    'caption:resize': plugin.onResize,
+                    'caption:update': plugin.onCaptionUpdate,
+                    'ended': plugin.pause,
+                    'fullscreen': plugin.onResize,
+                    'pause': plugin.pause,
+                    'play': plugin.play,
+                    'destroy': plugin.destroy
+                });
+            });
+
             describe('renderLanguageMenu', function () {
                 describe('is rendered', function () {
                     it('if languages more than 1', function () {
@@ -593,7 +608,7 @@
             it(msg, function () {
                 spyOn(Caption, 'fetchAvailableTranslations');
                 $.ajax.andCallFake(function (settings) {
-                    settings.error([]);
+                    _.result(settings, 'error');
                 });
 
                 state.config.transcriptLanguages = {};
@@ -612,7 +627,7 @@
             xit(msg, function () {
                 $.ajax
                     .andCallFake(function (settings) {
-                        settings.error([]);
+                        _.result(settings, 'error');
                     });
 
                 state.config.transcriptLanguages = {
@@ -690,7 +705,7 @@
             msg = 'on error: captions are hidden if there are no transcript';
             it(msg, function () {
                 $.ajax.andCallFake(function (settings) {
-                    settings.error();
+                    _.result(settings, 'error');
                 });
                 Caption.fetchAvailableTranslations();
 
@@ -907,8 +922,8 @@
                             $('.subtitles').css('maxHeight'), 10
                         );
                         videoWrapperHeight = $('.video-wrapper').height();
-                        progressSliderHeight = videoControl.sliderEl.height();
-                        controlHeight = videoControl.el.height();
+                        progressSliderHeight = state.el.find('.slider').height();
+                        controlHeight = state.el.find('.video-controls').height();
                         shouldBeHeight = videoWrapperHeight -
                             0.5 * progressSliderHeight -
                             controlHeight;
@@ -1043,7 +1058,6 @@
         describe('toggle', function () {
             beforeEach(function () {
                 state = jasmine.initializePlayer();
-                spyOn(state.videoPlayer, 'log');
                 $('.subtitles li[data-index=1]').addClass('current');
             });
 
@@ -1053,15 +1067,6 @@
                     state.videoCaption.toggle(jQuery.Event('click'));
                 });
 
-                it('log the hide_transcript event', function () {
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'hide_transcript',
-                        {
-                            currentTime: state.videoPlayer.currentTime
-                        }
-                    );
-                });
-
                 it('hide the caption', function () {
                     expect(state.el).toHaveClass('closed');
                 });
@@ -1079,15 +1084,6 @@
                     jasmine.Clock.useMock();
                 });
 
-                it('log the show_transcript event', function () {
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'show_transcript',
-                        {
-                            currentTime: state.videoPlayer.currentTime
-                        }
-                    );
-                });
-
                 it('show the caption', function () {
                     expect(state.el).not.toHaveClass('closed');
                 });
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js
index 269a75053c45325c8defd51fbdc17f043c131a6d..295b151a4fd0fda46cc4d09e00152bce3378ef94 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js
@@ -68,6 +68,7 @@
             $('source').remove();
             _.result(state.storage, 'clear');
             _.result($('video').data('contextmenu'), 'destroy');
+            _.result(state.videoPlayer, 'destroy');
         });
 
         describe('constructor', function () {
@@ -219,12 +220,13 @@
 
             it('mouse left/right-clicking behaves as expected on play/pause menu item', function () {
                 var menuItem = menuItems.first();
+                spyOn(state.videoPlayer, 'isPlaying');
                 spyOn(state.videoPlayer, 'play').andCallFake(function () {
-                    state.videoControl.isPlaying = true;
+                    state.videoPlayer.isPlaying.andReturn(true);
                     state.el.trigger('play');
                 });
                 spyOn(state.videoPlayer, 'pause').andCallFake(function () {
-                    state.videoControl.isPlaying = false;
+                    state.videoPlayer.isPlaying.andReturn(false);
                     state.el.trigger('pause');
                 });
                 // Left-click on play
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js
index 98569620c2298d7b4ba2e6f1cb47a3fd5c188621..85794dc2d5ecc7910cbda09d987a5620442dd889 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js
@@ -13,12 +13,13 @@
         afterEach(function () {
             $('source').remove();
             state.storage.clear();
-            window.Video.previousState = null;
+            state.videoPlayer.destroy();
             window.onTouchBasedDevice = oldOTBD;
         });
 
         describe('constructor', function () {
             beforeEach(function () {
+                window.VideoState = {};
                 state = jasmine.initializePlayer();
             });
 
@@ -28,83 +29,13 @@
                         '.slider',
                         'ul.vcr',
                         'a.play',
-                        '.vidtime',
-                        '.add-fullscreen'
+                        '.vidtime'
                     ].join(',')
                 );
 
                 expect($('.video-controls').find('.vidtime'))
                     .toHaveText('0:00 / 0:00');
             });
-
-            it('add ARIA attributes to time control', function () {
-                var timeControl = $('div.slider > a');
-
-                expect(timeControl).toHaveAttrs({
-                    'role': 'slider',
-                    'title': 'Video position',
-                    'aria-disabled': 'false'
-                });
-
-                expect(timeControl).toHaveAttr('aria-valuetext');
-            });
-
-            it('add ARIA attributes to play control', function () {
-                var playControl = $('ul.vcr a');
-
-                expect(playControl).toHaveAttrs({
-                    'role': 'button',
-                    'title': 'Play',
-                    'aria-disabled': 'false'
-                });
-            });
-
-            it('add ARIA attributes to fullscreen control', function () {
-                var fullScreenControl = $('a.add-fullscreen');
-
-                expect(fullScreenControl).toHaveAttrs({
-                    'role': 'button',
-                    'title': 'Fill browser',
-                    'aria-disabled': 'false'
-                });
-            });
-
-            it('bind the playback button', function () {
-                expect($('.video_control')).toHandleWith(
-                    'click',
-                    state.videoControl.togglePlayback
-                );
-            });
-
-            describe('when on a non-touch based device', function () {
-                beforeEach(function () {
-                    state = jasmine.initializePlayer();
-                });
-
-                it('add the play class to video control', function () {
-                    expect($('.video_control')).toHaveClass('play');
-                    expect($('.video_control')).toHaveAttr(
-                        'title', 'Play'
-                    );
-                });
-            });
-
-            describe('when on a touch based device', function () {
-                beforeEach(function () {
-                    window.onTouchBasedDevice.andReturn(['iPad']);
-                    state = jasmine.initializePlayer();
-                });
-
-                it(
-                    'does not add the play class to video control',
-                    function ()
-                {
-                    expect($('.video_control')).toHaveClass('play');
-                    expect($('.video_control')).toHaveAttr(
-                        'title', 'Play'
-                    );
-                });
-            });
         });
 
         describe('constructor with start-time', function () {
@@ -115,6 +46,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         savedVideoPosition: 0
@@ -147,6 +79,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         savedVideoPosition: 15
@@ -181,6 +114,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         savedVideoPosition: -15
@@ -215,6 +149,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         savedVideoPosition: 'a'
@@ -249,6 +184,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         savedVideoPosition: 10000
@@ -278,13 +214,14 @@
 
         describe('constructor with end-time', function () {
             it(
-                'saved position is 0, timer slider and VCR set to 0:00 ' + 
+                'saved position is 0, timer slider and VCR set to 0:00 ' +
                 'and ending at specified end-time',
                 function ()
             {
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         end: 20,
                         savedVideoPosition: 0
@@ -319,6 +256,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         end: 20,
                         savedVideoPosition: 15
@@ -353,6 +291,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         end: 20,
                         savedVideoPosition: -15
@@ -387,6 +326,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         end: 20,
                         savedVideoPosition: 'a'
@@ -422,6 +362,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         end: 20,
                         savedVideoPosition: 10000
@@ -457,6 +398,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         end: 20,
@@ -492,6 +434,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         end: 20,
@@ -527,6 +470,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         end: 20,
@@ -562,6 +506,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         end: 20,
@@ -597,6 +542,7 @@
                 var duration, sliderEl, expectedValue;
 
                 runs(function () {
+                    window.VideoState = {};
                     state = jasmine.initializePlayer({
                         start: 10,
                         end: 20,
@@ -625,217 +571,8 @@
             });
         });
 
-        it('Controls height is actual on switch to fullscreen', function () {
-            spyOn($.fn, 'height').andCallFake(function (val) {
-                return _.isUndefined(val) ? 100: this;
-            });
-
-            state = jasmine.initializePlayer();
-            $(state.el).trigger('fullscreen');
-
-            expect(state.videoControl.height).toBe(150);
-        });
-
-        describe('play', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-                state.videoControl.play();
-            });
-
-            it('switch playback button to play state', function () {
-                expect($('.video_control')).not.toHaveClass('play');
-                expect($('.video_control')).toHaveClass('pause');
-                expect($('.video_control')).toHaveAttr('title', 'Pause');
-            });
-        });
-
-        describe('pause', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-                state.videoControl.pause();
-            });
-
-            it('switch playback button to pause state', function () {
-                expect($('.video_control')).not.toHaveClass('pause');
-                expect($('.video_control')).toHaveClass('play');
-                expect($('.video_control')).toHaveAttr('title', 'Play');
-            });
-        });
-
-        describe('togglePlayback', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-            });
-
-            describe(
-                'when the control does not have play or pause class',
-                function ()
-            {
-                beforeEach(function () {
-                    $('.video_control').removeClass('play')
-                        .removeClass('pause');
-                });
-
-                describe('when the video is playing', function () {
-                    beforeEach(function () {
-                        $('.video_control').addClass('play');
-                        spyOnEvent(state.videoControl, 'pause');
-                        state.videoControl.togglePlayback(
-                            $.Event('click')
-                        );
-                    });
-
-                    it('does not trigger the pause event', function () {
-                        expect('pause').not
-                            .toHaveBeenTriggeredOn(state.videoControl);
-                    });
-                });
-
-                describe('when the video is paused', function () {
-                    beforeEach(function () {
-                        $('.video_control').addClass('pause');
-                        spyOnEvent(state.videoControl, 'play');
-                        state.videoControl.togglePlayback(
-                            $.Event('click')
-                        );
-                    });
-
-                    it('does not trigger the play event', function () {
-                        expect('play').not
-                            .toHaveBeenTriggeredOn(state.videoControl);
-                    });
-                });
-            });
-        });
-
-        describe('Play placeholder', function () {
-            var cases = [
-                {
-                    name: 'PC',
-                    isShown: false,
-                    isTouch: null
-                }, {
-                    name: 'iPad',
-                    isShown: true,
-                    isTouch: ['iPad']
-                }, {
-                    name: 'Android',
-                    isShown: true,
-                    isTouch: ['Android']
-                }, {
-                    name: 'iPhone',
-                    isShown: false,
-                    isTouch: ['iPhone']
-                }
-            ];
-
-            beforeEach(function () {
-                jasmine.stubRequests();
-
-                spyOn(window.YT, 'Player').andCallThrough();
-            });
-
-            it ('works correctly on calling proper methods', function () {
-                var btnPlay;
-
-                state = jasmine.initializePlayer();
-                btnPlay = state.el.find('.btn-play');
-
-                state.videoControl.showPlayPlaceholder();
-
-                expect(btnPlay).not.toHaveClass('is-hidden');
-                expect(btnPlay).toHaveAttrs({
-                    'aria-hidden': 'false',
-                    'tabindex': 0
-                });
-
-                state.videoControl.hidePlayPlaceholder();
-
-                expect(btnPlay).toHaveClass('is-hidden');
-                expect(btnPlay).toHaveAttrs({
-                    'aria-hidden': 'true',
-                    'tabindex': -1
-                });
-            });
-
-            $.each(cases, function (index, data) {
-                var message = [
-                    (data.isShown) ? 'is' : 'is not',
-                    ' shown on',
-                    data.name
-                ].join('');
-
-                it(message, function () {
-                    var btnPlay;
-
-                    window.onTouchBasedDevice.andReturn(data.isTouch);
-                    state = jasmine.initializePlayer();
-                    btnPlay = state.el.find('.btn-play');
-
-                    if (data.isShown) {
-                        expect(btnPlay).not.toHaveClass('is-hidden');
-                    } else {
-                        expect(btnPlay).toHaveClass('is-hidden');
-                    }
-                });
-            });
-
-            $.each(['iPad', 'Android'], function (index, device) {
-                it(
-                    'is shown on paused video on ' + device +
-                    ' in HTML5 player',
-                    function ()
-                {
-                    var btnPlay;
-
-                    window.onTouchBasedDevice.andReturn([device]);
-                    state = jasmine.initializePlayer();
-                    btnPlay = state.el.find('.btn-play');
-
-                    state.videoControl.play();
-                    state.videoControl.pause();
-
-                    expect(btnPlay).not.toHaveClass('is-hidden');
-                });
-
-                it(
-                    'is hidden on playing video on ' + device +
-                    ' in HTML5 player',
-                    function ()
-                {
-                    var btnPlay;
-
-                    window.onTouchBasedDevice.andReturn([device]);
-                    state = jasmine.initializePlayer();
-                    btnPlay = state.el.find('.btn-play');
-
-                    state.videoControl.play();
-
-                    expect(btnPlay).toHaveClass('is-hidden');
-                });
-
-                it(
-                    'is hidden on paused video on ' + device +
-                    ' in YouTube player',
-                    function ()
-                {
-                    var btnPlay;
-
-                    window.onTouchBasedDevice.andReturn([device]);
-                    state = jasmine.initializePlayerYouTube();
-                    btnPlay = state.el.find('.btn-play');
-
-                    state.videoControl.play();
-                    state.videoControl.pause();
-
-                    expect(btnPlay).toHaveClass('is-hidden');
-                });
-            });
-        });
-
         it('show', function () {
             var controls;
-
             state = jasmine.initializePlayer();
             controls = state.el.find('.video-controls');
             controls.addClass('is-hidden');
@@ -843,5 +580,23 @@
             state.videoControl.show();
             expect(controls).not.toHaveClass('is-hidden');
         });
+
+        it('can destroy itself', function () {
+            state = jasmine.initializePlayer();
+            state.videoControl.destroy();
+            expect(state.videoControl).toBeUndefined();
+        });
+
+        it('can focus the first control', function () {
+            var btnPlay;
+            state = jasmine.initializePlayer({focusFirstControl: true});
+            btnPlay = state.el.find('.video-controls .play');
+            waitsFor(function () {
+                return state.el.hasClass('is-initialized');
+            }, 'Player is not initialized', WAIT_TIMEOUT);
+            runs(function () {
+                expect(btnPlay).toBeFocused();
+            });
+        });
     });
 }).call(this, window.WAIT_TIMEOUT);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..e41b40e782e2664871e45642b4b8e27e5453187b
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js
@@ -0,0 +1,157 @@
+(function (undefined) {
+    'use strict';
+    describe('VideoPlayer Events Bumper plugin', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice')
+                .andReturn(null);
+
+            jasmine.stubRequests();
+            state = jasmine.initializePlayer('video_with_bumper.html');
+            spyOn(Logger, 'log');
+            $('.poster .btn-play').click();
+            spyOn(state.bumperState.videoEventsBumperPlugin, 'getCurrentTime').andReturn(10);
+            spyOn(state.bumperState.videoEventsBumperPlugin, 'getDuration').andReturn(20);
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            window.onTouchBasedDevice = oldOTBD;
+            state.storage.clear();
+            if (state.bumperState && state.bumperState.videoPlayer) {
+                state.bumperState.videoPlayer.destroy();
+            }
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+        });
+
+        it('can emit "edx.video.bumper.loaded" event', function () {
+            state.el.trigger('ready');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.loaded', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.played" event', function () {
+            state.el.trigger('play');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.played', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.stopped" event', function () {
+            state.el.trigger('ended');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.stopped', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+
+            Logger.log.reset();
+            state.el.trigger('stop');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.stopped', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.skipped" event', function () {
+            state.el.trigger('skip', [false]);
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.skipped', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.dismissed" event', function () {
+            state.el.trigger('skip', [true]);
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.dismissed', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.transcript.menu.shown" event', function () {
+            state.el.trigger('language_menu:show');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.shown', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.transcript.menu.hidden" event', function () {
+            state.el.trigger('language_menu:hide');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.hidden', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.transcript.shown" event', function () {
+            state.el.trigger('captions:show');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.shown', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can emit "edx.video.bumper.transcript.hidden" event', function () {
+            state.el.trigger('captions:hide');
+            expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.hidden', {
+                host_component_id: 'id',
+                bumper_id: 'xmodule/include/fixtures/test.mp4',
+                code: 'html5',
+                currentTime: 10,
+                duration: 20
+            });
+        });
+
+        it('can destroy itself', function () {
+            var plugin = state.bumperState.videoEventsBumperPlugin;
+            spyOn($.fn, 'off').andCallThrough();
+            plugin.destroy();
+            expect(state.bumperState.videoEventsBumperPlugin).toBeUndefined();
+            expect($.fn.off).toHaveBeenCalledWith({
+                'ready': plugin.onReady,
+                'play': plugin.onPlay,
+                'ended stop': plugin.onEnded,
+                'skip': plugin.onSkip,
+                'language_menu:show': plugin.onShowLanguageMenu,
+                'language_menu:hide': plugin.onHideLanguageMenu,
+                'captions:show': plugin.onShowCaptions,
+                'captions:hide': plugin.onHideCaptions,
+                'destroy': plugin.destroy
+            });
+        });
+    });
+
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..78352e575f1fae952d21470a9e9ac1aef9e39f05
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js
@@ -0,0 +1,166 @@
+(function (undefined) {
+    'use strict';
+    describe('VideoPlayer Events plugin', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice')
+                .andReturn(null);
+
+            jasmine.stubRequests();
+            state = jasmine.initializePlayer();
+            spyOn(Logger, 'log');
+            spyOn(state.videoEventsPlugin, 'getCurrentTime').andReturn(10);
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            window.onTouchBasedDevice = oldOTBD;
+            state.storage.clear();
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+        });
+
+        it('can emit "load_video" event', function () {
+            state.el.trigger('ready');
+            expect(Logger.log).toHaveBeenCalledWith('load_video', {
+                id: 'id',
+                code: 'html5'
+            });
+        });
+
+        it('can emit "play_video" event', function () {
+            state.el.trigger('play');
+            expect(Logger.log).toHaveBeenCalledWith('play_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+        });
+
+        it('can emit "pause_video" event', function () {
+            state.el.trigger('pause');
+            expect(Logger.log).toHaveBeenCalledWith('pause_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+        });
+
+        it('can emit "speed_change_video" event', function () {
+            state.el.trigger('speedchange', ['2.0', '1.0']);
+            expect(Logger.log).toHaveBeenCalledWith('speed_change_video', {
+                id: 'id',
+                code: 'html5',
+                current_time: 10,
+                old_speed: '1.0',
+                new_speed: '2.0'
+            });
+        });
+
+        it('can emit "seek_video" event', function () {
+            state.el.trigger('seek', [1, 0, 'any']);
+            expect(Logger.log).toHaveBeenCalledWith('seek_video', {
+                id: 'id',
+                code: 'html5',
+                old_time: 0,
+                new_time: 1,
+                type: 'any'
+            });
+        });
+
+        it('can emit "stop_video" event', function () {
+            state.el.trigger('ended');
+            expect(Logger.log).toHaveBeenCalledWith('stop_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+
+            Logger.log.reset();
+            state.el.trigger('stop');
+            expect(Logger.log).toHaveBeenCalledWith('stop_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+        });
+
+        it('can emit "skip_video" event', function () {
+            state.el.trigger('skip', [false]);
+            expect(Logger.log).toHaveBeenCalledWith('skip_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+        });
+
+        it('can emit "do_not_show_again_video" event', function () {
+            state.el.trigger('skip', [true]);
+            expect(Logger.log).toHaveBeenCalledWith('do_not_show_again_video', {
+                id: 'id',
+                code: 'html5',
+                currentTime: 10
+            });
+        });
+
+        it('can emit "video_show_cc_menu" event', function () {
+            state.el.trigger('language_menu:show');
+            expect(Logger.log).toHaveBeenCalledWith('video_show_cc_menu', {
+                id: 'id',
+                code: 'html5'
+            });
+        });
+
+        it('can emit "video_hide_cc_menu" event', function () {
+            state.el.trigger('language_menu:hide');
+            expect(Logger.log).toHaveBeenCalledWith('video_hide_cc_menu', {
+                id: 'id',
+                code: 'html5'
+            });
+        });
+
+        it('can emit "show_transcript" event', function () {
+            state.el.trigger('captions:show');
+            expect(Logger.log).toHaveBeenCalledWith('show_transcript', {
+                id: 'id',
+                code: 'html5',
+                current_time: 10
+            });
+        });
+
+        it('can emit "hide_transcript" event', function () {
+            state.el.trigger('captions:hide');
+            expect(Logger.log).toHaveBeenCalledWith('hide_transcript', {
+                id: 'id',
+                code: 'html5',
+                current_time: 10
+            });
+        });
+
+        it('can destroy itself', function () {
+            var plugin = state.videoEventsPlugin;
+            spyOn($.fn, 'off').andCallThrough();
+            state.videoEventsPlugin.destroy();
+            expect(state.videoEventsPlugin).toBeUndefined();
+            expect($.fn.off).toHaveBeenCalledWith({
+                'ready': plugin.onReady,
+                'play': plugin.onPlay,
+                'pause': plugin.onPause,
+                'ended stop': plugin.onEnded,
+                'seek': plugin.onSeek,
+                'skip': plugin.onSkip,
+                'speedchange': plugin.onSpeedChange,
+                'language_menu:show': plugin.onShowLanguageMenu,
+                'language_menu:hide': plugin.onHideLanguageMenu,
+                'captions:show': plugin.onShowCaptions,
+                'captions:hide': plugin.onHideCaptions,
+                'destroy': plugin.destroy
+            });
+        });
+    });
+
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js
index ab3c12df6f5aa87f38f45833ef323f8f1bd31717..5f69d2c7c782fb5f4b0673d8a58066b64317252f 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js
@@ -26,6 +26,7 @@
         afterEach(function () {
             // Turn jQuery animations back on.
             jQuery.fx.off = true;
+            state.videoPlayer.destroy();
         });
 
         it(
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..215b891f41ff56d9a823ced896975181e93841be
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js
@@ -0,0 +1,102 @@
+(function () {
+    'use strict';
+    describe('VideoFullScreen', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            state.videoPlayer.destroy();
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        describe('constructor', function () {
+            beforeEach(function () {
+                state = jasmine.initializePlayer();
+            });
+
+            it('renders the fullscreen control', function () {
+                expect($('.add-fullscreen')).toExist();
+                expect(state.videoFullScreen.fullScreenState).toBe(false);
+            });
+
+            it('correctly adds ARIA attributes to fullscreen control', function () {
+                var fullScreenControl = $('.add-fullscreen');
+
+                expect(fullScreenControl).toHaveAttrs({
+                    'role': 'button',
+                    'title': 'Fill browser',
+                    'aria-disabled': 'false'
+                });
+            });
+
+            it('correctly triggers the event handler to toggle fullscreen mode', function () {
+                spyOn(state.videoFullScreen, 'exit');
+                spyOn(state.videoFullScreen, 'enter');
+
+                state.videoFullScreen.fullScreenState = false;
+                state.videoFullScreen.toggle();
+                expect(state.videoFullScreen.enter).toHaveBeenCalled();
+
+                state.videoFullScreen.fullScreenState = true;
+                state.videoFullScreen.toggle();
+                expect(state.videoFullScreen.exit).toHaveBeenCalled();
+            });
+
+            it('correctly updates ARIA on state change', function () {
+                var fullScreenControl = $('.add-fullscreen');
+                fullScreenControl.click();
+                expect(fullScreenControl).toHaveAttrs({
+                    'role': 'button',
+                    'title': 'Exit full browser',
+                    'aria-disabled': 'false'
+                });
+                fullScreenControl.click();
+                expect(fullScreenControl).toHaveAttrs({
+                    'role': 'button',
+                    'title': 'Fill browser',
+                    'aria-disabled': 'false'
+                });
+            });
+
+            it('correctly can out of fullscreen by pressing esc', function () {
+                spyOn(state.videoCommands, 'execute');
+                var esc = $.Event('keyup');
+                esc.keyCode = 27;
+                state.isFullScreen = true;
+                $(document).trigger(esc);
+                expect(state.videoCommands.execute).toHaveBeenCalledWith('toggleFullScreen');
+            });
+
+            it('can update video dimensions on state change', function () {
+                state.el.trigger('fullscreen', [true]);
+                expect(state.resizer.setMode).toHaveBeenCalledWith('both');
+                state.el.trigger('fullscreen', [false]);
+                expect(state.resizer.setMode).toHaveBeenCalledWith('width');
+            });
+
+            it('can destroy itself', function () {
+                state.videoFullScreen.destroy();
+                expect($('.add-fullscreen')).not.toExist();
+                expect(state.videoFullScreen).toBeUndefined();
+            });
+        });
+
+        it('Controls height is actual on switch to fullscreen', function () {
+            spyOn($.fn, 'height').andCallFake(function (val) {
+                return _.isUndefined(val) ? 100: this;
+            });
+
+            state = jasmine.initializePlayer();
+            $(state.el).trigger('fullscreen');
+
+            expect(state.videoFullScreen.height).toBe(150);
+        });
+    });
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..877dc9861e249e3ba3d262578574e8d49bd72061
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js
@@ -0,0 +1,68 @@
+(function () {
+    'use strict';
+    describe('VideoPlayPauseControl', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+            state = jasmine.initializePlayer();
+            spyOn(state.videoCommands, 'execute');
+            spyOn(state.videoSaveStatePlugin, 'saveState');
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            state.videoPlayer.destroy();
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        it('can render the control', function () {
+            expect($('.video_control.play')).toExist();
+        });
+
+        it('add ARIA attributes to play control', function () {
+            expect($('.video_control.play')).toHaveAttrs({
+                'role': 'button',
+                'title': 'Play',
+                'aria-disabled': 'false'
+            });
+        });
+
+        it('can update ARIA state on play', function () {
+            state.el.trigger('play');
+            expect($('.video_control.pause')).toHaveAttrs({
+                'role': 'button',
+                'title': 'Pause',
+                'aria-disabled': 'false'
+            });
+        });
+
+        it('can update ARIA state on video ends', function () {
+            state.el.trigger('play');
+            state.el.trigger('ended');
+            expect($('.video_control.play')).toHaveAttrs({
+                'role': 'button',
+                'title': 'Play',
+                'aria-disabled': 'false'
+            });
+        });
+
+        it('can update state on pause', function () {
+            state.el.trigger('pause');
+            expect(state.videoSaveStatePlugin.saveState).toHaveBeenCalledWith(true);
+        });
+
+        it('can start video playing on click', function () {
+            $('.video_control.play').click();
+            expect(state.videoCommands.execute).toHaveBeenCalledWith('togglePlayback');
+        });
+
+        it('can destroy itself', function () {
+            state.videoPlayPauseControl.destroy();
+            expect(state.videoPlayPauseControl).toBeUndefined();
+        });
+    });
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..d99c12e24ccfb3d824555713f317ad6583d504b1
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js
@@ -0,0 +1,151 @@
+(function () {
+    'use strict';
+    describe('VideoPlayPlaceholder', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(['iPad']);
+
+            state = jasmine.initializePlayer();
+            spyOn(state.videoCommands, 'execute');
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            state.videoPlayer.destroy();
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        var cases = [
+            {
+                name: 'PC',
+                isShown: false,
+                isTouch: null
+            }, {
+                name: 'iPad',
+                isShown: true,
+                isTouch: ['iPad']
+            }, {
+                name: 'Android',
+                isShown: true,
+                isTouch: ['Android']
+            }, {
+                name: 'iPhone',
+                isShown: false,
+                isTouch: ['iPhone']
+            }
+        ];
+
+        beforeEach(function () {
+            jasmine.stubRequests();
+            spyOn(window.YT, 'Player').andCallThrough();
+        });
+
+        it ('works correctly on calling proper methods', function () {
+            var btnPlay;
+
+            state = jasmine.initializePlayer();
+            btnPlay = state.el.find('.btn-play');
+
+            state.videoPlayPlaceholder.show();
+
+            expect(btnPlay).not.toHaveClass('is-hidden');
+            expect(btnPlay).toHaveAttrs({
+                'aria-hidden': 'false',
+                'tabindex': 0
+            });
+
+            state.videoPlayPlaceholder.hide();
+
+            expect(btnPlay).toHaveClass('is-hidden');
+            expect(btnPlay).toHaveAttrs({
+                'aria-hidden': 'true',
+                'tabindex': -1
+            });
+        });
+
+        $.each(cases, function (index, data) {
+            var message = [
+                (data.isShown) ? 'is' : 'is not',
+                ' shown on',
+                data.name
+            ].join('');
+
+            it(message, function () {
+                var btnPlay;
+
+                window.onTouchBasedDevice.andReturn(data.isTouch);
+                state = jasmine.initializePlayer();
+                btnPlay = state.el.find('.btn-play');
+
+                if (data.isShown) {
+                    expect(btnPlay).not.toHaveClass('is-hidden');
+                } else {
+                    expect(btnPlay).toHaveClass('is-hidden');
+                }
+            });
+        });
+
+        $.each(['iPad', 'Android'], function (index, device) {
+            it(
+                'is shown on paused video on ' + device +
+                ' in HTML5 player',
+                function ()
+            {
+                var btnPlay;
+
+                window.onTouchBasedDevice.andReturn([device]);
+                state = jasmine.initializePlayer();
+                btnPlay = state.el.find('.btn-play');
+
+                state.el.trigger('play');
+                state.el.trigger('pause');
+                expect(btnPlay).not.toHaveClass('is-hidden');
+            });
+
+            it(
+                'is hidden on playing video on ' + device +
+                ' in HTML5 player',
+                function ()
+            {
+                var btnPlay;
+
+                window.onTouchBasedDevice.andReturn([device]);
+                state = jasmine.initializePlayer();
+                btnPlay = state.el.find('.btn-play');
+
+                state.el.trigger('play');
+                expect(btnPlay).toHaveClass('is-hidden');
+            });
+
+            it(
+                'is hidden on paused video on ' + device +
+                ' in YouTube player',
+                function ()
+            {
+                var btnPlay;
+
+                window.onTouchBasedDevice.andReturn([device]);
+                state = jasmine.initializePlayerYouTube();
+                btnPlay = state.el.find('.btn-play');
+
+                state.el.trigger('play');
+                state.el.trigger('pause');
+                expect(btnPlay).toHaveClass('is-hidden');
+            });
+        });
+
+        it('starts play the video on click', function () {
+            $('.btn-play').click();
+            expect(state.videoCommands.execute).toHaveBeenCalledWith('play');
+        });
+
+        it('can destroy itself', function () {
+            state.videoPlayPlaceholder.destroy();
+            expect(state.videoPlayPlaceholder).toBeUndefined();
+        });
+    });
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ccea6a0ab9b6d55cd2b431b79357197e6ead9a4
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js
@@ -0,0 +1,64 @@
+(function () {
+    'use strict';
+    describe('VideoPlaySkipControl', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+            state = jasmine.initializePlayer('video_with_bumper.html');
+            $('.poster .btn-play').click();
+            spyOn(state.bumperState.videoCommands, 'execute');
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            if (state.bumperState && state.bumperState.videoPlayer) {
+                state.bumperState.videoPlayer.destroy();
+            }
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        it('can render the control', function () {
+            expect($('.video_control.play')).toExist();
+        });
+
+        it('add ARIA attributes to play control', function () {
+            expect($('.video_control.play')).toHaveAttrs({
+                'role': 'button',
+                'title': 'Play',
+                'aria-disabled': 'false'
+            });
+        });
+
+        it('can update state on play', function () {
+            state.el.trigger('play');
+            expect($('.video_control.play')).not.toExist();
+            expect($('.video_control.skip')).toExist();
+        });
+
+        it('can start video playing on click', function () {
+            $('.video_control.play').click();
+            expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('play');
+        });
+
+        it('can skip the video on click', function () {
+            state.el.trigger('play');
+            spyOn(state.bumperState.videoPlayer, 'isPlaying').andReturn(true);
+            $('.video_control.skip').first().click();
+            expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('skip');
+        });
+
+        it('can destroy itself', function () {
+            var plugin = state.bumperState.videoPlaySkipControl,
+                el = plugin.el;
+            spyOn($.fn, 'off').andCallThrough();
+            plugin.destroy();
+            expect(state.bumperState.videoPlaySkipControl).toBeUndefined();
+            expect(el).not.toExist();
+            expect($.fn.off).toHaveBeenCalledWith('destroy', plugin.destroy);
+        });
+    });
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
index da910d7bb0fba2e84524a36d5540d725ebe7db1c..fc74ef9229336e39e04a1de22ccb73b40670c702 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
@@ -1,5 +1,4 @@
 (function (requirejs, require, define, undefined) {
-
 'use strict';
 
 require(
@@ -21,6 +20,9 @@ function (VideoPlayer) {
             if (state.storage) {
                 state.storage.clear();
             }
+            if (state.videoPlayer) {
+                _.result(state.videoPlayer, 'destroy');
+            }
         });
 
         describe('constructor', function () {
@@ -47,7 +49,7 @@ function (VideoPlayer) {
                     expect(state.videoCaption).toBeDefined();
                     expect(state.speed).toEqual('1.50');
                     expect(state.config.transcriptTranslationUrl)
-                        .toEqual('/transcript/translation');
+                        .toEqual('/transcript/translation/__lang__');
                 });
 
                 it('create video speed control', function () {
@@ -71,18 +73,15 @@ function (VideoPlayer) {
                 var events;
 
                 jasmine.stubRequests();
-
                 spyOn(window.YT, 'Player').andCallThrough();
-
                 state = jasmine.initializePlayerYouTube();
-
                 state.videoEl = $('video, iframe');
 
                 events = {
                     onReady:                 state.videoPlayer.onReady,
                     onStateChange:           state.videoPlayer.onStateChange,
-                    onPlaybackQualityChange: state.videoPlayer
-                        .onPlaybackQualityChange
+                    onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange,
+                    onError:                 state.videoPlayer.onError
                 };
 
                 expect(YT.Player).toHaveBeenCalledWith('id', {
@@ -156,7 +155,7 @@ function (VideoPlayer) {
                 });
 
                 it('controls are in paused state', function () {
-                    expect(state.videoControl.isPlaying).toBe(false);
+                    expect(state.videoPlayer.isPlaying()).toBe(false);
                 });
             });
         });
@@ -166,16 +165,10 @@ function (VideoPlayer) {
                 state = jasmine.initializePlayer();
 
                 state.videoEl = $('video, iframe');
-
-                spyOn(state.videoPlayer, 'log').andCallThrough();
                 spyOn(state.videoPlayer, 'play').andCallThrough();
                 state.videoPlayer.onReady();
             });
 
-            it('log the load_video event', function () {
-                expect(state.videoPlayer.log).toHaveBeenCalledWith('load_video');
-            });
-
             it('autoplay the first video', function () {
                 expect(state.videoPlayer.play).not.toHaveBeenCalled();
             });
@@ -197,9 +190,7 @@ function (VideoPlayer) {
                 var playbackRates = state.videoPlayer.player.getAvailablePlaybackRates();
 
                 state.currentPlayerMode = 'flash';
-
                 state.videoPlayer.onReady();
-
                 expect(playbackRates.length).toBe(4);
                 expect(state.currentPlayerMode).toBe('html5');
             });
@@ -209,10 +200,7 @@ function (VideoPlayer) {
             describe('when the video is unstarted', function () {
                 beforeEach(function () {
                     state = jasmine.initializePlayer();
-
                     state.videoEl = $('video, iframe');
-
-                    spyOn(state.videoControl, 'pause').andCallThrough();
                     spyOn($.fn, 'trigger').andCallThrough();
 
                     state.videoPlayer.onStateChange({
@@ -221,7 +209,7 @@ function (VideoPlayer) {
                 });
 
                 it('pause the video control', function () {
-                    expect(state.videoControl.pause).toHaveBeenCalled();
+                    expect($('.video_control')).toHaveClass('play');
                 });
 
                 it('pause the video caption', function () {
@@ -244,9 +232,7 @@ function (VideoPlayer) {
 
                     state.videoEl = $('video, iframe');
 
-                    spyOn(state.videoPlayer, 'log').andCallThrough();
                     spyOn(window, 'setInterval').andReturn(100);
-                    spyOn(state.videoControl, 'play');
                     spyOn($.fn, 'trigger').andCallThrough();
 
                     state.videoPlayer.onStateChange({
@@ -254,23 +240,6 @@ function (VideoPlayer) {
                     });
                 });
 
-                it('speed_change_video event is not logged when speed not change', function () {
-                    expect(state.videoPlayer.log).not.toHaveBeenCalledWith(
-                        'speed_change_video',
-                        {
-                            current_time: state.videoPlayer.currentTime,
-                            old_speed: state.speed,
-                            new_speed: state.speed
-                        }
-                    );
-                });
-
-                it('log the play_video event', function () {
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'play_video', { currentTime: 0 }
-                    );
-                });
-
                 it('set update interval', function () {
                     expect(window.setInterval).toHaveBeenCalledWith(
                         state.videoPlayer.update, 200
@@ -279,7 +248,7 @@ function (VideoPlayer) {
                 });
 
                 it('play the video control', function () {
-                    expect(state.videoControl.play).toHaveBeenCalled();
+                    expect($('.video_control')).toHaveClass('pause');
                 });
 
                 it('play the video caption', function () {
@@ -295,10 +264,7 @@ function (VideoPlayer) {
 
                     state.videoEl = $('video, iframe');
 
-                    spyOn(state.videoPlayer, 'log').andCallThrough();
-                    spyOn(state.videoControl, 'pause').andCallThrough();
                     spyOn($.fn, 'trigger').andCallThrough();
-
                     state.videoPlayer.onStateChange({
                         data: YT.PlayerState.PLAYING
                     });
@@ -310,18 +276,12 @@ function (VideoPlayer) {
                     });
                 });
 
-                it('log the pause_video event', function () {
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'pause_video', { currentTime: 0 }
-                    );
-                });
-
                 it('clear update interval', function () {
                     expect(state.videoPlayer.updateInterval).toBeUndefined();
                 });
 
                 it('pause the video control', function () {
-                    expect(state.videoControl.pause).toHaveBeenCalled();
+                    expect($('.video_control')).toHaveClass('play');
                 });
 
                 it('pause the video caption', function () {
@@ -334,32 +294,19 @@ function (VideoPlayer) {
                     state = jasmine.initializePlayer();
 
                     state.videoEl = $('video, iframe');
-
-                    spyOn(state.videoPlayer, 'log').andCallThrough();
-                    spyOn(state.videoControl, 'pause').andCallThrough();
                     spyOn($.fn, 'trigger').andCallThrough();
-
                     state.videoPlayer.onStateChange({
                         data: YT.PlayerState.ENDED
                     });
                 });
 
                 it('pause the video control', function () {
-                    expect(state.videoControl.pause).toHaveBeenCalled();
+                    expect($('.video_control')).toHaveClass('play');
                 });
 
                 it('pause the video caption', function () {
                     expect($.fn.trigger).toHaveBeenCalledWith('ended', {});
                 });
-
-                it('log stop_video event', function () {
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'stop_video',
-                        {
-                            currentTime: state.videoPlayer.currentTime
-                        }
-                    );
-                });
             });
         });
 
@@ -397,25 +344,6 @@ function (VideoPlayer) {
                     });
                 });
 
-                it('slider event causes log update', function () {
-                    runs(function () {
-                        spyOn(state.videoPlayer, 'log');
-                        state.videoProgressSlider.onSlide(
-                            jQuery.Event('slide'), { value: 2 }
-                        );
-                        // Video player uses _.debounce (with a wait time in 300 ms) for seeking.
-                        // That's why we have to do this tick(300).
-                        jasmine.Clock.tick(300);
-                        expect(state.videoPlayer.currentTime).toBe(2);
-
-                        expect(state.videoPlayer.log).toHaveBeenCalledWith('seek_video', {
-                            old_time: jasmine.any(Number),
-                            new_time: 2,
-                            type: 'onSlideSeek'
-                        });
-                    });
-                });
-
                 it('seek the player', function () {
                     runs(function () {
                         spyOn(state.videoPlayer.player, 'seekTo').andCallThrough();
@@ -469,24 +397,6 @@ function (VideoPlayer) {
                         .andCallThrough();
                 });
 
-                it('slider event causes log update', function () {
-                    spyOn(state.videoPlayer, 'log');
-                    state.videoProgressSlider.onSlide(
-                        jQuery.Event('slide'), { value: 2 }
-                    );
-                    // Video player uses _.debounce (with a wait time in 300 ms) for seeking.
-                    // That's why we have to do this tick(300).
-                    jasmine.Clock.tick(300);
-                    expect(state.videoPlayer.currentTime).toBe(2);
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'seek_video', {
-                            old_time: 0,
-                            new_time: 2,
-                            type: 'onSlideSeek'
-                        }
-                    );
-                });
-
                 it('video has a correct speed', function () {
                     state.speed = '2.0';
                     state.videoPlayer.onPlay();
@@ -785,7 +695,7 @@ function (VideoPlayer) {
                     state = jasmine.initializePlayer();
                     state.videoEl = $('video, iframe');
                     spyOn($.fn, 'trigger').andCallThrough();
-                    state.videoControl.toggleFullScreen(jQuery.Event('click'));
+                    $('.add-fullscreen').click();
                 });
 
                 it('replace the full screen button tooltip', function () {
@@ -810,11 +720,10 @@ function (VideoPlayer) {
                     state.videoEl = $('video, iframe');
                     spyOn($.fn, 'trigger').andCallThrough();
                     state.el.addClass('video-fullscreen');
-                    state.videoControl.fullScreenState = true;
-                    state.videoControl.isFullScreen = true;
-                    state.videoControl.fullScreenEl.attr('title', 'Exit-fullscreen');
-
-                    state.videoControl.toggleFullScreen(jQuery.Event('click'));
+                    state.videoFullScreen.fullScreenState = true;
+                    state.videoFullScreen.isFullScreen = true;
+                    state.videoFullScreen.fullScreenEl.attr('title', 'Exit-fullscreen');
+                    $('.add-fullscreen').click();
                 });
 
                 it('replace the full screen button tooltip', function () {
@@ -835,83 +744,6 @@ function (VideoPlayer) {
             });
         });
 
-        describe('play', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-
-                state.videoEl = $('video, iframe');
-
-                spyOn(state.videoPlayer.player, 'playVideo').andCallThrough();
-            });
-
-            describe('when the player is not ready', function () {
-                beforeEach(function () {
-                    state.videoPlayer.player.playVideo = void 0;
-                    state.videoPlayer.play();
-                });
-
-                it('does nothing', function () {
-                    expect(state.videoPlayer.player.playVideo).toBeUndefined();
-                });
-            });
-
-            describe('when the player is ready', function () {
-                beforeEach(function () {
-                    state.videoPlayer.player.playVideo.andReturn(true);
-                    state.videoPlayer.play();
-                });
-
-                it('delegate to the player', function () {
-                    expect(state.videoPlayer.player.playVideo).toHaveBeenCalled();
-                });
-            });
-        });
-
-        describe('isPlaying', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-
-                state.videoEl = $('video, iframe');
-
-                spyOn(state.videoPlayer.player, 'getPlayerState').andCallThrough();
-            });
-
-            describe('when the video is playing', function () {
-                beforeEach(function () {
-                    state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PLAYING);
-                });
-
-                it('return true', function () {
-                    expect(state.videoPlayer.isPlaying()).toBeTruthy();
-                });
-            });
-
-            describe('when the video is not playing', function () {
-                beforeEach(function () {
-                    state.videoPlayer.player.getPlayerState.andReturn(YT.PlayerState.PAUSED);
-                });
-
-                it('return false', function () {
-                    expect(state.videoPlayer.isPlaying()).toBeFalsy();
-                });
-            });
-        });
-
-        describe('pause', function () {
-            beforeEach(function () {
-                state = jasmine.initializePlayer();
-
-                state.videoEl = $('video, iframe');
-
-                spyOn(state.videoPlayer.player, 'pauseVideo').andCallThrough();
-                state.videoPlayer.pause();
-            });
-
-            it('delegate to the player', function () {
-                expect(state.videoPlayer.player.pauseVideo).toHaveBeenCalled();
-            });
-        });
-
         describe('duration', function () {
             beforeEach(function () {
                 state = jasmine.initializePlayer();
@@ -1016,9 +848,7 @@ function (VideoPlayer) {
 
                     runs(function () {
                         state = jasmine.initializePlayer();
-
                         state.videoEl = $('video, iframe');
-
                         controls = state.el.find('.video-controls');
                     });
 
@@ -1053,7 +883,6 @@ function (VideoPlayer) {
                     saveState: jasmine.createSpy(),
                     videoPlayer: {
                         currentTime: 60,
-                        log: jasmine.createSpy(),
                         updatePlayTime: jasmine.createSpy(),
                         setPlaybackRate: jasmine.createSpy(),
                         player: jasmine.createSpyObj('player', ['setPlaybackRate'])
@@ -1063,18 +892,6 @@ function (VideoPlayer) {
             });
 
             describe('always', function () {
-                it('check if speed_change_video is logged', function () {
-                    VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false);
-                    expect(state.videoPlayer.log).toHaveBeenCalledWith(
-                        'speed_change_video',
-                        {
-                            current_time: state.videoPlayer.currentTime,
-                            old_speed: '1.50',
-                            new_speed: '0.75'
-                        }
-                    );
-                });
-
                 it('convert the current time to the new speed', function () {
                     state.isFlashMode.andReturn(true);
                     VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false);
@@ -1083,10 +900,7 @@ function (VideoPlayer) {
 
                 it('set video speed to the new speed', function () {
                     VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false);
-                    expect(state.setSpeed).toHaveBeenCalledWith('0.75', true);
-                    expect(state.saveState).toHaveBeenCalledWith(true, {
-                        speed: '0.75'
-                    });
+                    expect(state.setSpeed).toHaveBeenCalledWith('0.75');
                     expect(state.videoPlayer.setPlaybackRate)
                         .toHaveBeenCalledWith('0.75');
                 });
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..18a6f6874c8bfd80fb473ce855ead409381dcc45
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js
@@ -0,0 +1,42 @@
+(function (WAIT_TIMEOUT) {
+    'use strict';
+    describe('VideoPoster', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+            state = jasmine.initializePlayer('video_with_bumper.html');
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            if (state.bumperState && state.bumperState.videoPlayer) {
+                state.bumperState.videoPlayer.destroy();
+            }
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        it('can render the poster', function () {
+            expect($('.poster')).toExist();
+            expect($('.btn-play')).toExist();
+        });
+
+        it('can start playing the video on click', function () {
+            $('.btn-play').click();
+            waitsFor(function () {
+                return state.el.hasClass('is-playing');
+            }, 'Player is not playing.', WAIT_TIMEOUT);
+        });
+
+        it('destroy itself on "play" event', function () {
+            $('.btn-play').click();
+            expect($('.poster')).not.toExist();
+        });
+    });
+}).call(this, window.WAIT_TIMEOUT);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
index d7a56857190a1921b43658b65d592c689ef71b3b..491e98fae72940e6f3c9cb44a7505855ebf3b198 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js
@@ -12,6 +12,7 @@
             $('source').remove();
             window.onTouchBasedDevice = oldOTBD;
             state.storage.clear();
+            state.videoPlayer.destroy();
         });
 
         describe('constructor', function () {
@@ -38,6 +39,18 @@
                     expect(state.videoProgressSlider.handle)
                         .toBe('.slider .ui-slider-handle');
                 });
+
+                it('add ARIA attributes to time control', function () {
+                    var timeControl = $('div.slider > a');
+
+                    expect(timeControl).toHaveAttrs({
+                        'role': 'slider',
+                        'title': 'Video position',
+                        'aria-disabled': 'false'
+                    });
+
+                    expect(timeControl).toHaveAttr('aria-valuetext');
+                });
             });
 
             describe('on a touch-based device', function () {
@@ -304,6 +317,13 @@
             });
         });
 
+        it('can destroy itself', function () {
+            state = jasmine.initializePlayer();
+            state.videoProgressSlider.destroy();
+            expect(state.videoProgressSlider).toBeUndefined();
+            expect($('.slider')).toBeEmpty();
+        });
+
     });
 
 }).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js
index 1ade3cb9cedd00e6ca4a520ddca0a5112d855f3a..0bf3722a4c4cbeb3df367a845851e1ab871652ae 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js
@@ -1,12 +1,13 @@
 (function (undefined) {
     describe('VideoQualityControl', function () {
-        var state, qualityControl, qualityControlEl, videoPlayer, player;
+        var state, qualityControl, videoPlayer, player;
 
         afterEach(function () {
             $('source').remove();
             if (state.storage) {
                 state.storage.clear();
             }
+            state.videoPlayer.destroy();
         });
 
         describe('constructor, YouTube mode', function () {
@@ -105,6 +106,11 @@
                  expect(qualityControl.el).toHaveClass('active');
             });
 
+            it('can destroy itself', function () {
+                state.videoQualityControl.destroy();
+                expect(state.videoQualityControl).toBeUndefined();
+                expect($('.quality-control')).not.toExist();
+            });
         });
 
         describe('constructor, HTML5 mode', function () {
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c101cdb3242b35095d83ed1ab9f170f0b66d5bc
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js
@@ -0,0 +1,230 @@
+(function (undefined) {
+    'use strict';
+    describe('VideoPlayer Save State plugin', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice')
+                .andReturn(null);
+
+            jasmine.stubRequests();
+            state = jasmine.initializePlayer();
+            spyOn(state.storage, 'setItem');
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            window.onTouchBasedDevice = oldOTBD;
+            state.storage.clear();
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+        });
+
+        describe('saveState function', function () {
+            var videoPlayerCurrentTime, newCurrentTime, speed;
+
+            // We make sure that `currentTime` is a float. We need to test
+            // that Math.round() is called.
+            videoPlayerCurrentTime = 3.1242;
+
+            // We have two times, because one is  stored in
+            // `videoPlayer.currentTime`, and the other is passed directly to
+            // `saveState` in `data` object. In each case, there is different
+            // code that handles these times. They have to be different for
+            // test completeness sake. Also, make sure it is float, as is the
+            // time above.
+            newCurrentTime = 5.4;
+            speed = '0.75';
+
+            beforeEach(function () {
+                state.videoPlayer.currentTime = videoPlayerCurrentTime;
+                spyOn(Time, 'formatFull').andCallThrough();
+            });
+
+            it('data is not an object, async is true', function () {
+                itSpec({
+                    asyncVal: true,
+                    speedVal: undefined,
+                    positionVal: videoPlayerCurrentTime,
+                    data: undefined,
+                    ajaxData: {
+                        saved_video_position: Time.formatFull(Math.round(videoPlayerCurrentTime))
+                    }
+                });
+            });
+
+            it('data contains speed, async is false', function () {
+                itSpec({
+                    asyncVal: false,
+                    speedVal: speed,
+                    positionVal: undefined,
+                    data: {
+                        speed: speed
+                    },
+                    ajaxData: {
+                        speed: speed
+                    }
+                });
+            });
+
+            it('data contains float position, async is true', function () {
+                itSpec({
+                    asyncVal: true,
+                    speedVal: undefined,
+                    positionVal: newCurrentTime,
+                    data: {
+                        saved_video_position: newCurrentTime
+                    },
+                    ajaxData: {
+                        saved_video_position: Time.formatFull(Math.round(newCurrentTime))
+                    }
+                });
+            });
+
+            it('data contains speed and rounded position, async is false', function () {
+                itSpec({
+                    asyncVal: false,
+                    speedVal: speed,
+                    positionVal: Math.round(newCurrentTime),
+                    data: {
+                        speed: speed,
+                        saved_video_position: Math.round(newCurrentTime)
+                    },
+                    ajaxData: {
+                        speed: speed,
+                        saved_video_position: Time.formatFull(Math.round(newCurrentTime))
+                    }
+                });
+            });
+
+            it('data contains empty object, async is true', function () {
+                itSpec({
+                    asyncVal: true,
+                    speedVal: undefined,
+                    positionVal: undefined,
+                    data: {},
+                    ajaxData: {}
+                });
+            });
+
+            it('data contains position 0, async is true', function () {
+                itSpec({
+                    asyncVal: true,
+                    speedVal: undefined,
+                    positionVal: 0,
+                    data: {
+                        saved_video_position: 0
+                    },
+                    ajaxData: {
+                        saved_video_position: Time.formatFull(Math.round(0))
+                    }
+                });
+            });
+
+            function itSpec(value) {
+                var asyncVal    = value.asyncVal,
+                    speedVal    = value.speedVal,
+                    positionVal = value.positionVal,
+                    data        = value.data,
+                    ajaxData    = value.ajaxData;
+
+                state.videoSaveStatePlugin.saveState(asyncVal, data);
+
+                if (speedVal) {
+                    expect(state.storage.setItem).toHaveBeenCalledWith(
+                        'speed',
+                        speedVal,
+                        true
+                    );
+                }
+                if (positionVal) {
+                    expect(state.storage.setItem).toHaveBeenCalledWith(
+                        'savedVideoPosition',
+                        positionVal,
+                        true
+                    );
+                    expect(Time.formatFull).toHaveBeenCalledWith(
+                        positionVal
+                    );
+                }
+                expect($.ajax).toHaveBeenCalledWith({
+                    url: state.config.saveStateUrl,
+                    type: 'POST',
+                    async: asyncVal,
+                    dataType: 'json',
+                    data: ajaxData
+                });
+            }
+        });
+
+        it('can save state on speed change', function () {
+            state.el.trigger('speedchange', ['2.0']);
+            expect($.ajax).toHaveBeenCalledWith({
+                url: state.config.saveStateUrl,
+                type: 'POST',
+                async: true,
+                dataType: 'json',
+                data: {speed: '2.0'}
+            });
+        });
+
+        it('can save state on page unload', function () {
+            $.ajax.reset();
+            state.videoSaveStatePlugin.onUnload();
+            expect($.ajax).toHaveBeenCalledWith({
+                url: state.config.saveStateUrl,
+                type: 'POST',
+                async: false,
+                dataType: 'json',
+                data: {saved_video_position: '00:00:00'}
+            });
+        });
+
+        it('can save state on pause', function () {
+            state.el.trigger('pause');
+            expect($.ajax).toHaveBeenCalledWith({
+                url: state.config.saveStateUrl,
+                type: 'POST',
+                async: true,
+                dataType: 'json',
+                data: {saved_video_position: '00:00:00'}
+            });
+        });
+
+        it('can save state on language change', function () {
+            state.el.trigger('language_menu:change', ['ua']);
+            expect(state.storage.setItem).toHaveBeenCalledWith('language', 'ua');
+        });
+
+        it('can save information about youtube availability', function () {
+            state.el.trigger('youtube_availability', [true]);
+            expect($.ajax).toHaveBeenCalledWith({
+                url: state.config.saveStateUrl,
+                type: 'POST',
+                async: true,
+                dataType: 'json',
+                data: {youtube_is_available: true}
+            });
+        });
+
+        it('can destroy itself', function () {
+            var plugin = state.videoSaveStatePlugin;
+            spyOn($.fn, 'off').andCallThrough();
+            state.videoSaveStatePlugin.destroy();
+            expect(state.videoSaveStatePlugin).toBeUndefined();
+            expect($.fn.off).toHaveBeenCalledWith({
+                'speedchange': plugin.onSpeedChange,
+                'play': plugin.bindUnloadHandler,
+                'pause destroy': plugin.saveStateHandler,
+                'language_menu:change': plugin.onLanguageChange,
+                'youtube_availability': plugin.onYoutubeAvailability
+            });
+            expect($.fn.off).toHaveBeenCalledWith('destroy', plugin.destroy);
+            expect($.fn.off).toHaveBeenCalledWith('unload', plugin.onUnload);
+        });
+    });
+
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..da3a87845b0c94aeab7c68d4bf398dd85cd1b215
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js
@@ -0,0 +1,55 @@
+(function () {
+    'use strict';
+    describe('VideoSkipControl', function () {
+        var state, oldOTBD;
+
+        beforeEach(function () {
+            oldOTBD = window.onTouchBasedDevice;
+            window.onTouchBasedDevice = jasmine
+                .createSpy('onTouchBasedDevice').andReturn(null);
+            state = jasmine.initializePlayer('video_with_bumper.html');
+            $('.poster .btn-play').click();
+            spyOn(state.bumperState.videoCommands, 'execute').andCallThrough();
+        });
+
+        afterEach(function () {
+            $('source').remove();
+            state.storage.clear();
+            if (state.bumperState && state.bumperState.videoPlayer) {
+                state.bumperState.videoPlayer.destroy();
+            }
+            if (state.videoPlayer) {
+                state.videoPlayer.destroy();
+            }
+            window.onTouchBasedDevice = oldOTBD;
+        });
+
+        it('can render the control when video starts playing', function () {
+            expect($('.skip-control')).not.toExist();
+            state.el.trigger('play');
+            expect($('.skip-control')).toExist();
+        });
+
+        it('add ARIA attributes to play control', function () {
+            state.el.trigger('play');
+            expect($('.skip-control')).toHaveAttrs({
+                'role': 'button',
+                'title': 'Do not show again',
+                'aria-disabled': 'false'
+            });
+        });
+
+        it('can skip the video on click', function () {
+            spyOn(state.bumperState.videoBumper, 'skipAndDoNotShowAgain');
+            state.el.trigger('play');
+            $('.skip-control').click();
+            expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('skip', true);
+            expect(state.bumperState.videoBumper.skipAndDoNotShowAgain).toHaveBeenCalled();
+        });
+
+        it('can destroy itself', function () {
+            state.bumperState.videoPlaySkipControl.destroy();
+            expect(state.bumperState.videoPlaySkipControl).toBeUndefined();
+        });
+    });
+}).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js
index 45db124f0a0efc55d2204be0738c821337342a22..d5b14e6b2d79718958fa32b2ed0452a695d82716 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js
@@ -12,6 +12,7 @@
             $('source').remove();
             window.onTouchBasedDevice = oldOTBD;
             state.storage.clear();
+            state.videoPlayer.destroy();
         });
 
         describe('constructor', function () {
@@ -247,5 +248,13 @@
                 expect($('.speeds .value')).toHaveHtml('0.75x');
             });
         });
+
+        it('can destroy itself', function () {
+            state = jasmine.initializePlayer();
+            state.videoSpeedControl.destroy();
+            expect(state.videoSpeedControl).toBeUndefined();
+            expect($('.video-speeds')).not.toExist();
+            expect($('.speed-button')).not.toExist();
+        });
     });
 }).call(this);
diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js
index 7ff313f956f5c2e5d5d0e55c063fc4b53558a65b..e1edb571d3f36c2ca8672221acc675fad29020b5 100644
--- a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js
+++ b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js
@@ -13,6 +13,7 @@ describe('VideoVolumeControl', function () {
         $('source').remove();
         window.onTouchBasedDevice = oldOTBD;
         state.storage.clear();
+        state.videoPlayer.destroy();
     });
 
     it('Volume level has correct value even if cookie is broken', function () {
@@ -35,8 +36,7 @@ describe('VideoVolumeControl', function () {
         });
 
         it('render the volume control', function () {
-            expect(state.videoControl.secondaryControlsEl.html())
-                .toContain('<div class="volume">\n');
+            expect($('.volume')).toExist();
         });
 
         it('create the slider', function () {
@@ -292,7 +292,7 @@ describe('VideoVolumeControl', function () {
                 shiftKey: true
             });
         });
-    })
+    });
 
     describe('keyDownButtonHandler', function () {
         beforeEach(function () {
@@ -308,6 +308,6 @@ describe('VideoVolumeControl', function () {
             }));
             expect(volumeControl.getMuteStatus()).toEqual(isMuted);
         });
-    })
+    });
 });
 }).call(this);
diff --git a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
index cbf7df47eecc2308f718383160305b8f27ae8f0b..f0c1debcd0af0b5bb71b85c34298af22f6e9b343 100644
--- a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
+++ b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js
@@ -177,9 +177,8 @@ function () {
             }
         };
 
-        var cleanDelta = function () {
-            delta['height'] = 0;
-            delta['width'] = 0;
+        var resetDelta = function () {
+            delta['height'] = delta['width'] = 0;
 
             return module;
         };
@@ -200,12 +199,23 @@ function () {
             return module;
         };
 
+        var destroy = function () {
+            var data = getData();
+            data.element.css({
+                'height': '', 'width': '', 'top': '', 'left': ''
+            });
+            removeCallbacks();
+            resetDelta();
+            mode = null;
+        };
+
         initialize.apply(module, arguments);
 
         return $.extend(true, module, {
             align: align,
             alignByWidthOnly: alignByWidthOnly,
             alignByHeightOnly: alignByHeightOnly,
+            destroy: destroy,
             setParams: initialize,
             setMode: setMode,
             setElement: setElement,
@@ -218,7 +228,7 @@ function () {
             delta: {
                 add: addDelta,
                 substract: substractDelta,
-                reset: cleanDelta
+                reset: resetDelta
             }
         });
     };
diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
index 05654966f5b296839e2660bb35b5b6d96e30772d..ad7edc8b566d7d1aff67994252fa06c67fe25d7d 100644
--- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
+++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
@@ -14,8 +14,8 @@
 
 define(
 'video/01_initialize.js',
-['video/03_video_player.js', 'video/00_video_storage.js', 'video/00_i18n.js'],
-function (VideoPlayer, VideoStorage, i18n) {
+['video/03_video_player.js', 'video/00_i18n.js'],
+function (VideoPlayer, i18n) {
     /**
      * @function
      *
@@ -71,7 +71,6 @@ function (VideoPlayer, VideoStorage, i18n) {
         isYoutubeType: isYoutubeType,
         parseSpeed: parseSpeed,
         parseYoutubeStreams: parseYoutubeStreams,
-        saveState: saveState,
         setPlayerMode: setPlayerMode,
         setSpeed: setSpeed,
         speedToString: speedToString,
@@ -145,9 +144,7 @@ function (VideoPlayer, VideoStorage, i18n) {
                     _youtubeApiDeferred.resolve();
                 }
 
-                window.YT.ready(function () {
-                    onYTApiReady();
-                });
+                window.YT.ready(onYTApiReady);
             } else {
                 // There is only one global variable window.onYouTubeIframeAPIReady which
                 // is supposed to be a function that will be called by the YouTube API
@@ -191,9 +188,7 @@ function (VideoPlayer, VideoStorage, i18n) {
                 // Attach a callback to our Deferred object to be called once the
                 // YouTube API loads.
                 window.onYouTubeIframeAPIReady.done(function () {
-                    window.YT.ready(function () {
-                        onYTApiReady();
-                    });
+                    window.YT.ready(onYTApiReady);
                 });
             }
         } else {
@@ -212,20 +207,15 @@ function (VideoPlayer, VideoStorage, i18n) {
             // callback, which will set `state.youtubeApiAvailable` to `true`.
             // If something goes wrong at this stage, `state.youtubeApiAvailable` is
             // `false`.
-            _reportToServer(state, state.youtubeApiAvailable);
+            if (!state.youtubeIsAvailable) {
+                console.log('[Video info]: YouTube API is not available.');
+            }
+            state.el.trigger('youtube_availability', [state.youtubeIsAvailable]);
         }, state.config.ytTestTimeout);
 
         $.getScript(document.location.protocol + '//' + state.config.ytApiUrl);
     }
 
-    function _reportToServer(state, youtubeIsAvailable) {
-        if (!youtubeIsAvailable) {
-            console.log('[Video info]: YouTube API is not available.');
-        }
-
-        state.saveState(true, { youtube_is_available: youtubeIsAvailable });
-    }
-
     // function _configureCaptions(state)
     //     Configure displaying of captions.
     //
@@ -296,8 +286,7 @@ function (VideoPlayer, VideoStorage, i18n) {
 
         state.videoType = 'html5';
 
-        if (!state.config.sub || !state.config.sub.length) {
-            state.config.sub = '';
+        if (!_.keys(state.config.transcriptLanguages).length) {
             state.config.showCaptions = false;
         }
         state.setSpeed(state.speed);
@@ -328,8 +317,9 @@ function (VideoPlayer, VideoStorage, i18n) {
     function _initializeModules(state, i18n) {
         var dfd = $.Deferred(),
             modulesList = $.map(state.modules, function(module) {
-                if ($.isFunction(module)) {
-                    return module(state, i18n);
+                var options = state.options[module.moduleName] || {};
+                if (_.isFunction(module)) {
+                    return module(state, i18n, options);
                 } else if ($.isPlainObject(module)) {
                     return module;
                 }
@@ -388,7 +378,6 @@ function (VideoPlayer, VideoStorage, i18n) {
                     },
                     'startTime': function (value) {
                         value = parseInt(value, 10);
-
                         if (!isFinite(value) || value < 0) {
                             return 0;
                         }
@@ -407,6 +396,13 @@ function (VideoPlayer, VideoStorage, i18n) {
                 },
                 config = {};
 
+            data = _.extend({
+                startTime: 0,
+                endTime: null,
+                sub: '',
+                streams: ''
+            }, data);
+
             $.each(data, function(option, value) {
                 // Extract option that is in `extractKeys`.
                 if ($.inArray(option, extractKeys) !== -1) {
@@ -420,7 +416,7 @@ function (VideoPlayer, VideoStorage, i18n) {
 
                 // Pre-process data.
                 if (conversions[option]) {
-                    if ($.isFunction(conversions[option])) {
+                    if (_.isFunction(conversions[option])) {
                         value = conversions[option].call(this, value);
                     } else {
                         throw new TypeError(option + ' is not a function.');
@@ -463,12 +459,11 @@ function (VideoPlayer, VideoStorage, i18n) {
 
     function initialize(element) {
         var self = this,
-            el = $(element).find('.video'),
+            el = this.el,
+            id = this.id,
             container = el.find('.video-wrapper'),
-            id = el.attr('id').replace(/video_/, ''),
             __dfd__ = $.Deferred(),
-            isTouch = onTouchBasedDevice() || '',
-            storage = VideoStorage('VideoState', id);
+            isTouch = onTouchBasedDevice() || '';
 
         if (isTouch) {
             el.addClass('is-touch');
@@ -476,23 +471,18 @@ function (VideoPlayer, VideoStorage, i18n) {
 
         $.extend(this, {
             __dfd__: __dfd__,
-            el: el,
             container: container,
-            id: id,
             isFullScreen: false,
-            isTouch: isTouch,
-            storage: storage
+            isTouch: isTouch
         });
 
-        console.log(
-            '[Video info]: Initializing video with id "' + id + '".'
-        );
+        console.log('[Video info]: Initializing video with id "%s".', id);
 
         // We store all settings passed to us by the server in one place. These
         // are "read only", so don't modify them. All variable content lives in
         // 'state' object.
         // jQuery .data() return object with keys in lower camelCase format.
-        this.config = $.extend({}, _getConfiguration(el.data(), storage), {
+        this.config = $.extend({}, _getConfiguration(this.metadata, this.storage), {
             element: element,
             fadeOutTimeout:     1400,
             captionsFreezeTime: 10000,
@@ -602,26 +592,18 @@ function (VideoPlayer, VideoStorage, i18n) {
     //         true: Parsing of YouTube video IDs went OK, and we can proceed
     //             onwards to play YouTube videos.
     function parseYoutubeStreams(youtubeStreams) {
-        var _this;
-
-        if (
-            typeof youtubeStreams === 'undefined' ||
-            youtubeStreams.length === 0
-        ) {
+        if (_.isUndefined(youtubeStreams) || !youtubeStreams.length) {
             return false;
         }
 
-        _this = this;
         this.videos = {};
 
-        $.each(youtubeStreams.split(/,/), function (index, video) {
+        _.each(youtubeStreams.split(/,/), function (video) {
             var speed;
-
             video = video.split(/:/);
-            speed = _this.speedToString(video[0]);
-
-            _this.videos[speed] = video[1];
-        });
+            speed = this.speedToString(video[0]);
+            this.videos[speed] = video[1];
+        }, this);
 
         return _.isString(this.videos['1.0']);
     }
@@ -633,23 +615,21 @@ function (VideoPlayer, VideoStorage, i18n) {
     //     example the length of the video can be determined from the meta
     //     data.
     function fetchMetadata() {
-        var _this = this,
+        var self = this,
             metadataXHRs = [];
 
         this.metadata = {};
 
-        $.each(this.videos, function (speed, url) {
-            var xhr = _this.getVideoMetadata(url, function (data) {
+        metadataXHRs = _.map(this.videos, function (url, speed) {
+            return self.getVideoMetadata(url, function (data) {
                 if (data.data) {
-                    _this.metadata[data.data.id] = data.data;
+                    self.metadata[data.data.id] = data.data;
                 }
             });
-
-            metadataXHRs.push(xhr);
         });
 
         $.when.apply(this, metadataXHRs).done(function () {
-            _this.el.trigger('metadata_received');
+            self.el.trigger('metadata_received');
 
             // Not only do we trigger the "metadata_received" event, we also
             // set a flag to notify that metadata has been received. This
@@ -657,7 +637,7 @@ function (VideoPlayer, VideoStorage, i18n) {
             // to know that metadata has been received. This is important in
             // cases when some code will subscribe to the "metadata_received"
             // event after it has been triggered.
-            _this.youtubeMetadataReceived = true;
+            self.youtubeMetadataReceived = true;
 
         });
     }
@@ -666,23 +646,21 @@ function (VideoPlayer, VideoStorage, i18n) {
     //
     //     Create a separate array of available speeds.
     function parseSpeed() {
-        this.speeds = ($.map(this.videos, function (url, speed) {
-            return speed;
-        })).sort();
+        this.speeds = _.keys(this.videos).sort();
     }
 
-    function setSpeed(newSpeed, updateStorage) {
+    function setSpeed(newSpeed) {
         // Possible speeds for each player type.
         // HTML5 =          [0.75, 1, 1.25, 1.5]
         // Youtube Flash =  [0.75, 1, 1.25, 1.5]
         // Youtube HTML5 =  [0.25, 0.5, 1, 1.5, 2]
         var map = {
-                '0.25': '0.75', // Youtube HTML5 -> HTML5 or Youtube Flash
-                '0.50': '0.75', // Youtube HTML5 -> HTML5 or Youtube Flash
-                '0.75': '0.50', // HTML5 or Youtube Flash -> Youtube HTML5
-                '1.25': '1.50', // HTML5 or Youtube Flash -> Youtube HTML5
-                '2.0': '1.50'   // Youtube HTML5 -> HTML5 or Youtube Flash
-            };
+            '0.25': '0.75', // Youtube HTML5 -> HTML5 or Youtube Flash
+            '0.50': '0.75', // Youtube HTML5 -> HTML5 or Youtube Flash
+            '0.75': '0.50', // HTML5 or Youtube Flash -> Youtube HTML5
+            '1.25': '1.50', // HTML5 or Youtube Flash -> Youtube HTML5
+            '2.0': '1.50'   // Youtube HTML5 -> HTML5 or Youtube Flash
+        };
 
         if (_.contains(this.speeds, newSpeed)) {
             this.speed = newSpeed;
@@ -690,57 +668,21 @@ function (VideoPlayer, VideoStorage, i18n) {
             newSpeed = map[newSpeed];
             this.speed = _.contains(this.speeds, newSpeed) ? newSpeed : '1.0';
         }
-
-        if (updateStorage) {
-            this.storage.setItem('speed', this.speed, true);
-            this.storage.setItem('general_speed', this.speed);
-        }
     }
 
     function getVideoMetadata(url, callback) {
-        var successHandler, xhr;
-
-        if (typeof url !== 'string') {
+        if (!(_.isString(url))) {
             url = this.videos['1.0'] || '';
         }
-        successHandler = ($.isFunction(callback)) ? callback : null;
-        xhr = $.ajax({
+
+        return $.ajax({
             url: [
                 document.location.protocol, '//', this.config.ytTestUrl, url,
                 '?v=2&alt=jsonc'
             ].join(''),
             dataType: 'jsonp',
             timeout: this.config.ytTestTimeout,
-            success: successHandler
-        });
-
-        return xhr;
-    }
-
-    function saveState(async, data) {
-
-        if (!($.isPlainObject(data))) {
-            data = {
-                saved_video_position: this.videoPlayer.currentTime
-            };
-        }
-
-        if (data.speed) {
-            this.storage.setItem('speed', data.speed, true);
-        }
-
-        if (data.hasOwnProperty('saved_video_position')) {
-            this.storage.setItem('savedVideoPosition', data.saved_video_position, true);
-
-            data.saved_video_position = Time.formatFull(data.saved_video_position);
-        }
-
-        $.ajax({
-            url: this.config.saveStateUrl,
-            type: 'POST',
-            async: async ? true : false,
-            dataType: 'json',
-            data: data,
+            success: _.isFunction(callback) ? callback : null
         });
     }
 
diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
index d055b85d62c4523de5d115493f422629f5eeff7b..dc3fd7974b8dc199d22043b1fb3b9244bd41f1b4 100644
--- a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
+++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
@@ -110,6 +110,54 @@ function () {
                     });
         };
 
+        Player.prototype.onError = function (event) {
+            if ($.isFunction(this.config.events.onError)) {
+                this.config.events.onError();
+            }
+        };
+
+        Player.prototype.destroy = function () {
+            this.video.removeEventListener('loadedmetadata', this.onLoadedMetadata, false);
+            this.video.removeEventListener('play', this.onPlay, false);
+            this.video.removeEventListener('playing', this.onPlaying, false);
+            this.video.removeEventListener('pause', this.onPause, false);
+            this.video.removeEventListener('ended', this.onEnded, false);
+            this.el
+                .find('.video-player div').removeClass('hidden')
+                .end()
+                .find('.video-player h3').addClass('hidden')
+                .end().removeClass('is-initialized')
+                .find('.spinner').attr({'aria-hidden': 'false'});
+            this.videoEl.remove();
+        };
+
+        Player.prototype.onLoadedMetadata = function () {
+            this.playerState = HTML5Video.PlayerState.PAUSED;
+            if ($.isFunction(this.config.events.onReady)) {
+                this.config.events.onReady(null);
+            }
+        };
+
+        Player.prototype.onPlay = function () {
+            this.playerState = HTML5Video.PlayerState.BUFFERING;
+            this.callStateChangeCallback();
+        };
+
+        Player.prototype.onPlaying = function () {
+            this.playerState = HTML5Video.PlayerState.PLAYING;
+            this.callStateChangeCallback();
+        };
+
+        Player.prototype.onPause = function () {
+            this.playerState = HTML5Video.PlayerState.PAUSED;
+            this.callStateChangeCallback();
+        };
+
+        Player.prototype.onEnded = function () {
+            this.playerState = HTML5Video.PlayerState.ENDED;
+            this.callStateChangeCallback();
+        };
+
         return Player;
 
         /*
@@ -152,6 +200,7 @@ function () {
             var isTouch = onTouchBasedDevice() || '',
                 sourceList, _this, errorMessage, lastSource;
 
+            _.bindAll(this, 'onLoadedMetadata', 'onPlay', 'onPlaying', 'onPause', 'onEnded');
             this.logs = [];
             // Initially we assume that el is a DOM element. If jQuery selector
             // fails to select something, we assume that el is an ID of a DOM
@@ -226,6 +275,8 @@ function () {
 
             lastSource = this.videoEl.find('source').last();
             lastSource.on('error', this.showErrorMessage.bind(this));
+            lastSource.on('error', this.onError.bind(this));
+            this.videoEl.on('error', this.onError.bind(this));
 
             if (/iP(hone|od)/i.test(isTouch[0])) {
                 this.videoEl.prop('controls', true);
@@ -280,35 +331,11 @@ function () {
             // When the <video> tag has been processed by the browser, and it
             // is ready for playback, notify other parts of the VideoPlayer,
             // and initially pause the video.
-            this.video.addEventListener('loadedmetadata', function () {
-                _this.playerState = HTML5Video.PlayerState.PAUSED;
-                if ($.isFunction(_this.config.events.onReady)) {
-                    _this.config.events.onReady(null);
-                }
-            }, false);
-
-            // Register the 'play' event.
-            this.video.addEventListener('play', function () {
-                _this.playerState = HTML5Video.PlayerState.BUFFERING;
-                _this.callStateChangeCallback();
-            }, false);
-
-            this.video.addEventListener('playing', function () {
-                _this.playerState = HTML5Video.PlayerState.PLAYING;
-                _this.callStateChangeCallback();
-            }, false);
-
-            // Register the 'pause' event.
-            this.video.addEventListener('pause', function () {
-                _this.playerState = HTML5Video.PlayerState.PAUSED;
-                _this.callStateChangeCallback();
-            }, false);
-
-            // Register the 'ended' event.
-            this.video.addEventListener('ended', function () {
-                _this.playerState = HTML5Video.PlayerState.ENDED;
-                _this.callStateChangeCallback();
-            }, false);
+            this.video.addEventListener('loadedmetadata', this.onLoadedMetadata, false);
+            this.video.addEventListener('play', this.onPlay, false);
+            this.video.addEventListener('playing', this.onPlaying, false);
+            this.video.addEventListener('pause', this.onPause, false);
+            this.video.addEventListener('ended', this.onEnded, false);
 
             // Place the <video> element on the page.
             this.videoEl.appendTo(this.el.find('.video-player div'));
diff --git a/common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js b/common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js
index 53e54f817cd9bce499821953a4d685ef25c9de0b..e1c2ce142a9ad1fa97b00627d7d973bad7194a50 100644
--- a/common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js
+++ b/common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js
@@ -1,308 +1,241 @@
-(function (requirejs, require, define) {
-
+(function(define) {
+'use strict';
 // VideoAccessibleMenu module.
 define(
-'video/035_video_accessible_menu.js',
-[],
-function () {
-
-    // VideoAccessibleMenu() function - what this module "exports".
-    return function (state) {
-        var dfd = $.Deferred();
-
-        if (state.el.find('li.video-tracks') === 0) {
-            dfd.resolve();
-            return dfd.promise();
+'video/035_video_accessible_menu.js', [],
+function() {
+    /**
+     * Video Download Transcript control module.
+     * @exports video/035_video_accessible_menu.js
+     * @constructor
+     * @param {jquery Element} element
+     * @param {Object} options
+     */
+    var VideoAccessibleMenu = function(element, options) {
+        if (!(this instanceof VideoAccessibleMenu)) {
+            return new VideoAccessibleMenu(element, options);
         }
 
-        state.videoAccessibleMenu = {
-            value: state.storage.getItem('transcript_download_format')
-        };
-
-        _initialize(state);
-        dfd.resolve();
-        return dfd.promise();
-    };
-
-    // ***************************************************************
-    // Private functions start here.
-    // ***************************************************************
+        _.bindAll(this, 'openMenu', 'openMenuHandler', 'closeMenu', 'closeMenuHandler', 'toggleMenuHandler',
+            'clickHandler', 'keyDownHandler', 'render', 'menuItemsLinksFocused', 'changeFileType', 'setValue'
+        );
 
-    function _initialize(state) {
-        _makeFunctionsPublic(state);
-        _renderElements(state);
-        _addAriaAttributes(state);
-        _bindHandlers(state);
-    }
+        this.container = element;
+        this.options = options || {};
 
-    // function _makeFunctionsPublic(state)
-    //
-    //     Functions which will be accessible via 'state' object. When called,
-    //     these functions will get the 'state' object as a context.
-    function _makeFunctionsPublic(state) {
-        var methodsDict = {
-            changeFileType: changeFileType,
-            setValue: setValue
-        };
-
-        state.bindTo(methodsDict, state.videoAccessibleMenu, state);
-    }
-
-    // function _renderElements(state)
-    //
-    //     Create any necessary DOM elements, attach them, and set their
-    //     initial configuration. Also make the created DOM elements available
-    //     via the 'state' object. Much easier to work this way - you don't
-    //     have to do repeated jQuery element selects.
-    function _renderElements(state) {
+        if (this.container.find('.video-tracks')) {
+            this.initialize();
+        }
+    };
 
-        // For the  time being, we assume that the menu structure is present in
-        // the template HTML. In the future accessible menu plugin, everything
-        // inside <div class='menu-container'></div> will be generated in this
-        // file.
-        var container = state.el.find('li.video-tracks>div.a11y-menu-container'),
-            button = container.children('a.a11y-menu-button'),
-            menuList = container.children('ol.a11y-menu-list'),
-            menuItems = menuList.children('li.a11y-menu-item'),
-            menuItemsLinks = menuItems.children('a.a11y-menu-item-link'),
+    VideoAccessibleMenu.prototype = {
+        /** Initializes the module. */
+        initialize: function() {
+            this.value = this.options.storage.getItem('transcript_download_format');
+            this.el = this.container.find('.video-tracks .a11y-menu-container');
+            this.render();
+            this.bindHandlers();
+        },
+
+        /**
+         * Creates any necessary DOM elements, attach them, and set their,
+         * initial configuration.
+         */
+        render: function() {
+            var value, msg;
+            // For the  time being, we assume that the menu structure is present in
+            // the template HTML. In the future accessible menu plugin, everything
+            // inside <div class='menu-container'></div> will be generated in this
+            // file.
+            this.button = this.el.children('.a11y-menu-button');
+            this.menuList = this.el.children('.a11y-menu-list');
+            this.menuItems = this.menuList.children('.a11y-menu-item');
+            this.menuItemsLinks = this.menuItems.children('.a11y-menu-item-link');
             value = (function (val, activeElement) {
                 return val || activeElement.find('a').data('value') || 'srt';
-            }(state.videoAccessibleMenu.value, menuItems.filter('.active'))),
+            }(this.value, this.menuItems.filter('.active')));
             msg = '.' + value;
 
-        $.extend(state.videoAccessibleMenu, {
-            container: container,
-            button: button,
-            menuList: menuList,
-            menuItems: menuItems,
-            menuItemsLinks: menuItemsLinks
-        });
-
-        if (value) {
-            state.videoAccessibleMenu.setValue(value);
-            button.text(gettext(msg));
-        }
-    }
-
-    function _addAriaAttributes(state) {
-        var menu = state.videoAccessibleMenu;
-
-        menu.button.attr({
-            'role': 'button',
-            'aria-disabled': 'false'
-        });
-
-        menu.menuList.attr('role', 'menu');
-
-        menu.menuItemsLinks.each(function(){
-            $(this).attr({
-                'role': 'menuitem',
-                'aria-disabled': 'false'
+            if (value) {
+                this.setValue(value);
+                this.button.text(gettext(msg));
+            }
+        },
+
+        /** Bind any necessary function callbacks to DOM events. */
+        bindHandlers: function() {
+            // Attach various events handlers to menu container.
+            this.el.on({
+                'mouseenter': this.openMenuHandler,
+                'mouseleave': this.closeMenuHandler,
+                'click': this.toggleMenuHandler,
+                'keydown': this.keyDownHandler
             });
-        });
-    }
-
-    // Get previous element in array or cyles back to the last if it is the
-    // first.
-    function _previousMenuItemLink(links, index) {
-        return $(links.eq(index < 1 ? links.length - 1 : index - 1));
-    }
-
-    // Get next element in array or cyles back to the first if it is the last.
-    function _nextMenuItemLink(links, index) {
-        return $(links.eq(index >= links.length - 1 ? 0 : index + 1));
-    }
-
-    function _menuItemsLinksFocused(menu) {
-        return menu.menuItemsLinks.is(':focus');
-    }
-
-    function _openMenu(menu, without_handler) {
-        // When menu items have focus, the menu stays open on
-        // mouseleave. A _closeMenuHandler is added to the window
-        // element to have clicks close the menu when they happen
-        // outside of it. We namespace the click event to easily remove it (and
-        // only it) in _closeMenu.
-        menu.container.addClass('open');
-        menu.button.text('...');
-        if (!without_handler) {
-            $(window).on('click.currentMenu', _closeMenuHandler.bind(menu));
-        }
-
-        // @TODO: onOpen callback
-    }
-
-    function _closeMenu(menu, without_handler) {
-        // Remove the previously added clickHandler from window element.
-        var msg = '.' + menu.value;
-
-        menu.container.removeClass('open');
-        menu.button.text(gettext(msg));
-        if (!without_handler) {
-            $(window).off('click.currentMenu');
-        }
-
-        // @TODO: onClose callback
-    }
-
-    function _openMenuHandler(event) {
-        _openMenu(this, true);
 
-        return false;
-    }
-
-    function _closeMenuHandler(event) {
-        // Only close the menu if no menu item link has focus or `click` event.
-        if (!_menuItemsLinksFocused(this) || event.type == 'click') {
-            _closeMenu(this, true);
-        }
-
-        return false;
-    }
-
-    function _toggleMenuHandler(event) {
-        if (this.container.hasClass('open')) {
-            _closeMenu(this, true);
-        } else {
-            _openMenu(this, true);
-        }
-
-        return false;
-    }
-
-    // Various event handlers. They all return false to stop propagation and
-    // prevent default behavior.
-    function _clickHandler(event) {
-        var target = $(event.currentTarget);
-
-        this.changeFileType.call(this, event);
-        _closeMenu(this, true);
+            // Attach click and keydown event handlers to individual menu items.
+            this.menuItems
+                .on('click', 'a.a11y-menu-item-link', this.clickHandler)
+                .on('keydown', 'a.a11y-menu-item-link', this.keyDownHandler);
+        },
+
+        // Get previous element in array or cyles back to the last if it is the
+        // first.
+        previousMenuItemLink: function(links, index) {
+            return index < 1 ? links.last() : links.eq(index - 1);
+        },
+
+        // Get next element in array or cyles back to the first if it is the last.
+        nextMenuItemLink: function(links, index) {
+            return index >= links.length - 1 ? links.first() : links.eq(index + 1);
+        },
+
+        menuItemsLinksFocused: function() {
+            return this.menuItemsLinks.is(':focus');
+        },
+
+        openMenu: function(withoutHandler) {
+            // When menu items have focus, the menu stays open on
+            // mouseleave. A closeMenuHandler is added to the window
+            // element to have clicks close the menu when they happen
+            // outside of it. We namespace the click event to easily remove it (and
+            // only it) in closeMenu.
+            this.el.addClass('open');
+            this.button.text('...');
+            if (!withoutHandler) {
+                $(window).on('click.currentMenu', this.closeMenuHandler);
+            }
+            // @TODO: onOpen callback
+        },
 
-        return false;
-    }
+        closeMenu: function(withoutHandler) {
+            // Remove the previously added clickHandler from window element.
+            var msg = '.' + this.value;
 
-    function _keyDownHandler(event) {
-        var KEY = $.ui.keyCode,
-            keyCode = event.keyCode,
-            target = $(event.currentTarget),
-            index;
+            this.el.removeClass('open');
+            this.button.text(gettext(msg));
+            if (!withoutHandler) {
+                $(window).off('click.currentMenu');
+            }
+            // @TODO: onClose callback
+        },
 
-        if (target.is('a.a11y-menu-item-link')) {
+        openMenuHandler: function() {
+            this.openMenu(true);
+            return false;
+        },
 
-            index = target.parent().index();
+        closeMenuHandler: function(event) {
+            // Only close the menu if no menu item link has focus or `click` event.
+            if (!this.menuItemsLinksFocused() || event.type === 'click') {
+                this.closeMenu(true);
+            }
+            return false;
+        },
 
-            switch (keyCode) {
-                // Scroll up menu, wrapping at the top. Keep menu open.
-                case KEY.UP:
-                    _previousMenuItemLink(this.menuItemsLinks, index).focus();
-                    break;
-                // Scroll down  menu, wrapping at the bottom. Keep menu
-                // open.
-                case KEY.DOWN:
-                    _nextMenuItemLink(this.menuItemsLinks, index).focus();
-                    break;
-                // Close menu.
-                case KEY.TAB:
-                    _closeMenu(this);
-                    // TODO
-                    // What has to happen here? In speed menu, tabbing backward
-                    // will give focus to Play/Pause button and tabbing
-                    // forward to Volume button.
-                    break;
-                // Close menu, give focus to button and change
-                // file type.
-                case KEY.ENTER:
-                case KEY.SPACE:
-                    this.button.focus();
-                    this.changeFileType.call(this, event);
-                    _closeMenu(this);
-                    break;
-                // Close menu and give focus to speed control.
-                case KEY.ESCAPE:
-                    _closeMenu(this);
-                    this.button.focus();
-                    break;
+        toggleMenuHandler: function() {
+            if (this.el.hasClass('open')) {
+                this.closeMenu(true);
+            } else {
+                this.openMenu(true);
             }
             return false;
-        }
-        else {
-            switch(keyCode) {
-                // Open menu and focus on last element of list above it.
-                case KEY.ENTER:
-                case KEY.SPACE:
-                case KEY.UP:
-                    _openMenu(this);
-                    this.menuItemsLinks.last().focus();
-                    break;
-                // Close menu.
-                case KEY.ESCAPE:
-                    _closeMenu(this);
-                    break;
+        },
+
+        // Various event handlers. They all return false to stop propagation and
+        // prevent default behavior.
+        clickHandler: function(event) {
+            this.changeFileType.call(this, event);
+            this.closeMenu(true);
+            return false;
+        },
+
+        keyDownHandler: function(event) {
+            var KEY = $.ui.keyCode,
+                keyCode = event.keyCode,
+                target = $(event.currentTarget),
+                index;
+
+            if (target.is('a.a11y-menu-item-link')) {
+                index = target.parent().index();
+                switch (keyCode) {
+                    // Scroll up menu, wrapping at the top. Keep menu open.
+                    case KEY.UP:
+                        this.previousMenuItemLink(this.menuItemsLinks, index).focus();
+                        break;
+                    // Scroll down  menu, wrapping at the bottom. Keep menu
+                    // open.
+                    case KEY.DOWN:
+                        this.nextMenuItemLink(this.menuItemsLinks, index).focus();
+                        break;
+                    // Close menu.
+                    case KEY.TAB:
+                        this.closeMenu();
+                        // TODO
+                        // What has to happen here? In speed menu, tabbing backward
+                        // will give focus to Play/Pause button and tabbing
+                        // forward to Volume button.
+                        break;
+                    // Close menu, give focus to button and change
+                    // file type.
+                    case KEY.ENTER:
+                    case KEY.SPACE:
+                        this.button.focus();
+                        this.changeFileType.call(this, event);
+                        this.closeMenu();
+                        break;
+                    // Close menu and give focus to speed control.
+                    case KEY.ESCAPE:
+                        this.closeMenu();
+                        this.button.focus();
+                        break;
+                }
+                return false;
+            }
+            else {
+                switch(keyCode) {
+                    // Open menu and focus on last element of list above it.
+                    case KEY.ENTER:
+                    case KEY.SPACE:
+                    case KEY.UP:
+                        this.openMenu();
+                        this.menuItemsLinks.last().focus();
+                        break;
+                    // Close menu.
+                    case KEY.ESCAPE:
+                        this.closeMenu();
+                        break;
+                }
+                // We do not stop propagation and default behavior on a TAB
+                // keypress.
+                return event.keyCode === KEY.TAB;
             }
-            // We do not stop propagation and default behavior on a TAB
-            // keypress.
-            return event.keyCode === KEY.TAB;
+        },
+
+        setValue: function(value) {
+            this.value = value;
+            this.menuItems
+                .removeClass('active')
+                .find("a[data-value='" + value + "']")
+                .parent()
+                .addClass('active');
+        },
+
+        changeFileType: function(event) {
+            var fileType = $(event.currentTarget).data('value'),
+                data = {'transcript_download_format': fileType};
+
+            this.setValue(fileType);
+            this.options.storage.setItem('transcript_download_format', fileType);
+
+            $.ajax({
+                url: this.options.saveStateUrl,
+                type: 'POST',
+                dataType: 'json',
+                data: data
+            });
         }
-    }
-
-    /**
-     * @desc Bind any necessary function callbacks to DOM events (click,
-     *     mousemove, etc.).
-     *
-     * @type {function}
-     * @access private
-     *
-     * @param {object} state The object containg the state of the video player.
-     *     All other modules, their parameters, public variables, etc. are
-     *     available via this object.
-     *
-     * @this {object} The global window object.
-     *
-     * @returns {undefined}
-     */
-    function _bindHandlers(state) {
-        var menu = state.videoAccessibleMenu;
-
-        // Attach various events handlers to menu container.
-        menu.container.on({
-            'mouseenter': _openMenuHandler.bind(menu),
-            'mouseleave': _closeMenuHandler.bind(menu),
-            'click': _toggleMenuHandler.bind(menu),
-            'keydown': _keyDownHandler.bind(menu)
-        });
-
-        // Attach click and keydown event handlers to individual menu items.
-        menu.menuItems
-            .on('click', 'a.a11y-menu-item-link', _clickHandler.bind(menu))
-            .on('keydown', 'a.a11y-menu-item-link', _keyDownHandler.bind(menu));
-    }
-
-    function setValue(value) {
-        var menu = this.videoAccessibleMenu;
-
-        menu.value = value;
-        menu.menuItems
-            .removeClass('active')
-            .find("a[data-value='" + value + "']")
-            .parent()
-            .addClass('active');
-    }
-
-    // ***************************************************************
-    // Public functions start here.
-    // These are available via the 'state' object. Their context ('this'
-    // keyword) is the 'state' object. The magic private function that makes
-    // them available and sets up their context is makeFunctionsPublic().
-    // ***************************************************************
-
-    function changeFileType(event) {
-        var fileType = $(event.currentTarget).data('value');
-
-        this.videoAccessibleMenu.setValue(fileType);
-        this.saveState(true, {'transcript_download_format': fileType});
-        this.storage.setItem('transcript_download_format', fileType);
-    }
+    };
 
+    return VideoAccessibleMenu;
 });
-
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define));
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
index a4c268cfa7cac835aab69f58a7da212b69f04bc5..c2307941e91e5f83e39c158ef963e391c671e58d 100644
--- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
+++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
@@ -15,6 +15,7 @@ function (HTML5Video, Resizer) {
             return dfd.promise();
         },
         methodsDict = {
+            destroy: destroy,
             duration: duration,
             handlePlaybackQualityChange: handlePlaybackQualityChange,
 
@@ -28,13 +29,14 @@ function (HTML5Video, Resizer) {
             isEnded: isEnded,
             isPlaying: isPlaying,
             isUnstarted: isUnstarted,
-            log: log,
             onCaptionSeek: onSeek,
             onEnded: onEnded,
+            onError: onError,
             onPause: onPause,
             onPlay: onPlay,
             runTimer: runTimer,
             stopTimer: stopTimer,
+            onLoadMetadataHtml5: onLoadMetadataHtml5,
             onPlaybackQualityChange: onPlaybackQualityChange,
             onReady: onReady,
             onSlideSeek: onSeek,
@@ -49,8 +51,7 @@ function (HTML5Video, Resizer) {
             update: update,
             figureOutStartEndTime: figureOutStartEndTime,
             figureOutStartingTime: figureOutStartingTime,
-            updatePlayTime: updatePlayTime,
-            logStopVideo:logStopVideo
+            updatePlayTime: updatePlayTime
         };
 
     VideoPlayer.prototype = methodsDict;
@@ -80,6 +81,17 @@ function (HTML5Video, Resizer) {
         state.videoPlayer.onCaptionSeek = debouncedF;
     }
 
+    // Updates players state, once metadata is loaded for html5 player.
+    function onLoadMetadataHtml5() {
+        var player = this.videoPlayer.player.videoEl,
+            videoWidth = player[0].videoWidth || player.width(),
+            videoHeight = player[0].videoHeight || player.height();
+
+        _resize(this, videoWidth, videoHeight);
+        _updateVcrAndRegion(this);
+    }
+
+
     // function _initialize(state)
     //
     //     Create any necessary DOM elements, attach them, and set their
@@ -94,8 +106,6 @@ function (HTML5Video, Resizer) {
         // metadata is loaded, which normally happens just after the video
         // starts playing. Just after that configurations can be applied.
         state.videoPlayer.ready = _.once(function () {
-            $(window).on('unload', state.saveState);
-
             if (!state.isFlashMode() && state.speed != '1.0') {
 
                 // Work around a bug in the Youtube API that causes videos to
@@ -150,20 +160,13 @@ function (HTML5Video, Resizer) {
                 videoSources: state.config.sources,
                 events: {
                     onReady:       state.videoPlayer.onReady,
-                    onStateChange: state.videoPlayer.onStateChange
+                    onStateChange: state.videoPlayer.onStateChange,
+                    onError: state.videoPlayer.onError
                 }
             });
 
             player = state.videoEl = state.videoPlayer.player.videoEl;
-
-            player[0].addEventListener('loadedmetadata', function () {
-                var videoWidth = player[0].videoWidth || player.width(),
-                    videoHeight = player[0].videoHeight || player.height();
-
-                _resize(state, videoWidth, videoHeight);
-
-                _updateVcrAndRegion(state);
-            }, false);
+            player[0].addEventListener('loadedmetadata', state.videoPlayer.onLoadMetadataHtml5, false);
 
         } else {
             youTubeId = state.youtubeId();
@@ -174,8 +177,8 @@ function (HTML5Video, Resizer) {
                 events: {
                     onReady: state.videoPlayer.onReady,
                     onStateChange: state.videoPlayer.onStateChange,
-                    onPlaybackQualityChange: state.videoPlayer
-                        .onPlaybackQualityChange
+                    onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange,
+                    onError: state.videoPlayer.onError
                 }
             });
 
@@ -261,8 +264,8 @@ function (HTML5Video, Resizer) {
             });
         }
 
-        $(window).on('resize', _.debounce(function () {
-            state.trigger('videoControl.updateControlsHeight', null);
+        $(window).on('resize.video', _.debounce(function () {
+            state.trigger('videoFullScreen.updateControlsHeight', null);
             state.el.trigger('caption:resize');
             state.resizer.align();
         }, 100));
@@ -292,8 +295,8 @@ function (HTML5Video, Resizer) {
             events: {
                 onReady: state.videoPlayer.onReady,
                 onStateChange: state.videoPlayer.onStateChange,
-                onPlaybackQualityChange: state.videoPlayer
-                    .onPlaybackQualityChange
+                onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange,
+                onError: state.videoPlayer.onError
             }
         });
 
@@ -309,6 +312,28 @@ function (HTML5Video, Resizer) {
     // them available and sets up their context is makeFunctionsPublic().
     // ***************************************************************
 
+    function destroy() {
+        var player = this.videoPlayer.player;
+        this.el.removeClass([
+            'is-unstarted', 'is-playing', 'is-paused', 'is-buffered',
+            'is-ended', 'is-cued'
+        ].join(' '));
+        $(window).off('.video');
+        this.el.trigger('destroy');
+        this.el.off();
+        this.videoPlayer.stopTimer();
+        if (this.resizer && this.resizer.destroy) {
+            this.resizer.destroy();
+        }
+        if (player && player.video) {
+            player.video.removeEventListener('loadedmetadata', this.videoPlayer.onLoadMetadataHtml5, false);
+        }
+        if (player && _.isFunction(player.destroy)) {
+            player.destroy();
+        }
+        delete this.videoPlayer;
+    }
+
     function pause() {
         if (this.videoPlayer.player.pauseVideo) {
             this.videoPlayer.player.pauseVideo();
@@ -349,9 +374,10 @@ function (HTML5Video, Resizer) {
                 this.trigger('videoProgressSlider.notifyThroughHandleEnd', {
                     end: true
                 });
-                // Emit `stop_video` event
-                this.videoPlayer.logStopVideo();
+
+                this.el.trigger('stop');
             }
+            this.el.trigger('timeupdate', [this.videoPlayer.currentTime]);
         }
     }
 
@@ -436,19 +462,8 @@ function (HTML5Video, Resizer) {
         }
 
         newSpeed = parseFloat(newSpeed).toFixed(2).replace(/\.00$/, '.0');
-
-        this.videoPlayer.log(
-            'speed_change_video',
-            {
-                current_time: time,
-                old_speed: this.speed,
-                new_speed: newSpeed
-            }
-        );
-
-        this.setSpeed(newSpeed, true);
+        this.setSpeed(newSpeed);
         this.videoPlayer.setPlaybackRate(newSpeed);
-        this.saveState(true, { speed: newSpeed });
     }
 
     // Every 200 ms, if the video is playing, we call the function update, via
@@ -459,20 +474,12 @@ function (HTML5Video, Resizer) {
         var time = params.time,
             type = params.type,
             oldTime = this.videoPlayer.currentTime;
-
         // After the user seeks, the video will start playing from
         // the sought point, and stop playing at the end.
         this.videoPlayer.goToStartTime = false;
 
         this.videoPlayer.seekTo(time);
-        this.videoPlayer.log(
-            'seek_video',
-            {
-                old_time: oldTime,
-                new_time: time,
-                type: type
-            }
-        );
+        this.el.trigger('seek', [time, oldTime, type]);
     }
 
     function seekTo(time) {
@@ -509,7 +516,6 @@ function (HTML5Video, Resizer) {
         }
 
         this.videoPlayer.updatePlayTime(time, true);
-        this.el.trigger('seek', arguments);
 
         // the timer is stopped above; restart it.
         if (this.videoPlayer.isPlaying()) {
@@ -534,9 +540,8 @@ function (HTML5Video, Resizer) {
 
     function onEnded() {
         var time = this.videoPlayer.duration();
-        this.videoPlayer.logStopVideo();
 
-        this.trigger('videoControl.pause', null);
+
         this.trigger('videoProgressSlider.notifyThroughHandleEnd', {
             end: true
         });
@@ -544,40 +549,20 @@ function (HTML5Video, Resizer) {
         if (this.videoPlayer.skipOnEndedStartEndReset) {
             this.videoPlayer.skipOnEndedStartEndReset = undefined;
         }
-
         // Sometimes `onEnded` events fires when `currentTime` not equal
         // `duration`. In this case, slider doesn't reach the end point of
         // timeline.
         this.videoPlayer.updatePlayTime(time);
-
         this.el.trigger('ended', arguments);
     }
 
     function onPause() {
-        this.videoPlayer.log(
-            'pause_video',
-            {
-                currentTime: this.videoPlayer.currentTime
-            }
-        );
-
         this.videoPlayer.stopTimer();
-
-        this.trigger('videoControl.pause', null);
-        this.saveState(true);
         this.el.trigger('pause', arguments);
     }
 
     function onPlay() {
-        this.videoPlayer.log(
-            'play_video',
-            {
-                currentTime: this.videoPlayer.currentTime
-            }
-        );
-
         this.videoPlayer.runTimer();
-        this.trigger('videoControl.play', null);
         this.trigger('videoProgressSlider.notifyThroughHandleEnd', {
             end: false
         });
@@ -591,22 +576,12 @@ function (HTML5Video, Resizer) {
         this.videoPlayer.player.setPlaybackQuality(value);
     }
 
-    function logStopVideo(){
-        this.videoPlayer.log(
-            'stop_video',
-            {
-                currentTime: this.videoPlayer.currentTime
-            }
-        );
-    }
-
     function onPlaybackQualityChange() {
         var quality;
 
         quality = this.videoPlayer.player.getPlaybackQuality();
 
         this.trigger('videoQualityControl.onQualityChange', quality);
-
         this.el.trigger('qualitychange', arguments);
     }
 
@@ -625,8 +600,6 @@ function (HTML5Video, Resizer) {
             _this.videoPlayer.onVolumeChange(volume);
         });
 
-        this.videoPlayer.log('load_video');
-
         availablePlaybackRates = this.videoPlayer.player
                                     .getAvailablePlaybackRates();
 
@@ -717,6 +690,10 @@ function (HTML5Video, Resizer) {
         }
 
         this.el.trigger('ready', arguments);
+
+        if (this.config.autoplay) {
+            this.videoPlayer.play();
+        }
     }
 
     function onStateChange(event) {
@@ -755,6 +732,10 @@ function (HTML5Video, Resizer) {
         }
     }
 
+    function onError (code) {
+        this.el.trigger('error', [code]);
+    }
+
     function figureOutStartEndTime(duration) {
         var videoPlayer = this.videoPlayer;
 
@@ -937,30 +918,6 @@ function (HTML5Video, Resizer) {
         return Math.floor(dur);
     }
 
-    function log(eventName, data) {
-        var logInfo;
-
-        // Default parameters that always get logged.
-        logInfo = {
-            id:   this.id
-        };
-
-        // If extra parameters were passed to the log.
-        if (data) {
-            $.each(data, function (paramName, value) {
-                logInfo[paramName] = value;
-            });
-        }
-
-        if (this.isYoutubeType()) {
-            logInfo.code = this.youtubeId();
-        } else {
-            logInfo.code = 'html5';
-        }
-
-        Logger.log(eventName, logInfo);
-    }
-
     function onVolumeChange(volume) {
         this.videoPlayer.player.setVolume(volume);
     }
diff --git a/common/lib/xmodule/xmodule/js/src/video/04_video_control.js b/common/lib/xmodule/xmodule/js/src/video/04_video_control.js
index 561c8c02d65c598f573ce1a1b16fa824b2afef68..ce67eb18ad1fbb91c43e928798ec5b8d645964fc 100644
--- a/common/lib/xmodule/xmodule/js/src/video/04_video_control.js
+++ b/common/lib/xmodule/xmodule/js/src/video/04_video_control.js
@@ -1,5 +1,4 @@
 (function (requirejs, require, define) {
-
 // VideoControl module.
 define(
 'video/04_video_control.js',
@@ -30,24 +29,29 @@ function () {
     //     get the 'state' object as a context.
     function _makeFunctionsPublic(state) {
         var methodsDict = {
-            exitFullScreenHandler: exitFullScreenHandler,
+            destroy: destroy,
             hideControls: hideControls,
-            hidePlayPlaceholder: hidePlayPlaceholder,
-            pause: pause,
-            play: play,
             show: show,
             showControls: showControls,
-            showPlayPlaceholder: showPlayPlaceholder,
-            toggleFullScreen: toggleFullScreen,
-            toggleFullScreenHandler: toggleFullScreenHandler,
-            togglePlayback: togglePlayback,
-            updateControlsHeight: updateControlsHeight,
+            focusFirst: focusFirst,
             updateVcrVidTime: updateVcrVidTime
         };
 
         state.bindTo(methodsDict, state.videoControl, state);
     }
 
+    function destroy() {
+        this.el.off({
+            'mousemove': this.videoControl.showControls,
+            'keydown': this.videoControl.showControls,
+            'destroy': this.videoControl.destroy,
+            'initialize': this.videoControl.focusFirst
+        });
+
+        this.el.off('controls:show');
+        delete this.videoControl;
+    }
+
     // function _renderElements(state)
     //
     //     Create any necessary DOM elements, attach them, and set their initial configuration. Also
@@ -55,21 +59,7 @@ function () {
     //     way - you don't have to do repeated jQuery element selects.
     function _renderElements(state) {
         state.videoControl.el = state.el.find('.video-controls');
-        // state.videoControl.el.append(el);
-
-        state.videoControl.sliderEl            = state.videoControl.el.find('.slider');
-        state.videoControl.playPauseEl         = state.videoControl.el.find('.video_control');
-        state.videoControl.playPlaceholder     = state.el.find('.btn-play');
-        state.videoControl.secondaryControlsEl = state.videoControl.el.find('.secondary-controls');
-        state.videoControl.fullScreenEl        = state.videoControl.el.find('.add-fullscreen');
-        state.videoControl.vidTimeEl           = state.videoControl.el.find('.vidtime');
-
-        state.videoControl.fullScreenState = false;
-        state.videoControl.pause();
-
-        if (state.isTouch && state.videoType === 'html5') {
-            state.videoControl.showPlayPlaceholder();
-        }
+        state.videoControl.vidTimeEl = state.videoControl.el.find('.vidtime');
 
         if ((state.videoType === 'html5') && (state.config.autohideHtml5)) {
             state.videoControl.fadeOutTimeout = state.config.fadeOutTimeout;
@@ -77,62 +67,23 @@ function () {
             state.videoControl.el.addClass('html5');
             state.controlHideTimeout = setTimeout(state.videoControl.hideControls, state.videoControl.fadeOutTimeout);
         }
-
-        // ARIA
-        // Let screen readers know that this anchor, representing the slider
-        // handle, behaves as a slider named 'video slider'.
-        state.videoControl.sliderEl.find('.ui-slider-handle').attr({
-            'role': 'slider',
-            'title': gettext('Video slider')
-        });
-
-        state.videoControl.updateControlsHeight();
     }
 
     // function _bindHandlers(state)
     //
     //     Bind any necessary function callbacks to DOM events (click, mousemove, etc.).
     function _bindHandlers(state) {
-        state.videoControl.playPauseEl.on('click', state.videoControl.togglePlayback);
-        state.videoControl.fullScreenEl.on('click', state.videoControl.toggleFullScreenHandler);
-        state.el.on('fullscreen', function (event, isFullScreen) {
-            var height = state.videoControl.updateControlsHeight();
-
-            if (isFullScreen) {
-                state.resizer
-                    .delta
-                    .substract(height, 'height')
-                    .setMode('both');
-
-            } else {
-                state.resizer
-                    .delta
-                    .reset()
-                    .setMode('width');
-            }
-        });
-
-        $(document).on('keyup', state.videoControl.exitFullScreenHandler);
-
         if ((state.videoType === 'html5') && (state.config.autohideHtml5)) {
-            state.el.on('mousemove', state.videoControl.showControls);
-            state.el.on('keydown', state.videoControl.showControls);
+            state.el.on({
+                'mousemove': state.videoControl.showControls,
+                'keydown': state.videoControl.showControls
+            });
         }
-        // The state.previousFocus is used in video_speed_control to track
-        // the element that had the focus before it.
-        state.videoControl.playPauseEl.on('blur', function () {
-            state.previousFocus = 'playPause';
-        });
 
-        if (/iPad|Android/i.test(state.isTouch[0])) {
-            state.videoControl.playPlaceholder
-                .on('click', function () {
-                    state.trigger('videoPlayer.play', null);
-                });
+        if (state.config.focusFirstControl) {
+            state.el.on('initialize', state.videoControl.focusFirst);
         }
-    }
-    function _getControlsHeight(control) {
-        return control.el.height() + 0.5 * control.sliderEl.height();
+        state.el.on('destroy', state.videoControl.destroy);
     }
 
     // ***************************************************************
@@ -141,10 +92,8 @@ function () {
     // The magic private function that makes them available and sets up their context is makeFunctionsPublic().
     // ***************************************************************
 
-    function updateControlsHeight () {
-        this.videoControl.height = _getControlsHeight(this.videoControl);
-
-        return this.videoControl.height;
+    function focusFirst() {
+        this.videoControl.el.find('.vcr a, .vcr button').first().focus();
     }
 
     function show() {
@@ -171,13 +120,12 @@ function () {
             }
 
             this.controlHideTimeout = setTimeout(this.videoControl.hideControls, this.videoControl.fadeOutTimeout);
-
             this.controlShowLock = false;
         }
     }
 
     function hideControls() {
-        var _this;
+        var _this = this;
 
         this.controlHideTimeout = null;
 
@@ -186,12 +134,8 @@ function () {
         }
 
         this.controlState = 'hiding';
-
-        _this = this;
-
         this.videoControl.el.fadeOut(this.videoControl.fadeOutTimeout, function () {
             _this.controlState = 'invisible';
-
             // If the focus was on the video control or the volume control,
             // then we must make sure to close these dialogs. Otherwise, after
             // next autofocus, these dialogs will be open, but the focus will
@@ -203,98 +147,6 @@ function () {
         });
     }
 
-    function showPlayPlaceholder(event) {
-        this.videoControl.playPlaceholder
-            .removeClass('is-hidden')
-            .attr({
-                'aria-hidden': 'false',
-                'tabindex': 0
-            });
-    }
-
-    function hidePlayPlaceholder(event) {
-        this.videoControl.playPlaceholder
-            .addClass('is-hidden')
-            .attr({
-                'aria-hidden': 'true',
-                'tabindex': -1
-            });
-    }
-
-    function play() {
-        this.videoControl.isPlaying = true;
-        this.videoControl.playPauseEl
-            .removeClass('play')
-            .addClass('pause')
-            .attr('title', gettext('Pause'));
-
-        if (/iPad|Android/i.test(this.isTouch[0]) && this.videoType === 'html5') {
-            this.videoControl.hidePlayPlaceholder();
-        }
-    }
-
-    function pause() {
-        this.videoControl.isPlaying = false;
-        this.videoControl.playPauseEl
-            .removeClass('pause')
-            .addClass('play')
-            .attr('title', gettext('Play'));
-
-        if (/iPad|Android/i.test(this.isTouch[0]) && this.videoType === 'html5') {
-            this.videoControl.showPlayPlaceholder();
-        }
-    }
-
-    function togglePlayback(event) {
-        event.preventDefault();
-        this.videoCommands.execute('togglePlayback');
-    }
-
-    /**
-     * Event handler to toggle fullscreen mode.
-     * @param {jquery Event} event
-     */
-    function toggleFullScreenHandler(event) {
-        event.preventDefault();
-        this.videoCommands.execute('toggleFullScreen');
-    }
-
-    /** Toggle fullscreen mode. */
-    function toggleFullScreen() {
-        var fullScreenClassNameEl = this.el.add(document.documentElement),
-            win = $(window), text;
-
-        if (this.videoControl.fullScreenState) {
-            this.videoControl.fullScreenState = this.isFullScreen = false;
-            fullScreenClassNameEl.removeClass('video-fullscreen');
-            text = gettext('Fill browser');
-            win.scrollTop(this.scrollPos);
-        } else {
-            this.scrollPos = win.scrollTop();
-            win.scrollTop(0);
-            this.videoControl.fullScreenState = this.isFullScreen = true;
-            fullScreenClassNameEl.addClass('video-fullscreen');
-            text = gettext('Exit full browser');
-        }
-
-        this.videoControl.fullScreenEl
-            .attr('title', text)
-            .text(text);
-
-        this.el.trigger('fullscreen', [this.isFullScreen]);
-    }
-
-    /**
-     * Event handler to exit from fullscreen mode.
-     * @param {jquery Event} event
-     */
-    function exitFullScreenHandler(event) {
-        if ((this.isFullScreen) && (event.keyCode === 27)) {
-            event.preventDefault();
-            this.videoCommands.execute('toggleFullScreen');
-        }
-    }
-
     function updateVcrVidTime(params) {
         var endTime = (this.config.endTime !== null) ? this.config.endTime : params.duration;
         // in case endTime is accidentally specified as being greater than the video
diff --git a/common/lib/xmodule/xmodule/js/src/video/04_video_full_screen.js b/common/lib/xmodule/xmodule/js/src/video/04_video_full_screen.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5618520579b2314cb92423a591980f50e7ae373
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/04_video_full_screen.js
@@ -0,0 +1,175 @@
+(function (define) {
+'use strict';
+define('video/04_video_full_screen.js', [], function () {
+    var template = [
+        '<a href="#" class="add-fullscreen" title="',
+            gettext('Fill browser'), '" role="button" aria-disabled="false">',
+            gettext('Fill browser'),
+        '</a>'
+    ].join('');
+
+    // VideoControl() function - what this module "exports".
+    return function (state) {
+        var dfd = $.Deferred();
+
+        state.videoFullScreen = {};
+
+        _makeFunctionsPublic(state);
+        _renderElements(state);
+        _bindHandlers(state);
+
+        dfd.resolve();
+        return dfd.promise();
+    };
+
+    // ***************************************************************
+    // Private functions start here.
+    // ***************************************************************
+
+    // function _makeFunctionsPublic(state)
+    //
+    //     Functions which will be accessible via 'state' object. When called, these functions will
+    //     get the 'state' object as a context.
+    function _makeFunctionsPublic(state) {
+        var methodsDict = {
+            destroy: destroy,
+            enter: enter,
+            exitHandler: exitHandler,
+            exit: exit,
+            onFullscreenChange: onFullscreenChange,
+            toggle: toggle,
+            toggleHandler: toggleHandler,
+            updateControlsHeight: updateControlsHeight
+        };
+
+        state.bindTo(methodsDict, state.videoFullScreen, state);
+    }
+
+    function destroy() {
+        $(document).off('keyup', this.videoFullScreen.exitHandler);
+        this.videoFullScreen.fullScreenEl.remove();
+        this.el.off({
+            'fullscreen': this.videoFullScreen.onFullscreenChange,
+            'destroy': this.videoFullScreen.destroy
+        });
+        if (this.isFullScreen) {
+            this.videoFullScreen.exit();
+        }
+        delete this.videoFullScreen;
+    }
+
+    // function _renderElements(state)
+    //
+    //     Create any necessary DOM elements, attach them, and set their initial configuration. Also
+    //     make the created DOM elements available via the 'state' object. Much easier to work this
+    //     way - you don't have to do repeated jQuery element selects.
+    function _renderElements(state) {
+        state.videoFullScreen.fullScreenEl = $(template);
+        state.videoFullScreen.sliderEl = state.el.find('.slider');
+        state.videoFullScreen.fullScreenState = false;
+        state.el.find('.secondary-controls').append(state.videoFullScreen.fullScreenEl);
+        state.videoFullScreen.updateControlsHeight();
+    }
+
+    // function _bindHandlers(state)
+    //
+    //     Bind any necessary function callbacks to DOM events (click, mousemove, etc.).
+    function _bindHandlers(state) {
+        state.videoFullScreen.fullScreenEl.on('click', state.videoFullScreen.toggleHandler);
+        state.el.on({
+            'fullscreen': state.videoFullScreen.onFullscreenChange,
+            'destroy': state.videoFullScreen.destroy
+        });
+        $(document).on('keyup', state.videoFullScreen.exitHandler);
+    }
+
+    function _getControlsHeight(controls, slider) {
+        return controls.height() + 0.5 * slider.height();
+    }
+
+    // ***************************************************************
+    // Public functions start here.
+    // These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
+    // The magic private function that makes them available and sets up their context is makeFunctionsPublic().
+    // ***************************************************************
+
+    function onFullscreenChange (event, isFullScreen) {
+        var height = this.videoFullScreen.updateControlsHeight();
+
+        if (isFullScreen) {
+            this.resizer
+                .delta
+                .substract(height, 'height')
+                .setMode('both');
+
+        } else {
+            this.resizer
+                .delta
+                .reset()
+                .setMode('width');
+        }
+    }
+
+    function updateControlsHeight() {
+        var controls = this.el.find('.video-controls'),
+            slider = this.videoFullScreen.sliderEl;
+        this.videoFullScreen.height = _getControlsHeight(controls, slider);
+        return this.videoFullScreen.height;
+    }
+
+    /**
+     * Event handler to toggle fullscreen mode.
+     * @param {jquery Event} event
+     */
+    function toggleHandler(event) {
+        event.preventDefault();
+        this.videoCommands.execute('toggleFullScreen');
+    }
+
+    function exit() {
+        var fullScreenClassNameEl = this.el.add(document.documentElement);
+
+        this.videoFullScreen.fullScreenState = this.isFullScreen = false;
+        fullScreenClassNameEl.removeClass('video-fullscreen');
+        $(window).scrollTop(this.scrollPos);
+        this.videoFullScreen.fullScreenEl
+            .attr('title', gettext('Fill browser'))
+            .text(gettext('Fill browser'));
+        this.el.trigger('fullscreen', [this.isFullScreen]);
+    }
+
+    function enter() {
+        var fullScreenClassNameEl = this.el.add(document.documentElement);
+
+        this.scrollPos = $(window).scrollTop();
+        $(window).scrollTop(0);
+        this.videoFullScreen.fullScreenState = this.isFullScreen = true;
+        fullScreenClassNameEl.addClass('video-fullscreen');
+        this.videoFullScreen.fullScreenEl
+            .attr('title', gettext('Exit full browser'))
+            .text(gettext('Exit full browser'));
+        this.el.trigger('fullscreen', [this.isFullScreen]);
+    }
+
+    /** Toggle fullscreen mode. */
+    function toggle() {
+        if (this.videoFullScreen.fullScreenState) {
+            this.videoFullScreen.exit();
+        } else {
+            this.videoFullScreen.enter();
+        }
+    }
+
+    /**
+     * Event handler to exit from fullscreen mode.
+     * @param {jquery Event} event
+     */
+    function exitHandler(event) {
+        if ((this.isFullScreen) && (event.keyCode === 27)) {
+            event.preventDefault();
+            this.videoCommands.execute('toggleFullScreen');
+        }
+    }
+});
+
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/05_video_quality_control.js b/common/lib/xmodule/xmodule/js/src/video/05_video_quality_control.js
index 03eb4ccad01e94f003580db05d0a788bbc1a8bad..11965fe31e71417261f2b822060e2ccf97fae89d 100644
--- a/common/lib/xmodule/xmodule/js/src/video/05_video_quality_control.js
+++ b/common/lib/xmodule/xmodule/js/src/video/05_video_quality_control.js
@@ -5,6 +5,12 @@ define(
 'video/05_video_quality_control.js',
 [],
 function () {
+    var template = [
+        '<a href="#" class="quality-control is-hidden" title="',
+            gettext('HD off'), '" role="button" aria-disabled="false">',
+            gettext('HD off'),
+        '</a>'
+    ].join('');
 
     // VideoQualityControl() function - what this module "exports".
     return function (state) {
@@ -12,7 +18,6 @@ function () {
 
         // Changing quality for now only works for YouTube videos.
         if (state.videoType !== 'youtube') {
-            state.el.find('a.quality-control').remove();
             return;
         }
 
@@ -36,6 +41,7 @@ function () {
     //     get the 'state' object as a context.
     function _makeFunctionsPublic(state) {
         var methodsDict = {
+            destroy: destroy,
             fetchAvailableQualities: fetchAvailableQualities,
             onQualityChange: onQualityChange,
             showQualityControl: showQualityControl,
@@ -45,16 +51,25 @@ function () {
         state.bindTo(methodsDict, state.videoQualityControl, state);
     }
 
+    function destroy() {
+        this.videoQualityControl.el.off({
+            'click': this.videoQualityControl.toggleQuality,
+            'destroy': this.videoQualityControl.destroy
+        });
+        this.el.off('.quality');
+        this.videoQualityControl.el.remove();
+        delete this.videoQualityControl;
+    }
+
     // function _renderElements(state)
     //
     //     Create any necessary DOM elements, attach them, and set their initial configuration. Also
     //     make the created DOM elements available via the 'state' object. Much easier to work this
     //     way - you don't have to do repeated jQuery element selects.
     function _renderElements(state) {
-        state.videoQualityControl.el = state.el.find('a.quality-control');
-
-        state.videoQualityControl.el.show();
+        var element = state.videoQualityControl.el = $(template);
         state.videoQualityControl.quality = 'large';
+        state.el.find('.secondary-controls').append(element);
     }
 
     // function _bindHandlers(state)
@@ -64,9 +79,11 @@ function () {
         state.videoQualityControl.el.on('click',
             state.videoQualityControl.toggleQuality
         );
-        state.el.on('play', _.once(
+        state.el.on('play.quality', _.once(
             state.videoQualityControl.fetchAvailableQualities
         ));
+
+        state.el.on('destroy.quality', state.videoQualityControl.destroy);
     }
 
     // ***************************************************************
@@ -141,7 +158,7 @@ function () {
         event.preventDefault();
 
         newQuality = isHD ? 'large' : 'highres';
-        
+
         this.trigger('videoPlayer.handlePlaybackQualityChange', newQuality);
     }
 
diff --git a/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js b/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js
index 61da5b7ce094c0c70a18adf37784064555fe1885..d5c5439e47a2df23f86da6170254a5c5b8e16c84 100644
--- a/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js
+++ b/common/lib/xmodule/xmodule/js/src/video/06_video_progress_slider.js
@@ -12,15 +12,17 @@ define(
 'video/06_video_progress_slider.js',
 [],
 function () {
+    var template = [
+        '<div class="slider" title="', gettext('Video position'), '"></div>'
+    ].join('');
+
     // VideoProgressSlider() function - what this module "exports".
     return function (state) {
         var dfd = $.Deferred();
 
         state.videoProgressSlider = {};
-
         _makeFunctionsPublic(state);
         _renderElements(state);
-        // No callbacks to DOM events (click, mousemove, etc.).
 
         dfd.resolve();
         return dfd.promise();
@@ -36,6 +38,7 @@ function () {
     //     these functions will get the 'state' object as a context.
     function _makeFunctionsPublic(state) {
         var methodsDict = {
+            destroy: destroy,
             buildSlider: buildSlider,
             getRangeParams: getRangeParams,
             onSlide: onSlide,
@@ -49,6 +52,12 @@ function () {
         state.bindTo(methodsDict, state.videoProgressSlider, state);
     }
 
+    function destroy() {
+        this.videoProgressSlider.el.removeAttr('tabindex').slider('destroy');
+        this.el.off('destroy', this.videoProgressSlider.destroy);
+        delete this.videoProgressSlider;
+    }
+
     // function _renderElements(state)
     //
     //     Create any necessary DOM elements, attach them, and set their
@@ -56,8 +65,9 @@ function () {
     //     via the 'state' object. Much easier to work this way - you don't
     //     have to do repeated jQuery element selects.
     function _renderElements(state) {
-        state.videoProgressSlider.el = state.videoControl.sliderEl;
+        state.videoProgressSlider.el = $(template);
 
+        state.el.find('.video-controls').prepend(state.videoProgressSlider.el);
         state.videoProgressSlider.buildSlider();
         _buildHandle(state);
     }
@@ -81,6 +91,8 @@ function () {
             'aria-valuemin': '0',
             'aria-valuenow': state.videoPlayer.currentTime
         });
+
+        state.el.on('destroy', state.videoProgressSlider.destroy);
     }
 
     // ***************************************************************
@@ -109,7 +121,7 @@ function () {
     // whole slider). Remember that endTime === null means the end-time
     // is set to the end of video by default.
     function updateStartEndTimeRegion(params) {
-        var left, width, start, end, duration, rangeParams;
+        var start, end, duration, rangeParams;
 
         // We must have a duration in order to determine the area of range.
         // It also must be non-zero.
diff --git a/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js b/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js
index 646fe8e732a73bd12b4d72cb81ff452106e83374..7177ee9215a42d61ee4e8b3bcab457af0069e900 100644
--- a/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js
+++ b/common/lib/xmodule/xmodule/js/src/video/07_video_volume_control.js
@@ -17,6 +17,10 @@ function() {
             return new VolumeControl(state, i18n);
         }
 
+        _.bindAll(this, 'keyDownHandler', 'updateVolumeSilently',
+            'onVolumeChangeHandler', 'openMenu', 'closeMenu',
+            'toggleMuteHandler', 'keyDownButtonHandler', 'destroy'
+        );
         this.state = state;
         this.state.videoVolumeControl = this;
         this.i18n = i18n;
@@ -33,17 +37,55 @@ function() {
         /** Step to increase/decrease volume level via keyboard. */
         step: 20,
 
+        template: [
+            '<div class="volume">',
+                '<a href="#" role="button" aria-disabled="false" title="',
+                    gettext('Volume'), '" aria-label="',
+                    gettext('Click on this button to mute or unmute this video or press UP or DOWN buttons to increase or decrease volume level.'),
+                    '"></a>',
+                '<div role="presentation" class="volume-slider-container">',
+                    '<div class="volume-slider"></div>',
+                '</div>',
+            '</div>'
+        ].join(''),
+
+        destroy: function () {
+            this.volumeSlider.slider('destroy');
+            this.state.el.find('iframe').removeAttr('tabindex');
+            this.a11y.destroy();
+            this.cookie = this.a11y = null;
+            this.closeMenu();
+
+            this.state.el
+                .off('play.volume')
+                .off({
+                    'keydown': this.keyDownHandler,
+                    'volumechange': this.onVolumeChangeHandler
+                });
+            this.el.off({
+                'mouseenter': this.openMenu,
+                'mouseleave': this.closeMenu
+            });
+            this.button.off({
+                'mousedown': this.toggleMuteHandler,
+                'keydown': this.keyDownButtonHandler,
+                'focus': this.openMenu,
+                'blur': this.closeMenu
+            });
+            this.el.remove();
+            delete this.state.videoVolumeControl;
+        },
+
         /** Initializes the module. */
         initialize: function() {
             var volume;
 
-            this.el = this.state.el.find('.volume');
-
             if (this.state.isTouch) {
                 // iOS doesn't support volume change
-                this.el.remove();
                 return false;
             }
+
+            this.el = $(this.template);
             // Youtube iframe react on key buttons and has his own handlers.
             // So, we disallow focusing on iframe.
             this.state.el.find('iframe').attr('tabindex', -1);
@@ -80,26 +122,28 @@ function() {
             // Therefore, we do not need redundant focusing on slider in TAB
             // order.
             container.find('a').attr('tabindex', -1);
+            this.state.el.find('.secondary-controls').append(this.el);
         },
 
         /** Bind any necessary function callbacks to DOM events. */
         bindHandlers: function() {
             this.state.el.on({
-                'keydown': this.keyDownHandler.bind(this),
-                'play': _.once(this.updateVolumeSilently.bind(this)),
-                'volumechange': this.onVolumeChangeHandler.bind(this)
+                'keydown': this.keyDownHandler,
+                'play.volume': _.once(this.updateVolumeSilently),
+                'volumechange': this.onVolumeChangeHandler
             });
             this.el.on({
-                'mouseenter': this.openMenu.bind(this),
-                'mouseleave': this.closeMenu.bind(this)
+                'mouseenter': this.openMenu,
+                'mouseleave': this.closeMenu
             });
             this.button.on({
                 'click': false,
-                'mousedown': this.toggleMuteHandler.bind(this),
-                'keydown': this.keyDownButtonHandler.bind(this),
-                'focus': this.openMenu.bind(this),
-                'blur': this.closeMenu.bind(this)
+                'mousedown': this.toggleMuteHandler,
+                'keydown': this.keyDownButtonHandler,
+                'focus': this.openMenu,
+                'blur': this.closeMenu
             });
+            this.state.el.on('destroy', this.destroy);
         },
 
         /**
@@ -343,6 +387,10 @@ function() {
     };
 
     Accessibility.prototype = {
+        destroy: function () {
+            this.liveRegion.remove();
+        },
+
         /** Initializes the module. */
         initialize: function() {
             this.liveRegion = $('<div />', {
diff --git a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
index 8f4b95d36df60af62395d5cc7912fd1766c76bfc..c813cb48ab6e6666439d1d0ac59b87e718319de3 100644
--- a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
+++ b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
@@ -16,6 +16,10 @@ function (Iterator) {
             return new SpeedControl(state);
         }
 
+        _.bindAll(this, 'onSetSpeed', 'onRenderSpeed', 'clickLinkHandler',
+            'keyDownLinkHandler', 'mouseEnterHandler', 'mouseLeaveHandler',
+            'clickMenuHandler', 'keyDownMenuHandler', 'destroy'
+        );
         this.state = state;
         this.state.videoSpeedControl = this;
         this.initialize();
@@ -24,24 +28,51 @@ function (Iterator) {
     };
 
     SpeedControl.prototype = {
+        template: [
+            '<div class="speeds menu-container">',
+                '<a class="speed-button" href="#" title="',
+                    gettext('Speeds'), '" role="button" aria-disabled="false">',
+                    '<span class="label">', gettext('Speed'), '</span>',
+                    '<span class="value"></span>',
+                '</a>',
+              '<ol class="video-speeds menu" role="menu"></ol>',
+            '</div>'
+        ].join(''),
+
+        destroy: function () {
+            this.el.off({
+                'mouseenter': this.mouseEnterHandler,
+                'mouseleave': this.mouseLeaveHandler,
+                'click': this.clickMenuHandler,
+                'keydown': this.keyDownMenuHandler
+            });
+
+            this.state.el.off({
+                'speed:set': this.onSetSpeed,
+                'speed:render': this.onRenderSpeed
+            });
+            this.closeMenu(true);
+            this.speedsContainer.remove();
+            this.el.remove();
+            delete this.state.videoSpeedControl;
+        },
+
         /** Initializes the module. */
         initialize: function () {
             var state = this.state;
 
-            this.el = state.el.find('.speeds');
-            this.speedsContainer = this.el.find('.video-speeds');
-            this.speedButton = this.el.find('.speed-button');
-
             if (!this.isPlaybackRatesSupported(state)) {
-                this.el.remove();
                 console.log(
                     '[Video info]: playbackRate is not supported.'
                 );
 
                 return false;
             }
-
+            this.el = $(this.template);
+            this.speedsContainer = this.el.find('.video-speeds');
+            this.speedButton = this.el.find('.speed-button');
             this.render(state.speeds, state.speed);
+            this.setSpeed(state.speed, true, true);
             this.bindHandlers();
 
             return true;
@@ -51,13 +82,11 @@ function (Iterator) {
          * Creates any necessary DOM elements, attach them, and set their,
          * initial configuration.
          * @param {array} speeds List of speeds available for the player.
-         * @param {string|number} currentSpeed Current speed for the player.
          */
-        render: function (speeds, currentSpeed) {
-            var self = this,
-                speedsContainer = this.speedsContainer,
+        render: function (speeds) {
+            var speedsContainer = this.speedsContainer,
                 reversedSpeeds = speeds.concat().reverse(),
-                speedsList = $.map(reversedSpeeds, function (speed, index) {
+                speedsList = $.map(reversedSpeeds, function (speed) {
                     return [
                         '<li data-speed="', speed, '" role="presentation">',
                             '<a class="speed-link" href="#" role="menuitem" tabindex="-1">',
@@ -69,7 +98,7 @@ function (Iterator) {
 
             speedsContainer.html(speedsList.join(''));
             this.speedLinks = new Iterator(speedsContainer.find('.speed-link'));
-            this.setSpeed(currentSpeed, true, true);
+            this.state.el.find('.secondary-controls').prepend(this.el);
         },
 
         /**
@@ -77,31 +106,34 @@ function (Iterator) {
          * mousemove, etc.).
          */
         bindHandlers: function () {
-            var self = this;
-
             // Attach various events handlers to the speed menu button.
             this.el.on({
-                'mouseenter': this.mouseEnterHandler.bind(this),
-                'mouseleave': this.mouseLeaveHandler.bind(this),
-                'click': this.clickMenuHandler.bind(this),
-                'keydown': this.keyDownMenuHandler.bind(this)
+                'mouseenter': this.mouseEnterHandler,
+                'mouseleave': this.mouseLeaveHandler,
+                'click': this.clickMenuHandler,
+                'keydown': this.keyDownMenuHandler
             });
 
             // Attach click and keydown event handlers to the individual speed
             // entries.
             this.speedsContainer.on({
-                click: this.clickLinkHandler.bind(this),
-                keydown: this.keyDownLinkHandler.bind(this)
+                click: this.clickLinkHandler,
+                keydown: this.keyDownLinkHandler
             }, 'a.speed-link');
 
             this.state.el.on({
-                'speed:set': function (event, speed) {
-                    self.setSpeed(speed, true);
-                },
-                'speed:render': function (event, speeds, currentSpeed) {
-                    self.render(speeds, currentSpeed);
-                }
+                'speed:set': this.onSetSpeed,
+                'speed:render': this.onRenderSpeed
             });
+            this.state.el.on('destroy', this.destroy);
+        },
+
+        onSetSpeed: function (event, speed) {
+            this.setSpeed(speed, true);
+        },
+
+        onRenderSpeed: function (event, speeds, currentSpeed) {
+            this.render(speeds, currentSpeed);
         },
 
         /**
@@ -133,7 +165,7 @@ function (Iterator) {
             // element to have clicks close the menu when they happen
             // outside of it.
             if (bindEvent) {
-                $(window).on('click.speedMenu', this.clickMenuHandler.bind(this));
+                $(window).on('click.speedMenu', this.clickMenuHandler);
             }
 
             this.el.addClass('is-opened');
@@ -175,7 +207,7 @@ function (Iterator) {
                 this.currentSpeed = speed;
 
                 if (!silent) {
-                    this.el.trigger('speedchange', [speed]);
+                    this.el.trigger('speedchange', [speed, this.state.speed]);
                 }
             }
         },
diff --git a/common/lib/xmodule/xmodule/js/src/video/095_video_context_menu.js b/common/lib/xmodule/xmodule/js/src/video/095_video_context_menu.js
index 33fbfa752bd77f625c76fcad8858e7edd93ba023..951f2a639e966a89e6f388fff166ec0f8b66e5d0 100644
--- a/common/lib/xmodule/xmodule/js/src/video/095_video_context_menu.js
+++ b/common/lib/xmodule/xmodule/js/src/video/095_video_context_menu.js
@@ -656,6 +656,12 @@ function (Component) {
 
         if (!state.isYoutubeType()) {
             state.el.find('video').contextmenu(state.el, options);
+            state.el.on('destroy', function () {
+                var contextmenu = $(this).find('video').data('contextmenu');
+                if (contextmenu) {
+                    contextmenu.destroy();
+                }
+            });
         }
 
         return $.Deferred().resolve().promise();
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_bumper.js b/common/lib/xmodule/xmodule/js/src/video/09_bumper.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c3ee16929187c39c1f2f1bf4fe318fcbbd9c7ae
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_bumper.js
@@ -0,0 +1,109 @@
+(function (define) {
+'use strict';
+define('video/09_bumper.js',[], function () {
+    /**
+     * VideoBumper module.
+     * @exports video/09_bumper.js
+     * @constructor
+     * @param {Object} player The player factory.
+     * @param {Object} state The object containing the state of the video
+     * @return {jquery Promise}
+     */
+    var VideoBumper = function (player, state) {
+        if (!(this instanceof VideoBumper)) {
+            return new VideoBumper(player, state);
+        }
+
+        _.bindAll(
+            this, 'showMainVideoHandler', 'destroy', 'skipByDuration', 'destroyAndResolve'
+        );
+        this.dfd = $.Deferred();
+        this.element = state.el;
+        this.element.addClass('is-bumper');
+        this.player = player;
+        this.state = state;
+        this.doNotShowAgain = false;
+        this.state.videoBumper = this;
+        this.bindHandlers();
+        this.initialize();
+        this.maxBumperDuration = 35; // seconds
+    };
+
+    VideoBumper.prototype = {
+        initialize: function () {
+            this.player();
+        },
+
+        getPromise: function () {
+            return this.dfd.promise();
+        },
+
+        showMainVideoHandler: function () {
+            this.state.storage.setItem('isBumperShown', true);
+            setTimeout(function () {
+                this.saveState();
+                this.showMainVideo();
+            }.bind(this), 20);
+        },
+
+        destroyAndResolve: function () {
+            this.destroy();
+            this.dfd.resolve();
+        },
+
+        showMainVideo: function () {
+            if (this.state.videoPlayer) {
+                this.destroyAndResolve();
+            } else {
+                this.state.el.on('initialize', this.destroyAndResolve);
+            }
+        },
+
+        skip: function () {
+            this.element.trigger('skip', [this.doNotShowAgain]);
+            this.showMainVideoHandler();
+        },
+
+        skipAndDoNotShowAgain: function () {
+            this.doNotShowAgain = true;
+            this.skip();
+        },
+
+        skipByDuration: function (event, time) {
+            if (time > this.maxBumperDuration) {
+                this.element.trigger('ended');
+            }
+        },
+
+        bindHandlers: function () {
+            var events = ['ended', 'error'].join(' ');
+            this.element.on(events, this.showMainVideoHandler);
+            this.element.on('timeupdate', this.skipByDuration);
+        },
+
+        saveState: function () {
+            var info = {bumper_last_view_date: true};
+            if (this.doNotShowAgain) {
+                _.extend(info, {bumper_do_not_show_again: true});
+            }
+            this.state.videoSaveStatePlugin.saveState(true, info);
+        },
+
+        destroy: function () {
+            var events = ['ended', 'error'].join(' ');
+            this.element.off(events, this.showMainVideoHandler);
+            this.element.off({
+                'timeupdate': this.skipByDuration,
+                'initialize': this.destroyAndResolve
+            });
+            this.element.removeClass('is-bumper');
+            if (_.isFunction(this.state.videoPlayer.destroy)) {
+                this.state.videoPlayer.destroy();
+            }
+            delete this.state.videoBumper;
+        }
+    };
+
+    return VideoBumper;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_events_bumper_plugin.js b/common/lib/xmodule/xmodule/js/src/video/09_events_bumper_plugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e18332eb238f02873dc00a7ad794f455ca84345
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_events_bumper_plugin.js
@@ -0,0 +1,112 @@
+(function(define) {
+'use strict';
+define('video/09_events_bumper_plugin.js', [], function() {
+    /**
+     * Events module.
+     * @exports video/09_events_bumper_plugin.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @param {Object} options
+     * @return {jquery Promise}
+     */
+    var EventsBumperPlugin = function(state, i18n, options) {
+        if (!(this instanceof EventsBumperPlugin)) {
+            return new EventsBumperPlugin(state, i18n, options);
+        }
+
+        _.bindAll(this, 'onReady', 'onPlay', 'onEnded', 'onShowLanguageMenu', 'onHideLanguageMenu', 'onSkip',
+            'onShowCaptions', 'onHideCaptions', 'destroy');
+        this.state = state;
+        this.options = _.extend({}, options);
+        this.state.videoEventsBumperPlugin = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    EventsBumperPlugin.moduleName = 'EventsBumperPlugin';
+    EventsBumperPlugin.prototype = {
+        destroy: function () {
+            this.state.el.off(this.events);
+            delete this.state.videoEventsBumperPlugin;
+        },
+
+        initialize: function() {
+            this.events = {
+                'ready': this.onReady,
+                'play': this.onPlay,
+                'ended stop': this.onEnded,
+                'skip': this.onSkip,
+                'language_menu:show': this.onShowLanguageMenu,
+                'language_menu:hide': this.onHideLanguageMenu,
+                'captions:show': this.onShowCaptions,
+                'captions:hide': this.onHideCaptions,
+                'destroy': this.destroy
+            };
+            this.bindHandlers();
+        },
+
+        bindHandlers: function() {
+            this.state.el.on(this.events);
+        },
+
+        onReady: function () {
+            this.log('edx.video.bumper.loaded');
+        },
+
+        onPlay: function () {
+            this.log('edx.video.bumper.played', {currentTime: this.getCurrentTime()});
+        },
+
+        onEnded: function () {
+            this.log('edx.video.bumper.stopped', {currentTime: this.getCurrentTime()});
+        },
+
+        onSkip: function (event, doNotShowAgain) {
+            var info = {currentTime: this.getCurrentTime()},
+                eventName = 'edx.video.bumper.' + (doNotShowAgain ? 'dismissed': 'skipped');
+            this.log(eventName, info);
+        },
+
+        onShowLanguageMenu: function () {
+            this.log('edx.video.bumper.transcript.menu.shown');
+        },
+
+        onHideLanguageMenu: function () {
+            this.log('edx.video.bumper.transcript.menu.hidden');
+        },
+
+        onShowCaptions: function () {
+            this.log('edx.video.bumper.transcript.shown', {currentTime: this.getCurrentTime()});
+        },
+
+        onHideCaptions: function () {
+            this.log('edx.video.bumper.transcript.hidden', {currentTime: this.getCurrentTime()});
+        },
+
+        getCurrentTime: function () {
+            var player = this.state.videoPlayer;
+            return player ? player.currentTime : 0;
+        },
+
+        getDuration: function () {
+            var player = this.state.videoPlayer;
+            return player ? player.duration() : 0;
+        },
+
+        log: function (eventName, data) {
+            var logInfo = _.extend({
+                host_component_id: this.state.id,
+                bumper_id: this.state.config.sources[0] || '',
+                duration: this.getDuration(),
+                code: 'html5'
+            }, data, this.options.data);
+            Logger.log(eventName, logInfo);
+        }
+    };
+
+    return EventsBumperPlugin;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_events_plugin.js b/common/lib/xmodule/xmodule/js/src/video/09_events_plugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..bf25c7f92d902e6cb7c61cb458facd37679d6e33
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_events_plugin.js
@@ -0,0 +1,129 @@
+(function(define) {
+'use strict';
+define('video/09_events_plugin.js', [], function() {
+    /**
+     * Events module.
+     * @exports video/09_events_plugin.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @param {Object} options
+     * @return {jquery Promise}
+     */
+    var EventsPlugin = function(state, i18n, options) {
+        if (!(this instanceof EventsPlugin)) {
+            return new EventsPlugin(state, i18n, options);
+        }
+
+        _.bindAll(this, 'onReady', 'onPlay', 'onPause', 'onEnded', 'onSeek',
+            'onSpeedChange', 'onShowLanguageMenu', 'onHideLanguageMenu', 'onSkip',
+            'onShowCaptions', 'onHideCaptions', 'destroy');
+        this.state = state;
+        this.options = _.extend({}, options);
+        this.state.videoEventsPlugin = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    EventsPlugin.moduleName = 'EventsPlugin';
+    EventsPlugin.prototype = {
+        destroy: function () {
+            this.state.el.off(this.events);
+            delete this.state.videoEventsPlugin;
+        },
+
+        initialize: function() {
+            this.events = {
+                'ready': this.onReady,
+                'play': this.onPlay,
+                'pause': this.onPause,
+                'ended stop': this.onEnded,
+                'seek': this.onSeek,
+                'skip': this.onSkip,
+                'speedchange': this.onSpeedChange,
+                'language_menu:show': this.onShowLanguageMenu,
+                'language_menu:hide': this.onHideLanguageMenu,
+                'captions:show': this.onShowCaptions,
+                'captions:hide': this.onHideCaptions,
+                'destroy': this.destroy
+            };
+            this.bindHandlers();
+        },
+
+        bindHandlers: function() {
+            this.state.el.on(this.events);
+        },
+
+        onReady: function () {
+            this.log('load_video');
+        },
+
+        onPlay: function () {
+            this.log('play_video', {currentTime: this.getCurrentTime()});
+        },
+
+        onPause: function () {
+            this.log('pause_video', {currentTime: this.getCurrentTime()});
+        },
+
+        onEnded: function () {
+            this.log('stop_video', {currentTime: this.getCurrentTime()});
+        },
+
+        onSkip: function (event, doNotShowAgain) {
+            var info = {currentTime: this.getCurrentTime()},
+                eventName = doNotShowAgain ? 'do_not_show_again_video': 'skip_video';
+            this.log(eventName, info);
+        },
+
+        onSeek: function (event, time, oldTime, type) {
+            this.log('seek_video', {
+                old_time: oldTime,
+                new_time: time,
+                type: type
+            });
+        },
+
+        onSpeedChange: function (event, newSpeed, oldSpeed) {
+            this.log('speed_change_video', {
+                current_time: this.getCurrentTime(),
+                old_speed: oldSpeed,
+                new_speed: newSpeed
+            });
+        },
+
+        onShowLanguageMenu: function () {
+            this.log('video_show_cc_menu');
+        },
+
+        onHideLanguageMenu: function () {
+            this.log('video_hide_cc_menu');
+        },
+
+        onShowCaptions: function () {
+            this.log('show_transcript', {current_time: this.getCurrentTime()});
+        },
+
+        onHideCaptions: function () {
+            this.log('hide_transcript', {current_time: this.getCurrentTime()});
+        },
+
+        getCurrentTime: function () {
+            var player = this.state.videoPlayer;
+            return player ? player.currentTime : 0;
+        },
+
+        log: function (eventName, data) {
+            var logInfo = _.extend({
+                id: this.state.id,
+                code: this.state.isYoutubeType() ? this.state.youtubeId() : 'html5'
+            }, data, this.options.data);
+            Logger.log(eventName, logInfo);
+        }
+    };
+
+    return EventsPlugin;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_play_pause_control.js b/common/lib/xmodule/xmodule/js/src/video/09_play_pause_control.js
new file mode 100644
index 0000000000000000000000000000000000000000..201c50c4728ebecbde97ff65ad47ae829ed92bf6
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_play_pause_control.js
@@ -0,0 +1,87 @@
+(function(define) {
+'use strict';
+define('video/09_play_pause_control.js', [], function() {
+    /**
+     * Play/pause control module.
+     * @exports video/09_play_pause_control.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @return {jquery Promise}
+     */
+    var PlayPauseControl = function(state, i18n) {
+        if (!(this instanceof PlayPauseControl)) {
+            return new PlayPauseControl(state, i18n);
+        }
+
+        _.bindAll(this, 'play', 'pause', 'onClick', 'destroy');
+        this.state = state;
+        this.state.videoPlayPauseControl = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    PlayPauseControl.prototype = {
+        template: [
+            '<a class="video_control play" href="#" title="',
+                gettext('Play'), '" role="button" aria-disabled="false">',
+                gettext('Play'),
+            '</a>'
+        ].join(''),
+
+        destroy: function () {
+            this.el.remove();
+            this.state.el.off('destroy', this.destroy);
+            delete this.state.videoPlayPauseControl;
+        },
+
+        /** Initializes the module. */
+        initialize: function() {
+            this.el = $(this.template);
+            this.render();
+            this.bindHandlers();
+        },
+
+        /**
+         * Creates any necessary DOM elements, attach them, and set their,
+         * initial configuration.
+         */
+        render: function() {
+            this.state.el.find('.vcr').prepend(this.el);
+        },
+
+        /** Bind any necessary function callbacks to DOM events. */
+        bindHandlers: function() {
+            this.el.on({
+                'click': this.onClick
+            });
+            this.state.el.on({
+                'play': this.play,
+                'pause ended': this.pause,
+                'destroy': this.destroy
+            });
+        },
+
+        onClick: function (event) {
+            event.preventDefault();
+            this.state.videoCommands.execute('togglePlayback');
+        },
+
+        play: function () {
+            this.el
+                .attr('title', this.i18n['Pause']).text(this.i18n['Pause'])
+                .removeClass('play').addClass('pause');
+        },
+
+        pause: function () {
+            this.el
+                .attr('title', this.i18n['Play']).text(this.i18n['Play'])
+                .removeClass('pause').addClass('play');
+        }
+    };
+
+    return PlayPauseControl;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_play_placeholder.js b/common/lib/xmodule/xmodule/js/src/video/09_play_placeholder.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcd20dabbfed8a6a6c0718cea4f1271754ab656e
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_play_placeholder.js
@@ -0,0 +1,87 @@
+(function(define) {
+'use strict';
+define('video/09_play_placeholder.js', [], function() {
+    /**
+     * Play placeholder control module.
+     * @exports video/09_play_placeholder.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @return {jquery Promise}
+     */
+    var PlayPlaceholder = function(state, i18n) {
+        if (!(this instanceof PlayPlaceholder)) {
+            return new PlayPlaceholder(state, i18n);
+        }
+
+        _.bindAll(this, 'onClick', 'hide', 'show', 'destroy');
+        this.state = state;
+        this.state.videoPlayPlaceholder = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    PlayPlaceholder.prototype = {
+        destroy: function () {
+            this.el.off('click', this.onClick);
+            this.state.el.on({
+                'destroy': this.destroy,
+                'play': this.hide,
+                'ended pause': this.show
+            });
+            this.hide();
+            delete this.state.videoPlayPlaceholder;
+        },
+
+        /**
+         * Indicates whether the placeholder should be shown. We display it
+         * for html5 videos on iPad and Android devices.
+         * @return {Boolean}
+         */
+        shouldBeShown: function () {
+            return /iPad|Android/i.test(this.state.isTouch[0]) && !this.state.isYoutubeType();
+        },
+
+        /** Initializes the module. */
+        initialize: function() {
+            if (!this.shouldBeShown()) {
+                return false;
+            }
+
+            this.el = this.state.el.find('.btn-play');
+            this.bindHandlers();
+            this.show();
+        },
+
+        /** Bind any necessary function callbacks to DOM events. */
+        bindHandlers: function() {
+            this.el.on('click', this.onClick);
+            this.state.el.on({
+                'destroy': this.destroy,
+                'play': this.hide,
+                'ended pause': this.show
+            });
+        },
+
+        onClick: function () {
+            this.state.videoCommands.execute('play');
+        },
+
+        hide: function () {
+            this.el
+                .addClass('is-hidden')
+                .attr({'aria-hidden': 'true', 'tabindex': -1});
+        },
+
+        show: function () {
+            this.el
+                .removeClass('is-hidden')
+                .attr({'aria-hidden': 'false', 'tabindex': 0});
+        }
+    };
+
+    return PlayPlaceholder;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_play_skip_control.js b/common/lib/xmodule/xmodule/js/src/video/09_play_skip_control.js
new file mode 100644
index 0000000000000000000000000000000000000000..c042230c7c063a994ac383c8f534a51133135b80
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_play_skip_control.js
@@ -0,0 +1,84 @@
+(function(define) {
+'use strict';
+define('video/09_play_skip_control.js', [], function() {
+    /**
+     * Play/skip control module.
+     * @exports video/09_play_skip_control.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @return {jquery Promise}
+     */
+    var PlaySkipControl = function(state, i18n) {
+        if (!(this instanceof PlaySkipControl)) {
+            return new PlaySkipControl(state, i18n);
+        }
+
+        _.bindAll(this, 'play', 'onClick', 'destroy');
+        this.state = state;
+        this.state.videoPlaySkipControl = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    PlaySkipControl.prototype = {
+        template: [
+            '<a class="video_control play play-skip-control" href="#" title="',
+                gettext('Play'), '" role="button" aria-disabled="false">',
+                gettext('Play'),
+            '</a>'
+        ].join(''),
+
+        destroy: function () {
+            this.el.remove();
+            this.state.el.off('destroy', this.destroy);
+            delete this.state.videoPlaySkipControl;
+        },
+
+        /** Initializes the module. */
+        initialize: function() {
+            this.el = $(this.template);
+            this.render();
+            this.bindHandlers();
+        },
+
+        /**
+         * Creates any necessary DOM elements, attach them, and set their,
+         * initial configuration.
+         */
+        render: function() {
+            this.state.el.find('.vcr').prepend(this.el);
+        },
+
+        /** Bind any necessary function callbacks to DOM events. */
+        bindHandlers: function() {
+            this.el.on('click', this.onClick);
+            this.state.el.on({
+                'play': this.play,
+                'destroy': this.destroy
+            });
+        },
+
+        onClick: function (event) {
+            event.preventDefault();
+            if (this.state.videoPlayer.isPlaying()) {
+                this.state.videoCommands.execute('skip');
+            } else {
+                this.state.videoCommands.execute('play');
+            }
+        },
+
+        play: function () {
+            this.el
+                .attr('title', gettext('Skip')).text(gettext('Skip'))
+                .removeClass('play').addClass('skip');
+            // Disable possibility to pause the video.
+            this.state.el.find('video').off('click');
+        }
+    };
+
+    return PlaySkipControl;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_poster.js b/common/lib/xmodule/xmodule/js/src/video/09_poster.js
new file mode 100644
index 0000000000000000000000000000000000000000..b243200a300898207228cf9f102d244fcd3a42bb
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_poster.js
@@ -0,0 +1,66 @@
+(function (define) {
+'use strict';
+define('video/09_poster.js', [], function () {
+    /**
+     * Poster module.
+     * @exports video/09_poster.js
+     * @constructor
+     * @param {jquery Element} element
+     * @param {Object} options
+     */
+    var VideoPoster = function (element, options) {
+        if (!(this instanceof VideoPoster)) {
+            return new VideoPoster(element, options);
+        }
+
+        _.bindAll(this, 'onClick', 'destroy');
+        this.element = element;
+        this.container = element.find('.video-player');
+        this.options = options || {};
+        this.initialize();
+    };
+
+    VideoPoster.moduleName = 'Poster';
+    VideoPoster.prototype = {
+        template: _.template([
+            '<div class="video-pre-roll is-<%= type %> poster" ',
+                'style="background-image: url(<%= url %>)">',
+                '<button class="btn-play">', gettext('Play video'), '</button>',
+            '</div>'
+        ].join('')),
+
+        initialize: function () {
+            this.el = $(this.template({
+                url: this.options.poster.url,
+                type: this.options.poster.type
+            }));
+            this.element.addClass('is-pre-roll');
+            this.render();
+            this.bindHandlers();
+        },
+
+        bindHandlers: function () {
+            this.el.on('click', this.onClick);
+            this.element.on('destroy', this.destroy);
+        },
+
+        render: function () {
+            this.container.append(this.el);
+        },
+
+        onClick: function () {
+            if (_.isFunction(this.options.onClick)) {
+                this.options.onClick();
+            }
+            this.destroy();
+        },
+
+        destroy: function () {
+            this.element.off('destroy', this.destroy).removeClass('is-pre-roll');
+            this.el.remove();
+        }
+    };
+
+    return VideoPoster;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_save_state_plugin.js b/common/lib/xmodule/xmodule/js/src/video/09_save_state_plugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..11d2772803ccf0c7f2cd0c2d60449c700eaf234d
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_save_state_plugin.js
@@ -0,0 +1,118 @@
+(function(define) {
+'use strict';
+define('video/09_save_state_plugin.js', [], function() {
+    /**
+     * Save state module.
+     * @exports video/09_save_state_plugin.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @param {Object} options
+     * @return {jquery Promise}
+     */
+    var SaveStatePlugin = function(state, i18n, options) {
+        if (!(this instanceof SaveStatePlugin)) {
+            return new SaveStatePlugin(state, i18n, options);
+        }
+
+        _.bindAll(this, 'onSpeedChange', 'saveStateHandler', 'bindUnloadHandler', 'onUnload', 'onYoutubeAvailability',
+            'onLanguageChange', 'destroy');
+        this.state = state;
+        this.options = _.extend({events: []}, options);
+        this.state.videoSaveStatePlugin = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+
+    SaveStatePlugin.moduleName = 'SaveStatePlugin';
+    SaveStatePlugin.prototype = {
+        destroy: function () {
+            this.state.el.off(this.events).off('destroy', this.destroy);
+            $(window).off('unload', this.onUnload);
+            delete this.state.videoSaveStatePlugin;
+        },
+
+        initialize: function() {
+            this.events = {
+                'speedchange': this.onSpeedChange,
+                'play': this.bindUnloadHandler,
+                'pause destroy': this.saveStateHandler,
+                'language_menu:change': this.onLanguageChange,
+                'youtube_availability': this.onYoutubeAvailability
+            };
+            this.bindHandlers();
+        },
+
+        bindHandlers: function() {
+            if (this.options.events.length) {
+                _.each(this.options.events, function (eventName) {
+                    var callback;
+                    if (_.has(this.events, eventName)) {
+                        callback = this.events[eventName];
+                        this.state.el.on(eventName, callback);
+                    }
+                }, this);
+            } else {
+                this.state.el.on(this.events);
+            }
+            this.state.el.on('destroy', this.destroy);
+        },
+
+        bindUnloadHandler: _.once(function () {
+            $(window).on('unload.video', this.onUnload);
+        }),
+
+        onSpeedChange: function (event, newSpeed) {
+            this.saveState(true, {speed: newSpeed});
+            this.state.storage.setItem('speed', newSpeed, true);
+            this.state.storage.setItem('general_speed', newSpeed);
+        },
+
+        saveStateHandler: function () {
+            this.saveState(true);
+        },
+
+        onUnload: function () {
+            this.saveState();
+        },
+
+        onLanguageChange: function (event, langCode) {
+            this.state.storage.setItem('language', langCode);
+        },
+
+        onYoutubeAvailability: function (event, youtubeIsAvailable) {
+            this.saveState(true, {youtube_is_available: youtubeIsAvailable});
+        },
+
+        saveState: function (async, data) {
+            if (!($.isPlainObject(data))) {
+                data = {
+                    saved_video_position: this.state.videoPlayer.currentTime
+                };
+            }
+
+            if (data.speed) {
+                this.state.storage.setItem('speed', data.speed, true);
+            }
+
+            if (_.has(data, 'saved_video_position')) {
+                this.state.storage.setItem('savedVideoPosition', data.saved_video_position, true);
+                data.saved_video_position = Time.formatFull(data.saved_video_position);
+            }
+
+            $.ajax({
+                url: this.state.config.saveStateUrl,
+                type: 'POST',
+                async: async ? true : false,
+                dataType: 'json',
+                data: data
+            });
+        }
+    };
+
+    return SaveStatePlugin;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_skip_control.js b/common/lib/xmodule/xmodule/js/src/video/09_skip_control.js
new file mode 100644
index 0000000000000000000000000000000000000000..c508c3ebb19c597cb3a26cfb0f1a74b76c278301
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/video/09_skip_control.js
@@ -0,0 +1,74 @@
+(function(define) {
+'use strict';
+// VideoSkipControl module.
+define(
+'video/09_skip_control.js', [],
+function() {
+    /**
+     * Video skip control module.
+     * @exports video/09_skip_control.js
+     * @constructor
+     * @param {Object} state The object containing the state of the video
+     * @param {Object} i18n The object containing strings with translations.
+     * @return {jquery Promise}
+     */
+    var SkipControl = function(state, i18n) {
+        if (!(this instanceof SkipControl)) {
+            return new SkipControl(state, i18n);
+        }
+
+        _.bindAll(this, 'onClick', 'render', 'destroy');
+        this.state = state;
+        this.state.videoSkipControl = this;
+        this.i18n = i18n;
+        this.initialize();
+
+        return $.Deferred().resolve().promise();
+    };
+
+    SkipControl.prototype = {
+        template: [
+            '<a class="video_control skip skip-control" href="#" title="',
+                gettext('Do not show again'), '" role="button" aria-disabled="false">',
+                gettext('Do not show again'),
+            '</a>'
+        ].join(''),
+
+        destroy: function () {
+            this.el.remove();
+            this.state.el.off('.skip');
+            delete this.state.videoSkipControl;
+        },
+
+        /** Initializes the module. */
+        initialize: function() {
+            this.el = $(this.template);
+            this.bindHandlers();
+        },
+
+        /**
+         * Creates any necessary DOM elements, attach them, and set their,
+         * initial configuration.
+         */
+        render: function() {
+            this.state.el.find('.vcr a').after(this.el);
+        },
+
+        /** Bind any necessary function callbacks to DOM events. */
+        bindHandlers: function() {
+            this.el.on('click', this.onClick);
+            this.state.el.on({
+                'play.skip': _.once(this.render),
+                'destroy.skip': this.destroy
+            });
+        },
+
+        onClick: function (event) {
+            event.preventDefault();
+            this.state.videoCommands.execute('skip', true);
+        }
+    };
+
+    return SkipControl;
+});
+}(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
index 27608e99a546b7f2e1692789154d5e7967d3c7e1..56d22655a66ffc0479c776e966e412cdf02b90e9 100644
--- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
+++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
@@ -1,5 +1,4 @@
 (function (define) {
-
 // VideoCaption module.
 define(
 'video/09_video_caption.js',
@@ -24,6 +23,10 @@ function (Sjson, AsyncProcess) {
             return new VideoCaption(state);
         }
 
+        _.bindAll(this, 'toggle', 'onMouseEnter', 'onMouseLeave', 'onMovement',
+            'onContainerMouseEnter', 'onContainerMouseLeave', 'fetchCaption',
+            'onResize', 'pause', 'play', 'onCaptionUpdate', 'onCaptionHandler', 'destroy'
+        );
         this.state = state;
         this.state.videoCaption = this;
         this.renderElements();
@@ -32,29 +35,61 @@ function (Sjson, AsyncProcess) {
     };
 
     VideoCaption.prototype = {
+        langTemplate: [
+            '<div class="lang menu-container">',
+                '<a href="#" class="hide-subtitles" title="',
+                    gettext('Turn off captions'), '" role="button" aria-disabled="false">',
+                    gettext('Turn off captions'),
+                '</a>',
+            '</div>'
+        ].join(''),
+
+        template: [
+            '<ol id="transcript-captions" class="subtitles" tabindex="0" role="group" aria-label="',
+                gettext('Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.'),
+                '">',
+                '<li></li>',
+            '</ol>'
+        ].join(''),
+
+        destroy: function () {
+            this.state.el
+                .off({
+                    'caption:fetch': this.fetchCaption,
+                    'caption:resize': this.onResize,
+                    'caption:update': this.onCaptionUpdate,
+                    'ended': this.pause,
+                    'fullscreen': this.onResize,
+                    'pause': this.pause,
+                    'play': this.play,
+                    'destroy': this.destroy
+                })
+                .removeClass('is-captions-rendered');
+            if (this.fetchXHR && this.fetchXHR.abort) {
+                this.fetchXHR.abort();
+            }
+            if (this.availableTranslationsXHR && this.availableTranslationsXHR.abort) {
+                this.availableTranslationsXHR.abort();
+            }
+            this.subtitlesEl.remove();
+            this.container.remove();
+            delete this.state.videoCaption;
+        },
         /**
         * @desc Initiate rendering of elements, and set their initial configuration.
         *
         */
         renderElements: function () {
-            var state = this.state,
-                languages = this.state.config.transcriptLanguages;
+            var languages = this.state.config.transcriptLanguages;
 
             this.loaded = false;
-            this.subtitlesEl = state.el.find('ol.subtitles');
-            this.container = state.el.find('.lang');
-            this.hideSubtitlesEl = state.el.find('a.hide-subtitles');
+            this.subtitlesEl = $(this.template);
+            this.container = $(this.langTemplate);
+            this.hideSubtitlesEl = this.container.find('a.hide-subtitles');
 
             if (_.keys(languages).length) {
                 this.renderLanguageMenu(languages);
-
-                if (!this.fetchCaption()) {
-                    this.hideCaptions(true);
-                    this.hideSubtitlesEl.hide();
-                }
-            } else {
-                this.hideCaptions(true, false);
-                this.hideSubtitlesEl.hide();
+                this.fetchCaption();
             }
         },
 
@@ -64,65 +99,40 @@ function (Sjson, AsyncProcess) {
         *
         */
         bindHandlers: function () {
-            var self = this,
-                state = this.state,
+            var state = this.state,
                 events = [
                     'mouseover', 'mouseout', 'mousedown', 'click', 'focus', 'blur',
                     'keydown'
                 ].join(' ');
 
-            // Change context to VideoCaption of event handlers using `bind`.
-            this.hideSubtitlesEl.on('click', this.toggle.bind(this));
+            this.hideSubtitlesEl.on('click', this.toggle);
             this.subtitlesEl
                 .on({
-                    mouseenter: this.onMouseEnter.bind(this),
-                    mouseleave: this.onMouseLeave.bind(this),
-                    mousemove: this.onMovement.bind(this),
-                    mousewheel: this.onMovement.bind(this),
-                    DOMMouseScroll: this.onMovement.bind(this)
+                    mouseenter: this.onMouseEnter,
+                    mouseleave: this.onMouseLeave,
+                    mousemove: this.onMovement,
+                    mousewheel: this.onMovement,
+                    DOMMouseScroll: this.onMovement
                 })
-                .on(events, 'li[data-index]', function (event) {
-                    switch (event.type) {
-                        case 'mouseover':
-                        case 'mouseout':
-                            self.captionMouseOverOut(event);
-                            break;
-                        case 'mousedown':
-                            self.captionMouseDown(event);
-                            break;
-                        case 'click':
-                            self.captionClick(event);
-                            break;
-                        case 'focusin':
-                            self.captionFocus(event);
-                            break;
-                        case 'focusout':
-                            self.captionBlur(event);
-                            break;
-                        case 'keydown':
-                            self.captionKeyDown(event);
-                            break;
-                    }
-                });
+                .on(events, 'li[data-index]', this.onCaptionHandler);
 
             if (this.showLanguageMenu) {
                 this.container.on({
-                    mouseenter: this.onContainerMouseEnter.bind(this),
-                    mouseleave: this.onContainerMouseLeave.bind(this)
+                    mouseenter: this.onContainerMouseEnter,
+                    mouseleave: this.onContainerMouseLeave
                 });
             }
 
             state.el
                 .on({
-                    'caption:fetch': this.fetchCaption.bind(this),
-                    'caption:resize': this.onResize.bind(this),
-                    'caption:update': function (event, time) {
-                        self.updatePlayTime(time);
-                    },
-                    'ended': this.pause.bind(this),
-                    'fullscreen': this.onResize.bind(this),
-                    'pause': this.pause.bind(this),
-                    'play': this.play.bind(this)
+                    'caption:fetch': this.fetchCaption,
+                    'caption:resize': this.onResize,
+                    'caption:update': this.onCaptionUpdate,
+                    'ended': this.pause,
+                    'fullscreen': this.onResize,
+                    'pause': this.pause,
+                    'play': this.play,
+                    'destroy': this.destroy
                 });
 
             if ((state.videoType === 'html5') && (state.config.autohideHtml5)) {
@@ -130,6 +140,33 @@ function (Sjson, AsyncProcess) {
             }
         },
 
+        onCaptionUpdate: function (event, time) {
+            this.updatePlayTime(time);
+        },
+
+        onCaptionHandler: function (event) {
+            switch (event.type) {
+                case 'mouseover':
+                case 'mouseout':
+                    this.captionMouseOverOut(event);
+                    break;
+                case 'mousedown':
+                    this.captionMouseDown(event);
+                    break;
+                case 'click':
+                    this.captionClick(event);
+                    break;
+                case 'focusin':
+                    this.captionFocus(event);
+                    break;
+                case 'focusout':
+                    this.captionBlur(event);
+                    break;
+                case 'keydown':
+                    this.captionKeyDown(event);
+                    break;
+            }
+        },
 
         /**
         * @desc Opens language menu.
@@ -138,8 +175,8 @@ function (Sjson, AsyncProcess) {
         */
         onContainerMouseEnter: function (event) {
             event.preventDefault();
-            this.state.videoPlayer.log('video_show_cc_menu', {});
             $(event.currentTarget).addClass('is-opened');
+            this.state.el.trigger('language_menu:show');
         },
 
         /**
@@ -149,8 +186,8 @@ function (Sjson, AsyncProcess) {
         */
         onContainerMouseLeave: function (event) {
             event.preventDefault();
-            this.state.videoPlayer.log('video_hide_cc_menu', {});
             $(event.currentTarget).removeClass('is-opened');
+            this.state.el.trigger('language_menu:hide');
         },
 
         /**
@@ -247,12 +284,11 @@ function (Sjson, AsyncProcess) {
             var self = this,
                 state = this.state,
                 language = state.getCurrentLanguage(),
+                url = state.config.transcriptTranslationUrl.replace('__lang__', language),
                 data, youtubeId;
 
             if (this.loaded) {
                 this.hideCaptions(false);
-            } else {
-                this.hideCaptions(state.hide_captions, false);
             }
 
             if (this.fetchXHR && this.fetchXHR.abort) {
@@ -266,16 +302,14 @@ function (Sjson, AsyncProcess) {
                     return false;
                 }
 
-                data = {
-                    videoId: youtubeId
-                };
+                data = {videoId: youtubeId};
             }
 
             state.el.removeClass('is-captions-rendered');
             // Fetch the captions file. If no file was specified, or if an error
             // occurred, then we hide the captions panel, and the "CC" button
             this.fetchXHR = $.ajaxWithPrefix({
-                url: state.config.transcriptTranslationUrl + '/' + language,
+                url: url,
                 notifyOnError: false,
                 data: data,
                 success: function (sjson) {
@@ -300,7 +334,9 @@ function (Sjson, AsyncProcess) {
                         } else {
                             self.renderCaption(start, captions);
                         }
-
+                        self.hideCaptions(state.hide_captions, false);
+                        self.state.el.find('.video-wrapper').after(self.subtitlesEl);
+                        self.state.el.find('.secondary-controls').append(self.container);
                         self.bindHandlers();
                     }
 
@@ -336,7 +372,7 @@ function (Sjson, AsyncProcess) {
             var self = this,
                 state = this.state;
 
-            return $.ajaxWithPrefix({
+            this.availableTranslationsXHR = $.ajaxWithPrefix({
                 url: state.config.transcriptAvailableTranslationsUrl,
                 notifyOnError: false,
                 success: function (response) {
@@ -359,6 +395,8 @@ function (Sjson, AsyncProcess) {
                     self.hideSubtitlesEl.hide();
                 }
             });
+
+            return this.availableTranslationsXHR;
         },
 
         /**
@@ -417,11 +455,11 @@ function (Sjson, AsyncProcess) {
 
                 if (state.lang !== langCode) {
                     state.lang = langCode;
-                    state.storage.setItem('language', langCode);
                     el  .addClass('is-active')
                         .siblings('li')
                         .removeClass('is-active');
 
+                    state.el.trigger('language_menu:change', [langCode]);
                     self.fetchCaption();
                 }
             });
@@ -658,7 +696,7 @@ function (Sjson, AsyncProcess) {
         *
         */
         play: function () {
-            var startAndCaptions, start, end;
+            var captions, startAndCaptions, start;
             if (this.loaded) {
                 if (!this.rendered) {
                     startAndCaptions = this.getBoundedCaptions();
@@ -689,10 +727,7 @@ function (Sjson, AsyncProcess) {
         */
         updatePlayTime: function (time) {
             var state = this.state,
-                startTime,
-                endTime,
-                params,
-                newIndex;
+                params, newIndex;
 
             if (this.loaded) {
                 if (state.isFlashMode()) {
@@ -797,9 +832,9 @@ function (Sjson, AsyncProcess) {
             event.preventDefault();
 
             if (this.state.el.hasClass('closed')) {
-                this.hideCaptions(false);
+                this.hideCaptions(false, true, true);
             } else {
-                this.hideCaptions(true);
+                this.hideCaptions(true, true, true);
             }
         },
 
@@ -811,38 +846,35 @@ function (Sjson, AsyncProcess) {
         * @param {boolean} update_cookie Flag to update or not the cookie.
         *
         */
-        hideCaptions: function (hide_captions, update_cookie) {
+        hideCaptions: function (hide_captions, update_cookie, trigger_event) {
             var hideSubtitlesEl = this.hideSubtitlesEl,
-                state = this.state,
-                type, text;
+                state = this.state, text;
 
             if (typeof update_cookie === 'undefined') {
                 update_cookie = true;
             }
 
             if (hide_captions) {
-                type = 'hide_transcript';
                 state.captionsHidden = true;
                 state.el.addClass('closed');
                 text = gettext('Turn on captions');
+                if (trigger_event) {
+                    this.state.el.trigger('captions:hide');
+                }
             } else {
-                type = 'show_transcript';
                 state.captionsHidden = false;
                 state.el.removeClass('closed');
                 this.scrollCaption();
                 text = gettext('Turn off captions');
+                if (trigger_event) {
+                    this.state.el.trigger('captions:show');
+                }
             }
 
             hideSubtitlesEl
                 .attr('title', text)
                 .text(gettext(text));
 
-            if (state.videoPlayer) {
-                state.videoPlayer.log(type, {
-                    currentTime: state.videoPlayer.currentTime
-                });
-            }
-
             if (state.resizer) {
                 if (state.isFullScreen) {
                     state.resizer.setMode('both');
@@ -868,9 +900,8 @@ function (Sjson, AsyncProcess) {
         */
         captionHeight: function () {
             var state = this.state;
-
             if (state.isFullScreen) {
-                return state.container.height() - state.videoControl.height;
+                return state.container.height() - state.videoFullScreen.height;
             } else {
                 return state.container.height();
             }
@@ -889,8 +920,8 @@ function (Sjson, AsyncProcess) {
             ) {
                 // In case of html5 autoshowing subtitles, we adjust height of
                 // subs, by height of scrollbar.
-                height = state.videoControl.el.height() +
-                    0.5 * state.videoControl.sliderEl.height();
+                height = state.el.find('.video-controls').height() +
+                    0.5 * state.el.find('.slider').height();
                 // Height of videoControl does not contain height of slider.
                 // css is set to absolute, to avoid yanking when slider
                 // autochanges its height.
diff --git a/common/lib/xmodule/xmodule/js/src/video/10_commands.js b/common/lib/xmodule/xmodule/js/src/video/10_commands.js
index ad78066864d34e5924b11c27069cb5cf19d54ee4..5ed94c929645fd45eb93e7d9e9056d7031acba5e 100644
--- a/common/lib/xmodule/xmodule/js/src/video/10_commands.js
+++ b/common/lib/xmodule/xmodule/js/src/video/10_commands.js
@@ -1,11 +1,8 @@
 (function(define) {
 'use strict';
-// VideoCommands module.
 define('video/10_commands.js', [], function() {
     var VideoCommands, Command, playCommand, pauseCommand, togglePlaybackCommand,
-        muteCommand, unmuteCommand, toggleMuteCommand, toggleFullScreenCommand,
-        setSpeedCommand;
-
+        toggleMuteCommand, toggleFullScreenCommand, setSpeedCommand, skipCommand;
     /**
      * Video commands module.
      * @exports video/10_commands.js
@@ -19,6 +16,7 @@ define('video/10_commands.js', [], function() {
             return new VideoCommands(state, i18n);
         }
 
+        _.bindAll(this, 'destroy');
         this.state = state;
         this.state.videoCommands = this;
         this.i18n = i18n;
@@ -29,9 +27,15 @@ define('video/10_commands.js', [], function() {
     };
 
     VideoCommands.prototype = {
+        destroy: function () {
+            this.state.el.off('destroy', this.destroy);
+            delete this.state.videoCommands;
+        },
+
         /** Initializes the module. */
         initialize: function() {
             this.commands = this.getCommands();
+            this.state.el.on('destroy', this.destroy);
         },
 
         execute: function (command) {
@@ -48,7 +52,8 @@ define('video/10_commands.js', [], function() {
             var commands = {},
                 commandsList = [
                     playCommand, pauseCommand, togglePlaybackCommand,
-                    toggleMuteCommand, toggleFullScreenCommand, setSpeedCommand
+                    toggleMuteCommand, toggleFullScreenCommand, setSpeedCommand,
+                    skipCommand
                 ];
 
             _.each(commandsList, function(command) {
@@ -73,7 +78,7 @@ define('video/10_commands.js', [], function() {
     });
 
     togglePlaybackCommand = new Command('togglePlayback', function (state) {
-        if (state.videoControl.isPlaying) {
+        if (state.videoPlayer.isPlaying()) {
             pauseCommand.execute(state);
         } else {
             playCommand.execute(state);
@@ -85,13 +90,21 @@ define('video/10_commands.js', [], function() {
     });
 
     toggleFullScreenCommand = new Command('toggleFullScreen', function (state) {
-        state.videoControl.toggleFullScreen();
+        state.videoFullScreen.toggle();
     });
 
     setSpeedCommand = new Command('speed', function (state, speed) {
         state.videoSpeedControl.setSpeed(state.speedToString(speed));
     });
 
+    skipCommand = new Command('skip', function (state, doNotShowAgain) {
+        if (doNotShowAgain) {
+            state.videoBumper.skipAndDoNotShowAgain();
+        } else {
+            state.videoBumper.skip();
+        }
+    });
+
     return VideoCommands;
 });
 }(RequireJS.define));
diff --git a/common/lib/xmodule/xmodule/js/src/video/10_main.js b/common/lib/xmodule/xmodule/js/src/video/10_main.js
index 1ac539111726776ab91fd82806e5d1a9db44ad03..be3bbc8ae87f5952deec404442ba72f4f03f6571 100644
--- a/common/lib/xmodule/xmodule/js/src/video/10_main.js
+++ b/common/lib/xmodule/xmodule/js/src/video/10_main.js
@@ -1,6 +1,5 @@
 (function (require, $) {
     'use strict';
-
     // In the case when the Video constructor will be called before RequireJS finishes loading all of the Video
     // dependencies, we will have a mock function that will collect all the elements that must be initialized as
     // Video elements.
@@ -35,74 +34,122 @@
     // Main module.
     require(
         [
+            'video/00_video_storage.js',
             'video/01_initialize.js',
             'video/025_focus_grabber.js',
             'video/035_video_accessible_menu.js',
             'video/04_video_control.js',
+            'video/04_video_full_screen.js',
             'video/05_video_quality_control.js',
             'video/06_video_progress_slider.js',
             'video/07_video_volume_control.js',
             'video/08_video_speed_control.js',
             'video/09_video_caption.js',
+            'video/09_play_placeholder.js',
+            'video/09_play_pause_control.js',
+            'video/09_play_skip_control.js',
+            'video/09_skip_control.js',
+            'video/09_bumper.js',
+            'video/09_save_state_plugin.js',
+            'video/09_events_plugin.js',
+            'video/09_events_bumper_plugin.js',
+            'video/09_poster.js',
             'video/10_commands.js',
             'video/095_video_context_menu.js'
         ],
         function (
-            initialize,
-            FocusGrabber,
-            VideoAccessibleMenu,
-            VideoControl,
-            VideoQualityControl,
-            VideoProgressSlider,
-            VideoVolumeControl,
-            VideoSpeedControl,
-            VideoCaption,
-            VideoCommands,
+            VideoStorage, initialize, FocusGrabber, VideoAccessibleMenu, VideoControl, VideoFullScreen,
+            VideoQualityControl, VideoProgressSlider, VideoVolumeControl, VideoSpeedControl, VideoCaption,
+            VideoPlayPlaceholder, VideoPlayPauseControl, VideoPlaySkipControl, VideoSkipControl, VideoBumper,
+            VideoSaveStatePlugin, VideoEventsPlugin, VideoEventsBumperPlugin, VideoPoster, VideoCommands,
             VideoContextMenu
         ) {
             var youtubeXhr = null,
                 oldVideo = window.Video;
 
             window.Video = function (element) {
-                var previousState = window.Video.previousState,
-                    state;
-
-                // Check for existance of previous state, uninitialize it if necessary, and create a new state. Store
-                // new state for future invocation of this module consturctor function.
-                if (previousState && previousState.videoPlayer) {
-                    previousState.saveState(true);
-                    $(window).off('unload', previousState.saveState);
+                var el = $(element).find('.video'),
+                    id = el.attr('id').replace(/video_/, ''),
+                    storage = VideoStorage('VideoState', id),
+                    bumperMetadata = el.data('bumper-metadata'),
+                    mainVideoModules = [FocusGrabber, VideoControl, VideoPlayPlaceholder,
+                        VideoPlayPauseControl, VideoProgressSlider, VideoSpeedControl, VideoVolumeControl,
+                        VideoQualityControl, VideoFullScreen, VideoCaption, VideoCommands, VideoContextMenu,
+                        VideoSaveStatePlugin, VideoEventsPlugin],
+                    bumperVideoModules = [VideoControl, VideoPlaySkipControl, VideoSkipControl,
+                        VideoVolumeControl, VideoCaption, VideoCommands, VideoSaveStatePlugin, VideoEventsBumperPlugin],
+                    state = {
+                        el: el,
+                        id: id,
+                        metadata: el.data('metadata'),
+                        storage: storage,
+                        options: {},
+                        youtubeXhr: youtubeXhr,
+                        modules: mainVideoModules
+                    };
+
+                var getBumperState = function (metadata) {
+                    var bumperState = $.extend(true, {
+                            el: el,
+                            id: id,
+                            storage: storage,
+                            options: {},
+                            youtubeXhr: youtubeXhr
+                        }, {metadata: metadata});
+
+                    bumperState.modules = bumperVideoModules;
+                    bumperState.options = {
+                        SaveStatePlugin: {events: ['language_menu:change']}
+                    };
+                    return bumperState;
+                };
+
+                var player = function (state) {
+                    return function () {
+                        _.extend(state.metadata, {autoplay: true, focusFirstControl: true});
+                        initialize(state, element);
+                    };
+                };
+
+                new VideoAccessibleMenu(el, {
+                    storage: storage,
+                    saveStateUrl: state.metadata.saveStateUrl
+                });
+
+                if (bumperMetadata) {
+                    new VideoPoster(el, {
+                        poster: el.data('poster'),
+                        onClick: _.once(function () {
+                            var mainVideoPlayer = player(state), bumper, bumperState;
+                            if (storage.getItem('isBumperShown')) {
+                                mainVideoPlayer();
+                            } else {
+                                bumperState = getBumperState(bumperMetadata);
+                                bumper = new VideoBumper(player(bumperState), bumperState);
+                                state.bumperState = bumperState;
+                                bumper.getPromise().done(function () {
+                                    delete state.bumperState;
+                                    mainVideoPlayer();
+                                });
+                            }
+                        })
+                    });
+                } else {
+                    initialize(state, element);
                 }
 
-                state = {};
-                // Because this constructor can be called multiple times on a single page (when the user switches
-                // verticals, the page doesn't reload, but the content changes), we must will check each time if there
-                // is a previous copy of 'state' object. If there is, we will make sure that copy exists cleanly. We
-                // have to do this because when verticals switch, the code does not handle any Xmodule JS code that is
-                // running - it simply removes DOM elements from the page. Any functions that were running during this,
-                // and that will run afterwards (expecting the DOM elements to be present) must be stopped by hand.
-                window.Video.previousState = state;
-
-                state.modules = [
-                    FocusGrabber,
-                    VideoAccessibleMenu,
-                    VideoControl,
-                    VideoQualityControl,
-                    VideoProgressSlider,
-                    VideoVolumeControl,
-                    VideoSpeedControl,
-                    VideoCaption,
-                    VideoCommands,
-                    VideoContextMenu
-                ];
-
-                state.youtubeXhr = youtubeXhr;
-                initialize(state, element);
                 if (!youtubeXhr) {
                     youtubeXhr = state.youtubeXhr;
                 }
 
-                $(element).find('.video').data('video-player-state', state);
+                el.data('video-player-state', state);
+                var onSequenceChange = function onSequenceChange () {
+                    if (state && state.videoPlayer) {
+                        state.videoPlayer.destroy();
+                    }
+                    $('.sequence').off('sequence:change', onSequenceChange);
+                };
+                $('.sequence').on('sequence:change', onSequenceChange);
 
                 // Because the 'state' object is only available inside this closure, we will also make it available to
                 // the caller by returning it. This is necessary so that we can test Video with Jasmine.
diff --git a/common/lib/xmodule/xmodule/modulestore/inheritance.py b/common/lib/xmodule/xmodule/modulestore/inheritance.py
index d6293647c7185fc8744d9310b9f2576610816547..d30a216df5420acbd23a699b0c2ae6ed2cc77248 100644
--- a/common/lib/xmodule/xmodule/modulestore/inheritance.py
+++ b/common/lib/xmodule/xmodule/modulestore/inheritance.py
@@ -149,6 +149,18 @@ class InheritanceMixin(XBlockMixin):
         default=True,
         scope=Scope.settings
     )
+    video_bumper = Dict(
+        display_name=_("Video Pre-Roll"),
+        help=_(
+            """Identify a video, 5-10 seconds in length, to play before course videos. Enter the video ID from"""
+            """ the Video Uploads page and one or more transcript files in the following format:"""
+            """ {"video_id": "ID", "transcripts": {"language": "/static/filename.srt"}}."""
+            """ For example, an entry for a video with two transcripts looks like this:"""
+            """ {"video_id": "77cef264-d6f5-4cf2-ad9d-0178ab8c77be","""
+            """ "transcripts": {"en": "/static/DemoX-D01_1.srt", "uk": "/static/DemoX-D01_1_uk.srt"}}"""
+        ),
+        scope=Scope.settings
+    )
 
     reset_key = "DEFAULT_SHOW_RESET_BUTTON"
     default_reset_button = getattr(settings, reset_key) if hasattr(settings, reset_key) else False
diff --git a/common/lib/xmodule/xmodule/video_module/__init__.py b/common/lib/xmodule/xmodule/video_module/__init__.py
index 9aa96ecee95be7b9292295a28dc724719169c826..ad2040c1983e21914c3e47ff4c81cf6599dbc7ca 100644
--- a/common/lib/xmodule/xmodule/video_module/__init__.py
+++ b/common/lib/xmodule/xmodule/video_module/__init__.py
@@ -8,3 +8,4 @@ Container for video module and it's utils.
 from .transcripts_utils import *
 from .video_utils import *
 from .video_module import *
+from .bumper_utils import *
diff --git a/common/lib/xmodule/xmodule/video_module/bumper_utils.py b/common/lib/xmodule/xmodule/video_module/bumper_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0bb914d280241053329813e30e89ac5cab179f37
--- /dev/null
+++ b/common/lib/xmodule/xmodule/video_module/bumper_utils.py
@@ -0,0 +1,142 @@
+"""
+Utils for video bumper
+"""
+import copy
+import json
+import pytz
+import logging
+from collections import OrderedDict
+
+from datetime import datetime, timedelta
+from django.conf import settings
+
+from .video_utils import set_query_parameter
+
+try:
+    import edxval.api as edxval_api
+except ImportError:
+    edxval_api = None
+
+log = logging.getLogger(__name__)
+
+
+def get_bumper_settings(video):
+    """
+    Get bumper settings from video instance.
+    """
+    bumper_settings = copy.deepcopy(getattr(video, 'video_bumper', {}))
+
+    # clean up /static/ prefix from bumper transcripts
+    for lang, transcript_url in bumper_settings.get('transcripts', {}).items():
+        bumper_settings['transcripts'][lang] = transcript_url.replace("/static/", "")
+
+    return bumper_settings
+
+
+def is_bumper_enabled(video):
+    """
+    Check if bumper enabled.
+
+    - Feature flag ENABLE_VIDEO_BUMPER should be set to True
+    - Do not show again button should not be clicked by user.
+    - Current time minus periodicity must be greater that last time viewed
+    - edxval_api should be presented
+
+    Returns:
+         bool.
+    """
+    bumper_last_view_date = getattr(video, 'bumper_last_view_date', None)
+    utc_now = datetime.utcnow().replace(tzinfo=pytz.utc)
+    periodicity = settings.FEATURES.get('SHOW_BUMPER_PERIODICITY', 0)
+    has_viewed = any([
+        getattr(video, 'bumper_do_not_show_again'),
+        (bumper_last_view_date and bumper_last_view_date + timedelta(seconds=periodicity) > utc_now)
+    ])
+    is_studio = getattr(video.system, "is_author_mode", False)
+    return bool(
+        not is_studio and
+        settings.FEATURES.get('ENABLE_VIDEO_BUMPER') and
+        get_bumper_settings(video) and
+        edxval_api and
+        not has_viewed
+    )
+
+
+def bumperize(video):
+    """
+    Populate video with bumper settings, if they are presented.
+    """
+    video.bumper = {
+        'enabled': False,
+        'edx_video_id': "",
+        'transcripts': {},
+        'metadata': None,
+    }
+
+    if not is_bumper_enabled(video):
+        return
+
+    bumper_settings = get_bumper_settings(video)
+
+    try:
+        video.bumper['edx_video_id'] = bumper_settings['video_id']
+        video.bumper['transcripts'] = bumper_settings['transcripts']
+    except (TypeError, KeyError):
+        log.warning(
+            "Could not retrieve video bumper information from course settings"
+        )
+        return
+
+    sources = get_bumper_sources(video)
+    if not sources:
+        return
+
+    video.bumper.update({
+        'metadata': bumper_metadata(video, sources),
+        'enabled': True,  # Video poster needs this.
+    })
+
+
+def get_bumper_sources(video):
+    """
+    Get bumper sources from edxval.
+
+    Returns list of sources.
+    """
+    try:
+        val_profiles = ["desktop_webm", "desktop_mp4"]
+        val_video_urls = edxval_api.get_urls_for_profiles(video.bumper['edx_video_id'], val_profiles)
+        bumper_sources = filter(None, [val_video_urls[p] for p in val_profiles])
+    except edxval_api.ValInternalError:
+        # if no bumper sources, nothing will be showed
+        log.warning(
+            "Could not retrieve information from VAL for Bumper edx Video ID: %s.", video.bumper['edx_video_id']
+        )
+        return []
+
+    return bumper_sources
+
+
+def bumper_metadata(video, sources):
+    """
+    Generate bumper metadata.
+    """
+    transcripts = video.get_transcripts_info(is_bumper=True)
+    unused_track_url, bumper_transcript_language, bumper_languages = video.get_transcripts_for_student(transcripts)
+
+    metadata = OrderedDict({
+        'saveStateUrl': video.system.ajax_url + '/save_user_state',
+        'showCaptions': json.dumps(video.show_captions),
+        'sources': sources,
+        'streams': '',
+        'transcriptLanguage': bumper_transcript_language,
+        'transcriptLanguages': bumper_languages,
+        'transcriptTranslationUrl': set_query_parameter(
+            video.runtime.handler_url(video, 'transcript', 'translation/__lang__').rstrip('/?'), 'is_bumper', 1
+        ),
+        'transcriptAvailableTranslationsUrl': set_query_parameter(
+            video.runtime.handler_url(video, 'transcript', 'available_translations').rstrip('/?'), 'is_bumper', 1
+        ),
+    })
+
+    return metadata
diff --git a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
index 8dca188d9add6c37d8ad77fb1c2d9e4d18fd66e8..fd82ed3452802105363c683d73603362f4b490af 100644
--- a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
+++ b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
@@ -15,6 +15,8 @@ from xmodule.exceptions import NotFoundError
 from xmodule.contentstore.content import StaticContent
 from xmodule.contentstore.django import contentstore
 
+from .bumper_utils import get_bumper_settings
+
 
 log = logging.getLogger(__name__)
 
@@ -408,20 +410,23 @@ def generate_sjson_for_all_speeds(item, user_filename, result_subs_dict, lang):
     )
 
 
-def get_or_create_sjson(item):
+def get_or_create_sjson(item, transcripts):
     """
     Get sjson if already exists, otherwise generate it.
 
     Generate sjson with subs_id name, from user uploaded srt.
     Subs_id is extracted from srt filename, which was set by user.
 
+    Args:
+        transcipts (dict): dictionary of (language: file) pairs.
+
     Raises:
         TranscriptException: when srt subtitles do not exist,
         and exceptions from generate_subs_from_source.
 
     `item` is module object.
     """
-    user_filename = item.transcripts[item.transcript_language]
+    user_filename = transcripts[item.transcript_language]
     user_subs_id = os.path.splitext(user_filename)[0]
     source_subs_id, result_subs_dict = user_subs_id, {1.0: user_subs_id}
     try:
@@ -517,7 +522,7 @@ class VideoTranscriptsMixin(object):
     This is necessary for both VideoModule and VideoDescriptor.
     """
 
-    def available_translations(self, verify_assets=True):
+    def available_translations(self, transcripts, verify_assets=True):
         """Return a list of language codes for which we have transcripts.
 
         Args:
@@ -528,39 +533,51 @@ class VideoTranscriptsMixin(object):
                 when trying to make a listing of videos and their languages.
 
                 Defaults to True.
+
+            transcripts (dict): A dict with all transcripts and a sub.
+
+                Defaults to False
         """
         translations = []
+        sub, other_lang = transcripts["sub"], transcripts["transcripts"]
 
         # If we're not verifying the assets, we just trust our field values
         if not verify_assets:
-            translations = list(self.transcripts)
-            if not translations or self.sub:
+            translations = list(other_lang)
+            if not translations or sub:
                 translations += ['en']
             return set(translations)
 
         # If we've gotten this far, we're going to verify that the transcripts
         # being referenced are actually in the contentstore.
-        if self.sub:  # check if sjson exists for 'en'.
+        if sub:  # check if sjson exists for 'en'.
             try:
-                Transcript.asset(self.location, self.sub, 'en')
+                Transcript.asset(self.location, sub, 'en')
             except NotFoundError:
-                pass
+                try:
+                    Transcript.asset(self.location, None, None, sub)
+                except NotFoundError:
+                    pass
+                else:
+                    translations = ['en']
             else:
                 translations = ['en']
 
-        for lang in self.transcripts:
+        for lang in other_lang:
             try:
-                Transcript.asset(self.location, None, None, self.transcripts[lang])
+                Transcript.asset(self.location, None, None, other_lang[lang])
             except NotFoundError:
                 continue
             translations.append(lang)
 
         return translations
 
-    def get_transcript(self, transcript_format='srt', lang=None):
+    def get_transcript(self, transcripts, transcript_format='srt', lang=None):
         """
         Returns transcript, filename and MIME type.
 
+        transcripts (dict): A dict with all transcripts and a sub.
+
         Raises:
             - NotFoundError if cannot find transcript file in storage.
             - ValueError if transcript file is empty or incorrect JSON.
@@ -572,11 +589,12 @@ class VideoTranscriptsMixin(object):
         If language is not 'en', give back transcript in proper language and format.
         """
         if not lang:
-            lang = self.transcript_language
+            lang = self.get_default_transcript_language(transcripts)
 
+        sub, other_lang = transcripts["sub"], transcripts["transcripts"]
         if lang == 'en':
-            if self.sub:  # HTML5 case and (Youtube case for new style videos)
-                transcript_name = self.sub
+            if sub:  # HTML5 case and (Youtube case for new style videos)
+                transcript_name = sub
             elif self.youtube_id_1_0:  # old courses
                 transcript_name = self.youtube_id_1_0
             else:
@@ -587,8 +605,8 @@ class VideoTranscriptsMixin(object):
             filename = u'{}.{}'.format(transcript_name, transcript_format)
             content = Transcript.convert(data, 'sjson', transcript_format)
         else:
-            data = Transcript.asset(self.location, None, None, self.transcripts[lang]).data
-            filename = u'{}.{}'.format(os.path.splitext(self.transcripts[lang])[0], transcript_format)
+            data = Transcript.asset(self.location, None, None, other_lang[lang]).data
+            filename = u'{}.{}'.format(os.path.splitext(other_lang[lang])[0], transcript_format)
             content = Transcript.convert(data, 'srt', transcript_format)
 
         if not content:
@@ -597,16 +615,36 @@ class VideoTranscriptsMixin(object):
 
         return content, filename, Transcript.mime_types[transcript_format]
 
-    def get_default_transcript_language(self):
+    def get_default_transcript_language(self, transcripts):
         """
         Returns the default transcript language for this video module.
+
+        Args:
+            transcripts (dict): A dict with all transcripts and a sub.
         """
-        if self.transcript_language in self.transcripts:
+        sub, other_lang = transcripts["sub"], transcripts["transcripts"]
+        if self.transcript_language in other_lang:
             transcript_language = self.transcript_language
-        elif self.sub:
+        elif sub:
             transcript_language = u'en'
-        elif len(self.transcripts) > 0:
-            transcript_language = sorted(self.transcripts)[0]
+        elif len(other_lang) > 0:
+            transcript_language = sorted(other_lang)[0]
         else:
             transcript_language = u'en'
         return transcript_language
+
+    def get_transcripts_info(self, is_bumper=False):
+        """
+        Returns a transcript dictionary for the video.
+        """
+        if is_bumper:
+            transcripts = copy.deepcopy(get_bumper_settings(self).get('transcripts', {}))
+            return {
+                "sub": transcripts.pop("en", ""),
+                "transcripts": transcripts,
+            }
+        else:
+            return {
+                "sub": self.sub,
+                "transcripts": self.transcripts,
+            }
diff --git a/common/lib/xmodule/xmodule/video_module/video_handlers.py b/common/lib/xmodule/xmodule/video_module/video_handlers.py
index 20535884446df3d8affa7a1c74eae1ebff0db713..4ed6e16e18eb1d8cf8ee8618e87dfe331bf27c8b 100644
--- a/common/lib/xmodule/xmodule/video_module/video_handlers.py
+++ b/common/lib/xmodule/xmodule/video_module/video_handlers.py
@@ -7,6 +7,7 @@ StudioViewHandlers are handlers for video descriptor instance.
 
 import json
 import logging
+from datetime import datetime
 from webob import Response
 
 from xblock.core import XBlock
@@ -44,7 +45,8 @@ class VideoStudentViewHandlers(object):
         """
         accepted_keys = [
             'speed', 'saved_video_position', 'transcript_language',
-            'transcript_download_format', 'youtube_is_available'
+            'transcript_download_format', 'youtube_is_available',
+            'bumper_last_view_date', 'bumper_do_not_show_again'
         ]
 
         conversions = {
@@ -61,6 +63,9 @@ class VideoStudentViewHandlers(object):
                     else:
                         value = data[key]
 
+                    if key == 'bumper_last_view_date':
+                        value = datetime.utcnow()
+
                     setattr(self, key, value)
 
                     if key == 'speed':
@@ -73,16 +78,17 @@ class VideoStudentViewHandlers(object):
 
         raise NotFoundError('Unexpected dispatch type')
 
-    def translation(self, youtube_id):
+    def translation(self, youtube_id, transcripts):
         """
         This is called to get transcript file for specific language.
 
         youtube_id: str: must be one of youtube_ids or None if HTML video
+        transcripts (dict): A dict with all transcripts and a sub.
 
         Logic flow:
 
         If youtube_id doesn't exist, we have a video in HTML5 mode. Otherwise,
-        video video in Youtube or Flash modes.
+        video in Youtube or Flash modes.
 
         if youtube:
             If english -> give back youtube_id subtitles:
@@ -106,6 +112,7 @@ class VideoStudentViewHandlers(object):
             NotFoundError if for 'en' subtitles no asset is uploaded.
             NotFoundError if youtube_id does not exist / invalid youtube_id
         """
+        sub, other_lang = transcripts["sub"], transcripts["transcripts"]
         if youtube_id:
             # Youtube case:
             if self.transcript_language == 'en':
@@ -122,7 +129,7 @@ class VideoStudentViewHandlers(object):
                 log.info("Can't find content in storage for %s transcript: generating.", youtube_id)
                 generate_sjson_for_all_speeds(
                     self,
-                    self.transcripts[self.transcript_language],
+                    other_lang[self.transcript_language],
                     {speed: youtube_id for youtube_id, speed in youtube_ids.iteritems()},
                     self.transcript_language
                 )
@@ -132,11 +139,18 @@ class VideoStudentViewHandlers(object):
         else:
             # HTML5 case
             if self.transcript_language == 'en':
-                return Transcript.asset(self.location, self.sub).data
-            else:
-                return get_or_create_sjson(self)
+                if '.srt' not in sub:  # not bumper case
+                    return Transcript.asset(self.location, sub).data
+                try:
+                    return get_or_create_sjson(self, {'en': sub})
+                except TranscriptException:
+                    pass  # to raise NotFoundError and try to get data in get_static_transcript
+            elif other_lang:
+                return get_or_create_sjson(self, other_lang)
+
+        raise NotFoundError
 
-    def get_static_transcript(self, request):
+    def get_static_transcript(self, request, transcripts):
         """
         Courses that are imported with the --nostatic flag do not show
         transcripts/captions properly even if those captions are stored inside
@@ -144,6 +158,8 @@ class VideoStudentViewHandlers(object):
         the static asset path of the course if the transcript can't be found
         inside the contentstore and the course has the static_asset_path field
         set.
+
+        transcripts (dict): A dict with all transcripts and a sub.
         """
         response = Response(status=404)
         # Only do redirect for English
@@ -154,7 +170,7 @@ class VideoStudentViewHandlers(object):
         if video_id:
             transcript_name = video_id
         else:
-            transcript_name = self.sub
+            transcript_name = transcripts["sub"]
 
         if transcript_name:
             # Get the asset path for course
@@ -181,7 +197,9 @@ class VideoStudentViewHandlers(object):
         """
         Entry point for transcript handlers for student_view.
 
-        Request GET may contain `videoId` for `translation` dispatch.
+        Request GET contains:
+            (optional) `videoId` for `translation` dispatch.
+            `is_bumper=1` flag for bumper case.
 
         Dispatches, (HTTP GET):
             /translation/[language_id]
@@ -197,15 +215,16 @@ class VideoStudentViewHandlers(object):
                     Returns list of languages, for which transcript files exist.
                     For 'en' check if SJSON exists. For non-`en` check if SRT file exists.
         """
+        is_bumper = request.GET.get('is_bumper', False)
+        transcripts = self.get_transcripts_info(is_bumper)
         if dispatch.startswith('translation'):
-
             language = dispatch.replace('translation', '').strip('/')
 
             if not language:
                 log.info("Invalid /translation request: no language.")
                 return Response(status=400)
 
-            if language not in ['en'] + self.transcripts.keys():
+            if language not in ['en'] + transcripts["transcripts"].keys():
                 log.info("Video: transcript facilities are not available for given language.")
                 return Response(status=404)
 
@@ -213,12 +232,12 @@ class VideoStudentViewHandlers(object):
                 self.transcript_language = language
 
             try:
-                transcript = self.translation(request.GET.get('videoId', None))
+                transcript = self.translation(request.GET.get('videoId', None), transcripts)
             except (TypeError, NotFoundError) as ex:
                 log.info(ex.message)
                 # Try to return static URL redirection as last resort
                 # if no translation is required
-                return self.get_static_transcript(request)
+                return self.get_static_transcript(request, transcripts)
             except (
                 TranscriptException,
                 UnicodeDecodeError,
@@ -232,7 +251,9 @@ class VideoStudentViewHandlers(object):
 
         elif dispatch == 'download':
             try:
-                transcript_content, transcript_filename, transcript_mime_type = self.get_transcript(self.transcript_download_format)
+                transcript_content, transcript_filename, transcript_mime_type = self.get_transcript(
+                    transcripts, transcript_format=self.transcript_download_format
+                )
             except (NotFoundError, ValueError, KeyError, UnicodeDecodeError):
                 log.debug("Video@download exception")
                 return Response(status=404)
@@ -246,8 +267,9 @@ class VideoStudentViewHandlers(object):
                 )
                 response.content_type = transcript_mime_type
 
-        elif dispatch == 'available_translations':
-            available_translations = self.available_translations()
+        elif dispatch.startswith('available_translations'):
+
+            available_translations = self.available_translations(transcripts)
             if available_translations:
                 response = Response(json.dumps(available_translations))
                 response.content_type = 'application/json'
diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py
index 8c80f79d14e87cde6a0c93ee5d32921eb23cdba2..d424a9352ce4bf8b61705345de34e3337e2a696a 100644
--- a/common/lib/xmodule/xmodule/video_module/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module/video_module.py
@@ -1,3 +1,4 @@
+
 # -*- coding: utf-8 -*-
 # pylint: disable=abstract-method
 """Video is ungraded Xmodule for support video content.
@@ -37,7 +38,8 @@ from xmodule.xml_module import is_pointer_tag, name_to_pathname, deserialize_fie
 from xmodule.exceptions import NotFoundError
 
 from .transcripts_utils import VideoTranscriptsMixin
-from .video_utils import create_youtube_string, get_video_from_cdn
+from .video_utils import create_youtube_string, get_video_from_cdn, get_poster
+from .bumper_utils import bumperize
 from .video_xfields import VideoFields
 from .video_handlers import VideoStudentViewHandlers, VideoStudioViewHandlers
 
@@ -117,11 +119,21 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
             resource_string(module, 'js/src/video/03_video_player.js'),
             resource_string(module, 'js/src/video/035_video_accessible_menu.js'),
             resource_string(module, 'js/src/video/04_video_control.js'),
+            resource_string(module, 'js/src/video/04_video_full_screen.js'),
             resource_string(module, 'js/src/video/05_video_quality_control.js'),
             resource_string(module, 'js/src/video/06_video_progress_slider.js'),
             resource_string(module, 'js/src/video/07_video_volume_control.js'),
             resource_string(module, 'js/src/video/08_video_speed_control.js'),
             resource_string(module, 'js/src/video/09_video_caption.js'),
+            resource_string(module, 'js/src/video/09_play_placeholder.js'),
+            resource_string(module, 'js/src/video/09_play_pause_control.js'),
+            resource_string(module, 'js/src/video/09_play_skip_control.js'),
+            resource_string(module, 'js/src/video/09_skip_control.js'),
+            resource_string(module, 'js/src/video/09_bumper.js'),
+            resource_string(module, 'js/src/video/09_save_state_plugin.js'),
+            resource_string(module, 'js/src/video/09_events_plugin.js'),
+            resource_string(module, 'js/src/video/09_events_bumper_plugin.js'),
+            resource_string(module, 'js/src/video/09_poster.js'),
             resource_string(module, 'js/src/video/095_video_context_menu.js'),
             resource_string(module, 'js/src/video/10_commands.js'),
             resource_string(module, 'js/src/video/10_main.js')
@@ -133,9 +145,13 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
     ]}
     js_module_name = "Video"
 
-    def get_transcripts_for_student(self):
+    def get_transcripts_for_student(self, transcripts):
         """Return transcript information necessary for rendering the XModule student view.
         This is more or less a direct extraction from `get_html`.
+
+        Args:
+            transcripts (dict): A dict with all transcripts and a sub.
+
         Returns:
             Tuple of (track_url, transcript_language, sorted_languages)
             track_url -> subtitle download url
@@ -143,31 +159,27 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
             sorted_languages -> dictionary of available transcript languages
         """
         track_url = None
+        sub, other_lang = transcripts["sub"], transcripts["transcripts"]
         if self.download_track:
             if self.track:
                 track_url = self.track
-            elif self.sub or self.transcripts:
+            elif sub or other_lang:
                 track_url = self.runtime.handler_url(self, 'transcript', 'download').rstrip('/?')
 
-        if not self.transcripts:
-            transcript_language = u'en'
-            languages = {'en': 'English'}
-        else:
-            transcript_language = self.get_default_transcript_language()
-
-            native_languages = {lang: label for lang, label in settings.LANGUAGES if len(lang) == 2}
-            languages = {
-                lang: native_languages.get(lang, display)
-                for lang, display in settings.ALL_LANGUAGES
-                if lang in self.transcripts
-            }
+        transcript_language = self.get_default_transcript_language(transcripts)
 
-            if self.sub:
-                languages['en'] = 'English'
+        native_languages = {lang: label for lang, label in settings.LANGUAGES if len(lang) == 2}
+        languages = {
+            lang: native_languages.get(lang, display)
+            for lang, display in settings.ALL_LANGUAGES
+            if lang in other_lang
+        }
+        if not other_lang or (other_lang and sub):
+            languages['en'] = 'English'
 
         # OrderedDict for easy testing of rendered context in tests
         sorted_languages = sorted(languages.items(), key=itemgetter(1))
-        if 'table' in self.transcripts:
+        if 'table' in other_lang:
             sorted_languages.insert(0, ('table', 'Table of Contents'))
 
         sorted_languages = OrderedDict(sorted_languages)
@@ -233,7 +245,7 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
             elif self.html5_sources:
                 download_video_link = self.html5_sources[0]
 
-        track_url, transcript_language, sorted_languages = self.get_transcripts_for_student()
+        track_url, transcript_language, sorted_languages = self.get_transcripts_for_student(self.get_transcripts_info())
 
         # CDN_VIDEO_URLS is only to be used here and will be deleted
         # TODO(ali@edx.org): Delete this after the CDN experiment has completed.
@@ -250,42 +262,73 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers,
             cdn_eval = False
             cdn_exp_group = None
 
-        return self.system.render_template('video.html', {
-            'ajax_url': self.system.ajax_url + '/save_user_state',
+        self.youtube_streams = youtube_streams or create_youtube_string(self)  # pylint: disable=W0201
+        metadata = {
+            'saveStateUrl': self.system.ajax_url + '/save_user_state',
             'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', False),
+            'streams': self.youtube_streams,
+            'sub': self.sub,
+            'sources': sources,
+
+            # This won't work when we move to data that
+            # isn't on the filesystem
+            'captionDataDir': getattr(self, 'data_dir', None),
+
+            'showCaptions': json.dumps(self.show_captions),
+            'generalSpeed': self.global_speed,
+            'speed': self.speed,
+            'savedVideoPosition': self.saved_video_position.total_seconds(),
+            'start': self.start_time.total_seconds(),
+            'end': self.end_time.total_seconds(),
+            'transcriptLanguage': transcript_language,
+            'transcriptLanguages': sorted_languages,
+
+            # TODO: Later on the value 1500 should be taken from some global
+            # configuration setting field.
+            'ytTestTimeout': 1500,
+
+            'ytApiUrl': settings.YOUTUBE['API'],
+            'ytTestUrl': settings.YOUTUBE['TEST_URL'],
+            'transcriptTranslationUrl': self.runtime.handler_url(
+                self, 'transcript', 'translation/__lang__'
+            ).rstrip('/?'),
+            'transcriptAvailableTranslationsUrl': self.runtime.handler_url(
+                self, 'transcript', 'available_translations'
+            ).rstrip('/?'),
+
+            ## For now, the option "data-autohide-html5" is hard coded. This option
+            ## either enables or disables autohiding of controls and captions on mouse
+            ## inactivity. If set to true, controls and captions will autohide for
+            ## HTML5 sources (non-YouTube) after a period of mouse inactivity over the
+            ## whole video. When the mouse moves (or a key is pressed while any part of
+            ## the video player is focused), the captions and controls will be shown
+            ## once again.
+            ##
+            ## There is no option in the "Advanced Editor" to set this option. However,
+            ## this option will have an effect if changed to "True". The code on
+            ## front-end exists.
+            'autohideHtml5': False
+        }
+
+        bumperize(self)
+
+        context = {
+            'bumper_metadata': json.dumps(self.bumper['metadata']),  # pylint: disable=E1101
+            'metadata': json.dumps(OrderedDict(metadata)),
+            'poster': json.dumps(get_poster(self)),
             'branding_info': branding_info,
             'cdn_eval': cdn_eval,
             'cdn_exp_group': cdn_exp_group,
-            # This won't work when we move to data that
-            # isn't on the filesystem
-            'data_dir': getattr(self, 'data_dir', None),
+            'id': self.location.html_id(),
             'display_name': self.display_name_with_default,
-            'end': self.end_time.total_seconds(),
             'handout': self.handout,
-            'id': self.location.html_id(),
-            'show_captions': json.dumps(self.show_captions),
             'download_video_link': download_video_link,
-            'sources': json.dumps(sources),
-            'speed': json.dumps(self.speed),
-            'general_speed': self.global_speed,
-            'saved_video_position': self.saved_video_position.total_seconds(),
-            'start': self.start_time.total_seconds(),
-            'sub': self.sub,
             'track': track_url,
-            'youtube_streams': youtube_streams or create_youtube_string(self),
-            # TODO: Later on the value 1500 should be taken from some global
-            # configuration setting field.
-            'yt_test_timeout': 1500,
-            'yt_api_url': settings.YOUTUBE['API'],
-            'yt_test_url': settings.YOUTUBE['TEST_URL'],
             'transcript_download_format': transcript_download_format,
             'transcript_download_formats_list': self.descriptor.fields['transcript_download_format'].values,
-            'transcript_language': transcript_language,
-            'transcript_languages': json.dumps(sorted_languages),
-            'transcript_translation_url': self.runtime.handler_url(self, 'transcript', 'translation').rstrip('/?'),
-            'transcript_available_translations_url': self.runtime.handler_url(self, 'transcript', 'available_translations').rstrip('/?'),
             'license': getattr(self, "license", None),
-        })
+        }
+        return self.system.render_template('video.html', context)
 
 
 @XBlock.wants("settings")
@@ -670,7 +713,10 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
         def _update_transcript_for_index(language=None):
             """ Find video transcript - if not found, don't update index """
             try:
-                transcript = self.get_transcript(transcript_format='txt', lang=language)[0].replace("\n", " ")
+                transcripts = self.get_transcripts_info()
+                transcript = self.get_transcript(
+                    transcripts, transcript_format='txt', lang=language
+                )[0].replace("\n", " ")
                 transcript_index_name = "transcript_{}".format(language if language else self.transcript_language)
                 video_body.update({transcript_index_name: transcript})
             except NotFoundError:
diff --git a/common/lib/xmodule/xmodule/video_module/video_utils.py b/common/lib/xmodule/xmodule/video_module/video_utils.py
index 428e50e05e9fda8edf6059853e5c6ec60aeb9065..dc556dea690bfe0e033e6a0efb9196e37bcfef07 100644
--- a/common/lib/xmodule/xmodule/video_module/video_utils.py
+++ b/common/lib/xmodule/xmodule/video_module/video_utils.py
@@ -3,9 +3,14 @@
 Module contains utils specific for video_module but not for transcripts.
 """
 import json
+from collections import OrderedDict
 import logging
 import urllib
 import requests
+from urllib import urlencode
+from urlparse import parse_qs, urlsplit, urlunsplit
+
+from django.conf import settings
 
 from requests.exceptions import RequestException
 
@@ -71,3 +76,40 @@ def get_video_from_cdn(cdn_base_url, original_video_url):
         return cdn_content['sources'][0]
     else:
         return None
+
+
+def get_poster(video):
+    """
+    Generate poster metadata.
+
+    youtube_streams is string that contains '1.00:youtube_id'
+
+    Poster metadata is dict of youtube url for image thumbnail and edx logo
+    """
+    if not video.bumper.get("enabled"):
+        return
+
+    poster = OrderedDict({"url": "", "type": ""})
+
+    if video.youtube_streams:
+        youtube_id = video.youtube_streams.split('1.00:')[1].split(',')[0]
+        poster["url"] = settings.YOUTUBE['IMAGE_API'].format(youtube_id=youtube_id)
+        poster["type"] = "youtube"
+    else:
+        poster["url"] = "https://www.edx.org/sites/default/files/theme/edx-logo-header.png"
+        poster["type"] = "html5"
+
+    return poster
+
+
+def set_query_parameter(url, param_name, param_value):
+    """
+    Given a URL, set or replace a query parameter and return the
+    modified URL.
+    """
+    scheme, netloc, path, query_string, fragment = urlsplit(url)
+    query_params = parse_qs(query_string)
+    query_params[param_name] = [param_value]
+    new_query_string = urlencode(query_params, doseq=True)
+
+    return urlunsplit((scheme, netloc, path, new_query_string, fragment))
diff --git a/common/lib/xmodule/xmodule/video_module/video_xfields.py b/common/lib/xmodule/xmodule/video_module/video_xfields.py
index 5bf2195b8836a1ed1193e14a0bc13b86819de31c..83375f23ab29c3e80ef9956cd8f03b9ba161f9b2 100644
--- a/common/lib/xmodule/xmodule/video_module/video_xfields.py
+++ b/common/lib/xmodule/xmodule/video_module/video_xfields.py
@@ -3,7 +3,7 @@ XFields for video module.
 """
 import datetime
 
-from xblock.fields import Scope, String, Float, Boolean, List, Dict
+from xblock.fields import Scope, String, Float, Boolean, List, Dict, DateTime
 
 from xmodule.fields import RelativeTime
 from xmodule.mixin import LicenseMixin
@@ -142,7 +142,7 @@ class VideoFields(LicenseMixin):
     )
     speed = Float(
         help=_("The last speed that the user specified for the video."),
-        scope=Scope.user_state,
+        scope=Scope.user_state
     )
     global_speed = Float(
         help=_("The default speed for the video."),
@@ -174,3 +174,12 @@ class VideoFields(LicenseMixin):
         scope=Scope.settings,
         default="",
     )
+    bumper_last_view_date = DateTime(
+        display_name=_("Date of the last view of the bumper"),
+        scope=Scope.preferences,
+    )
+    bumper_do_not_show_again = Boolean(
+        display_name=_("Do not show bumper again"),
+        scope=Scope.preferences,
+        default=False,
+    )
diff --git a/common/test/acceptance/pages/lms/video/video.py b/common/test/acceptance/pages/lms/video/video.py
index 86150798ee60988f40266def182f18e634beb15c..c730023466491378b8a4ac1c0a74a5536a83a803 100644
--- a/common/test/acceptance/pages/lms/video/video.py
+++ b/common/test/acceptance/pages/lms/video/video.py
@@ -3,6 +3,7 @@ Video player in the courseware.
 """
 
 import time
+import json
 import requests
 from selenium.webdriver.common.action_chains import ActionChains
 from bok_choy.page_object import PageObject
@@ -21,10 +22,12 @@ VIDEO_BUTTONS = {
     'download_transcript': '.video-tracks > a',
     'speed': '.speeds',
     'quality': '.quality-control',
+    'do_not_show_again': '.skip-control',
+    'skip_bumper': '.play-skip-control',
 }
 
 CSS_CLASS_NAMES = {
-    'closed_captions': '.closed .subtitles',
+    'closed_captions': '.video.closed',
     'captions_rendered': '.video.is-captions-rendered',
     'captions': '.subtitles',
     'captions_text': '.subtitles > li',
@@ -37,7 +40,8 @@ CSS_CLASS_NAMES = {
     'video_time': 'div.vidtime',
     'video_display_name': '.vert h2',
     'captions_lang_list': '.langs-list li',
-    'video_speed': '.speeds .value'
+    'video_speed': '.speeds .value',
+    'poster': '.poster',
 }
 
 VIDEO_MODES = {
@@ -79,7 +83,7 @@ class VideoPage(PageObject):
         self.wait_for_element_presence(video_selector, 'Video is initialized')
 
     @wait_for_js
-    def wait_for_video_player_render(self):
+    def wait_for_video_player_render(self, autoplay=False):
         """
         Wait until Video Player Rendered Completely.
 
@@ -88,7 +92,12 @@ class VideoPage(PageObject):
         self.wait_for_element_presence(CSS_CLASS_NAMES['video_init'], 'Video Player Initialized')
         self.wait_for_element_presence(CSS_CLASS_NAMES['video_time'], 'Video Player Initialized')
 
-        video_player_buttons = ['volume', 'play', 'fullscreen', 'speed']
+        video_player_buttons = ['volume', 'fullscreen', 'speed']
+        if autoplay:
+            video_player_buttons.append('pause')
+        else:
+            video_player_buttons.append('play')
+
         for button in video_player_buttons:
             self.wait_for_element_visibility(VIDEO_BUTTONS[button], '{} button is visible'.format(button.title()))
 
@@ -106,6 +115,34 @@ class VideoPage(PageObject):
 
         self.wait_for_ajax()
 
+    @wait_for_js
+    def wait_for_video_bumper_render(self):
+        """
+        Wait until Poster, Video Pre-Roll and main Video Player are Rendered Completely.
+        """
+        self.wait_for_video_class()
+        self.wait_for_element_presence(CSS_CLASS_NAMES['video_init'], 'Video Player Initialized')
+        self.wait_for_element_presence(CSS_CLASS_NAMES['video_time'], 'Video Player Initialized')
+
+        video_player_buttons = ['do_not_show_again', 'skip_bumper', 'volume']
+        for button in video_player_buttons:
+            self.wait_for_element_visibility(VIDEO_BUTTONS[button], '{} button is visible'.format(button.title()))
+
+    @property
+    def is_poster_shown(self):
+        """
+        Check whether a poster is show.
+        """
+        selector = self.get_element_selector(CSS_CLASS_NAMES['poster'])
+        return self.q(css=selector).visible
+
+    def click_on_poster(self):
+        """
+        Click on the video poster.
+        """
+        selector = self.get_element_selector(CSS_CLASS_NAMES['poster'])
+        self.q(css=selector).click()
+
     def get_video_vertical_selector(self, video_display_name=None):
         """
         Get selector for a video vertical with display name specified by `video_display_name`.
@@ -184,19 +221,14 @@ class VideoPage(PageObject):
     @property
     def is_autoplay_enabled(self):
         """
-        Extract `data-autoplay` attribute to check video autoplay is enabled or disabled.
+        Extract autoplay value of `data-metadata` attribute to check video autoplay is enabled or disabled.
 
         Returns:
             bool: Tells if autoplay enabled/disabled.
-
         """
         selector = self.get_element_selector(CSS_CLASS_NAMES['video_container'])
-        auto_play = self.q(css=selector).attrs('data-autoplay')[0]
-
-        if auto_play.lower() == 'false':
-            return False
-
-        return True
+        auto_play = json.loads(self.q(css=selector).attrs('data-metadata')[0])['autoplay']
+        return auto_play
 
     @property
     def is_error_message_shown(self):
@@ -268,6 +300,7 @@ class VideoPage(PageObject):
             bool: True means captions are visible, False means captions are not visible
 
         """
+        self.wait_for_ajax()
         caption_state_selector = self.get_element_selector(CSS_CLASS_NAMES['closed_captions'])
         return not self.q(css=caption_state_selector).present
 
@@ -515,6 +548,7 @@ class VideoPage(PageObject):
 
         language_selector = VIDEO_MENUS["language"] + ' li[data-lang-code="{code}"]'.format(code=code)
         language_selector = self.get_element_selector(language_selector)
+
         self.wait_for_element_visibility(language_selector, 'language menu is visible')
         self.q(css=language_selector).first.click()
 
diff --git a/common/test/acceptance/pages/studio/settings_advanced.py b/common/test/acceptance/pages/studio/settings_advanced.py
index 0dfad8cf44570ebd0f02439623b4a4b7705c1a9f..dfca78bd55faa6768b27305321121f6ad7c46d86 100644
--- a/common/test/acceptance/pages/studio/settings_advanced.py
+++ b/common/test/acceptance/pages/studio/settings_advanced.py
@@ -200,4 +200,5 @@ class AdvancedSettingsPage(CoursePage):
             'social_sharing_url',
             'teams_configuration',
             'minimum_grade_credit',
+            'video_bumper',
         ]
diff --git a/common/test/acceptance/tests/video/test_video_events.py b/common/test/acceptance/tests/video/test_video_events.py
index dabe17bda2a9c03d5398f4d99219f045517b4143..f851a02bcaea3219d016eaab21caac7d5b29efc8 100644
--- a/common/test/acceptance/tests/video/test_video_events.py
+++ b/common/test/acceptance/tests/video/test_video_events.py
@@ -2,15 +2,62 @@
 
 import datetime
 import json
+import ddt
 
 from ..helpers import EventsTestMixin
 from .test_video_module import VideoBaseTest
+from ...pages.lms.video.video import _parse_time_str
 
 from openedx.core.lib.tests.assertions.events import assert_event_matches, assert_events_equal
 from opaque_keys.edx.keys import UsageKey, CourseKey
 
 
-class VideoEventsTest(EventsTestMixin, VideoBaseTest):
+class VideoEventsTestMixin(EventsTestMixin, VideoBaseTest):
+    """
+    Useful helper methods to test video player event emission.
+    """
+    def assert_payload_contains_ids(self, video_event):
+        """
+        Video events should all contain "id" and "code" attributes in their payload.
+
+        This function asserts that those fields are present and have correct values.
+        """
+        video_descriptors = self.course_fixture.get_nested_xblocks(category='video')
+        video_desc = video_descriptors[0]
+        video_locator = UsageKey.from_string(video_desc.locator)
+
+        expected_event = {
+            'event': {
+                'id': video_locator.html_id(),
+                'code': '3_yD_cEKoCk'
+            }
+        }
+        self.assert_events_match([expected_event], [video_event])
+
+    def assert_valid_control_event_at_time(self, video_event, time_in_seconds):
+        """
+        Video control events should contain valid ID fields and a valid "currentTime" field.
+
+        This function asserts that those fields are present and have correct values.
+        """
+        current_time = json.loads(video_event['event'])['currentTime']
+        self.assertAlmostEqual(current_time, time_in_seconds, delta=1)
+
+    def assert_field_type(self, event_dict, field, field_type):
+        """Assert that a particular `field` in the `event_dict` has a particular type"""
+        self.assertIn(field, event_dict, '{0} not found in the root of the event'.format(field))
+        self.assertTrue(
+            isinstance(event_dict[field], field_type),
+            'Expected "{key}" to be a "{field_type}", but it has the value "{value}" of type "{t}"'.format(
+                key=field,
+                value=event_dict[field],
+                t=type(event_dict[field]),
+                field_type=field_type,
+            )
+        )
+
+
+class VideoEventsTest(VideoEventsTestMixin):
     """ Test video player event emission """
 
     def test_video_control_events(self):
@@ -47,33 +94,197 @@ class VideoEventsTest(EventsTestMixin, VideoBaseTest):
                 assert_event_matches({'event_type': 'pause_video'}, video_event)
                 self.assert_valid_control_event_at_time(video_event, self.video.seconds)
 
-    def assert_payload_contains_ids(self, video_event):
+    def test_strict_event_format(self):
         """
-        Video events should all contain "id" and "code" attributes in their payload.
+        This test makes a very strong assertion about the fields present in events. The goal of it is to ensure that new
+        fields are not added to all events mistakenly. It should be the only existing test that is updated when new top
+        level fields are added to all events.
+        """
+
+        captured_events = []
+        with self.capture_events(lambda e: e['event_type'] == 'load_video', captured_events=captured_events):
+            self.navigate_to_video()
+
+        load_video_event = captured_events[0]
+
+        # Validate the event payload
+        self.assert_payload_contains_ids(load_video_event)
+
+        # We cannot predict the value of these fields so we make weaker assertions about them
+        dynamic_string_fields = (
+            'accept_language',
+            'agent',
+            'host',
+            'ip',
+            'event',
+            'session'
+        )
+        for field in dynamic_string_fields:
+            self.assert_field_type(load_video_event, field, basestring)
+            self.assertIn(field, load_video_event, '{0} not found in the root of the event'.format(field))
+            del load_video_event[field]
+
+        # A weak assertion for the timestamp as well
+        self.assert_field_type(load_video_event, 'time', datetime.datetime)
+        del load_video_event['time']
+
+        # Note that all unpredictable fields have been deleted from the event at this point
+
+        course_key = CourseKey.from_string(self.course_id)
+        static_fields_pattern = {
+            'context': {
+                'course_id': unicode(course_key),
+                'org_id': course_key.org,
+                'path': '/event',
+                'user_id': self.user_info['user_id']
+            },
+            'event_source': 'browser',
+            'event_type': 'load_video',
+            'username': self.user_info['username'],
+            'page': self.browser.current_url,
+            'referer': self.browser.current_url,
+            'name': 'load_video',
+        }
+        assert_events_equal(static_fields_pattern, load_video_event)
+
+
+@ddt.ddt
+class VideoBumperEventsTest(VideoEventsTestMixin):
+    """ Test bumper video event emission """
+
+    # helper methods
+    def watch_video_and_skip(self):
+        """
+        Wait 5 seconds and press "skip" button.
+        """
+        self.video.wait_for_position('0:05')
+        self.video.click_player_button('skip_bumper')
+
+    def watch_video_and_dismiss(self):
+        """
+        Wait 5 seconds and press "do not show again" button.
+        """
+        self.video.wait_for_position('0:05')
+        self.video.click_player_button('do_not_show_again')
+
+    def wait_for_state(self, state='finished'):
+        """
+        Wait until video will be in given state.
+
+        Finished state means that video is played to the end.
+        """
+        self.video.wait_for_state(state)
+
+    def add_bumper(self):
+        """
+        Add video bumper to the course.
+        """
+        additional_data = {
+            u'video_bumper': {
+                u'value': {
+                    "transcripts": {},
+                    "video_id": "edx_video_id"
+                }
+            }
+        }
+        self.course_fixture.add_advanced_settings(additional_data)
+
+    @ddt.data(
+        ('edx.video.bumper.skipped', watch_video_and_skip),
+        ('edx.video.bumper.dismissed', watch_video_and_dismiss),
+        ('edx.video.bumper.stopped', wait_for_state)
+    )
+    @ddt.unpack
+    def test_video_control_events(self, event_type, action):
+        """
+        Scenario: Video component with pre-roll emits events correctly
+        Given the course has a Video component in "Youtube" mode with pre-roll enabled
+        And I click on the video poster
+        And the pre-roll video start playing
+        And I watch (5 seconds/5 seconds/to the end of) it
+        And I click (skip/do not show again) video button
+
+        Then a "edx.video.bumper.loaded" event is emitted
+        And a "edx.video.bumper.played" event is emitted
+        And a "edx.video.bumper.skipped/dismissed/stopped" event is emitted
+        And a "load_video" event is emitted
+        And a "play_video" event is emitted
+        """
+
+        def is_video_event(event):
+            """Filter out anything other than the video events of interest"""
+            return event['event_type'] in (
+                'edx.video.bumper.loaded',
+                'edx.video.bumper.played',
+                'edx.video.bumper.skipped',
+                'edx.video.bumper.dismissed',
+                'edx.video.bumper.stopped',
+                'load_video',
+                'play_video',
+                'pause_video'
+            ) and self.video.state != 'buffering'
+
+        captured_events = []
+        self.add_bumper()
+        with self.capture_events(is_video_event, number_of_matches=5, captured_events=captured_events):
+            self.navigate_to_video_no_render()
+            self.video.click_on_poster()
+            self.video.wait_for_video_bumper_render()
+            sources, duration = self.video.sources[0], self.video.duration
+            action(self)
+
+        # Filter subsequent events that appear due to bufferisation: edx.video.bumper.played
+        # As bumper does not emit pause event, we filter subsequent edx.video.bumper.played events from
+        # the list, except first.
+        filtered_events = []
+        for video_event in captured_events:
+            is_played_event = video_event['event_type'] == 'edx.video.bumper.played'
+            appears_again = filtered_events and video_event['event_type'] == filtered_events[-1]['event_type']
+            if is_played_event and appears_again:
+                continue
+            filtered_events.append(video_event)
+
+        for idx, video_event in enumerate(filtered_events):
+            if idx < 3:
+                self.assert_bumper_payload_contains_ids(video_event, sources, duration)
+            else:
+                self.assert_payload_contains_ids(video_event)
+
+            if idx == 0:
+                assert_event_matches({'event_type': 'edx.video.bumper.loaded'}, video_event)
+            elif idx == 1:
+                assert_event_matches({'event_type': 'edx.video.bumper.played'}, video_event)
+                self.assert_valid_control_event_at_time(video_event, 0)
+            elif idx == 2:
+                assert_event_matches({'event_type': event_type}, video_event)
+            elif idx == 3:
+                assert_event_matches({'event_type': 'load_video'}, video_event)
+            elif idx == 4:
+                assert_event_matches({'event_type': 'play_video'}, video_event)
+                self.assert_valid_control_event_at_time(video_event, 0)
+
+    def assert_bumper_payload_contains_ids(self, video_event, sources, duration):
+        """
+        Bumper video events should all contain "host_component_id", "bumper_id",
+        "duration", "code" attributes in their payload.
 
         This function asserts that those fields are present and have correct values.
         """
+        self.add_bumper()
         video_descriptors = self.course_fixture.get_nested_xblocks(category='video')
         video_desc = video_descriptors[0]
         video_locator = UsageKey.from_string(video_desc.locator)
 
         expected_event = {
             'event': {
-                'id': video_locator.html_id(),
-                'code': '3_yD_cEKoCk'
+                'host_component_id': video_locator.html_id(),
+                'bumper_id': sources,
+                'duration': _parse_time_str(duration),
+                'code': 'html5'
             }
         }
         self.assert_events_match([expected_event], [video_event])
 
-    def assert_valid_control_event_at_time(self, video_event, time_in_seconds):
-        """
-        Video control events should contain valid ID fields and a valid "currentTime" field.
-
-        This function asserts that those fields are present and have correct values.
-        """
-        current_time = json.loads(video_event['event'])['currentTime']
-        self.assertAlmostEqual(current_time, time_in_seconds, delta=1)
-
     def test_strict_event_format(self):
         """
         This test makes a very strong assertion about the fields present in events. The goal of it is to ensure that new
@@ -82,13 +293,17 @@ class VideoEventsTest(EventsTestMixin, VideoBaseTest):
         """
 
         captured_events = []
-        with self.capture_events(lambda e: e['event_type'] == 'load_video', captured_events=captured_events):
-            self.navigate_to_video()
+        self.add_bumper()
+        filter_event = lambda e: e['event_type'] == 'edx.video.bumper.loaded'
+        with self.capture_events(filter_event, captured_events=captured_events):
+            self.navigate_to_video_no_render()
+            self.video.click_on_poster()
 
         load_video_event = captured_events[0]
 
         # Validate the event payload
-        self.assert_payload_contains_ids(load_video_event)
+        sources, duration = self.video.sources[0], self.video.duration
+        self.assert_bumper_payload_contains_ids(load_video_event, sources, duration)
 
         # We cannot predict the value of these fields so we make weaker assertions about them
         dynamic_string_fields = (
@@ -119,23 +334,10 @@ class VideoEventsTest(EventsTestMixin, VideoBaseTest):
                 'user_id': self.user_info['user_id']
             },
             'event_source': 'browser',
-            'event_type': 'load_video',
+            'event_type': 'edx.video.bumper.loaded',
             'username': self.user_info['username'],
             'page': self.browser.current_url,
             'referer': self.browser.current_url,
-            'name': 'load_video',
+            'name': 'edx.video.bumper.loaded',
         }
         assert_events_equal(static_fields_pattern, load_video_event)
-
-    def assert_field_type(self, event_dict, field, field_type):
-        """Assert that a particular `field` in the `event_dict` has a particular type"""
-        self.assertIn(field, event_dict, '{0} not found in the root of the event'.format(field))
-        self.assertTrue(
-            isinstance(event_dict[field], field_type),
-            'Expected "{key}" to be a "{field_type}", but it has the value "{value}" of type "{t}"'.format(
-                key=field,
-                value=event_dict[field],
-                t=type(event_dict[field]),
-                field_type=field_type,
-            )
-        )
diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py
index 727ff7e8ba4fc67bd2f0c9bebc18558eb41a4b4e..48ee3b5dd859d5995716f59d7d46f4c50a875ba8 100644
--- a/common/test/acceptance/tests/video/test_video_module.py
+++ b/common/test/acceptance/tests/video/test_video_module.py
@@ -397,6 +397,7 @@ class YouTubeVideoTest(VideoBaseTest):
             'time_to_response': 2.0,
             'youtube_api_blocked': True,
         })
+
         self.metadata = self.metadata_for_mode('youtube_html5')
 
         self.navigate_to_video()
@@ -711,6 +712,84 @@ class YouTubeVideoTest(VideoBaseTest):
 
         self.assertEqual(self.video.caption_languages, {'zh_HANS': 'Simplified Chinese', 'zh_HANT': 'Traditional Chinese'})
 
+    def test_video_bumper_render(self):
+        """
+        Scenario: Multiple videos with bumper in sequentials all load and work, switching between sequentials
+        Given it has videos "A,B" in "Youtube" and "HTML5" modes in position "1" of sequential
+        And video "C" in "Youtube" mode in position "2" of sequential
+        When I open sequential position "1"
+        Then I see video "B" has a poster
+        When I click on it
+        Then I see video bumper is playing
+        When I skip the bumper
+        Then I see the main video
+        When I click on video "A"
+        Then the main video starts playing
+        When I open sequential position "2"
+        And click on the poster
+        Then the main video starts playing
+        Then I see that the main video starts playing once I go back to position "2" of sequential
+        When I reload the page
+        Then I see that the main video starts playing when I click on the poster
+        """
+        additional_data = {
+            u'video_bumper': {
+                u'value': {
+                    "transcripts": {},
+                    "video_id": "edx_video_id"
+                }
+            }
+        }
+
+        self.verticals = [
+            [{'display_name': 'A'}, {'display_name': 'B', 'metadata': self.metadata_for_mode('html5')}],
+            [{'display_name': 'C'}]
+        ]
+
+        tab1_video_names = ['A', 'B']
+        tab2_video_names = ['C']
+
+        def execute_video_steps(video_names):
+            """
+            Execute video steps
+            """
+            for video_name in video_names:
+                self.video.use_video(video_name)
+                self.assertTrue(self.video.is_poster_shown)
+                self.video.click_on_poster()
+                self.video.wait_for_video_player_render(autoplay=True)
+                self.assertIn(self.video.state, ['playing', 'buffering', 'finished'])
+
+        self.course_fixture.add_advanced_settings(additional_data)
+        self.navigate_to_video_no_render()
+
+        self.video.use_video('B')
+        self.assertTrue(self.video.is_poster_shown)
+        self.video.click_on_poster()
+        self.video.wait_for_video_bumper_render()
+        self.assertIn(self.video.state, ['playing', 'buffering', 'finished'])
+        self.video.click_player_button('skip_bumper')
+
+        # no autoplay here, maybe video is too small, so pause is not switched
+        self.video.wait_for_video_player_render()
+        self.assertIn(self.video.state, ['playing', 'buffering', 'finished'])
+
+        self.video.use_video('A')
+        execute_video_steps(['A'])
+
+        # go to second sequential position
+        self.course_nav.go_to_sequential_position(2)
+
+        execute_video_steps(tab2_video_names)
+
+        # go back to first sequential position
+        # we are again playing tab 1 videos to ensure that switching didn't broke some video functionality.
+        self.course_nav.go_to_sequential_position(1)
+        execute_video_steps(tab1_video_names)
+
+        self.video.browser.refresh()
+        execute_video_steps(tab1_video_names)
+
 
 class YouTubeHtml5VideoTest(VideoBaseTest):
     """ Test YouTube HTML5 Video Player """
diff --git a/common/test/db_cache/bok_choy_data.json b/common/test/db_cache/bok_choy_data.json
index f8500b6768a054ed9c946d579038c4aeb687bfe1..9f41bdda53b2d7fb944b2c1e650a63f5297771f8 100644
--- a/common/test/db_cache/bok_choy_data.json
+++ b/common/test/db_cache/bok_choy_data.json
@@ -1 +1 @@
-[{"pk": 74, "model": "contenttypes.contenttype", "fields": {"model": "accesstoken", "name": "access token", "app_label": "oauth2"}}, {"pk": 151, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifier", "name": "ai classifier", "app_label": "assessment"}}, {"pk": 150, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifierset", "name": "ai classifier set", "app_label": "assessment"}}, {"pk": 153, "model": "contenttypes.contenttype", "fields": {"model": "aigradingworkflow", "name": "ai grading workflow", "app_label": "assessment"}}, {"pk": 152, "model": "contenttypes.contenttype", "fields": {"model": "aitrainingworkflow", "name": "ai training workflow", "app_label": "assessment"}}, {"pk": 34, "model": "contenttypes.contenttype", "fields": {"model": "anonymoususerid", "name": "anonymous user id", "app_label": "student"}}, {"pk": 77, "model": "contenttypes.contenttype", "fields": {"model": "article", "name": "article", "app_label": "wiki"}}, {"pk": 78, "model": "contenttypes.contenttype", "fields": {"model": "articleforobject", "name": "Article for object", "app_label": "wiki"}}, {"pk": 81, "model": "contenttypes.contenttype", "fields": {"model": "articleplugin", "name": "article plugin", "app_label": "wiki"}}, {"pk": 79, "model": "contenttypes.contenttype", "fields": {"model": "articlerevision", "name": "article revision", "app_label": "wiki"}}, {"pk": 86, "model": "contenttypes.contenttype", "fields": {"model": "articlesubscription", "name": "article subscription", "app_label": "wiki"}}, {"pk": 141, "model": "contenttypes.contenttype", "fields": {"model": "assessment", "name": "assessment", "app_label": "assessment"}}, {"pk": 144, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedback", "name": "assessment feedback", "app_label": "assessment"}}, {"pk": 143, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedbackoption", "name": "assessment feedback option", "app_label": "assessment"}}, {"pk": 142, "model": "contenttypes.contenttype", "fields": {"model": "assessmentpart", "name": "assessment part", "app_label": "assessment"}}, {"pk": 154, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflow", "name": "assessment workflow", "app_label": "workflow"}}, {"pk": 156, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowcancellation", "name": "assessment workflow cancellation", "app_label": "workflow"}}, {"pk": 155, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowstep", "name": "assessment workflow step", "app_label": "workflow"}}, {"pk": 19, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "django_openid_auth"}}, {"pk": 25, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "default"}}, {"pk": 70, "model": "contenttypes.contenttype", "fields": {"model": "brandinginfoconfig", "name": "branding info config", "app_label": "branding"}}, {"pk": 57, "model": "contenttypes.contenttype", "fields": {"model": "certificategenerationconfiguration", "name": "certificate generation configuration", "app_label": "certificates"}}, {"pk": 56, "model": "contenttypes.contenttype", "fields": {"model": "certificategenerationcoursesetting", "name": "certificate generation course setting", "app_label": "certificates"}}, {"pk": 58, "model": "contenttypes.contenttype", "fields": {"model": "certificatehtmlviewconfiguration", "name": "certificate html view configuration", "app_label": "certificates"}}, {"pk": 113, "model": "contenttypes.contenttype", "fields": {"model": "certificateitem", "name": "certificate item", "app_label": "shoppingcart"}}, {"pk": 52, "model": "contenttypes.contenttype", "fields": {"model": "certificatewhitelist", "name": "certificate whitelist", "app_label": "certificates"}}, {"pk": 72, "model": "contenttypes.contenttype", "fields": {"model": "client", "name": "client", "app_label": "oauth2"}}, {"pk": 26, "model": "contenttypes.contenttype", "fields": {"model": "code", "name": "code", "app_label": "default"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 22, "model": "contenttypes.contenttype", "fields": {"model": "corsmodel", "name": "cors model", "app_label": "corsheaders"}}, {"pk": 124, "model": "contenttypes.contenttype", "fields": {"model": "country", "name": "country", "app_label": "embargo"}}, {"pk": 125, "model": "contenttypes.contenttype", "fields": {"model": "countryaccessrule", "name": "country access rule", "app_label": "embargo"}}, {"pk": 107, "model": "contenttypes.contenttype", "fields": {"model": "coupon", "name": "coupon", "app_label": "shoppingcart"}}, {"pk": 108, "model": "contenttypes.contenttype", "fields": {"model": "couponredemption", "name": "coupon redemption", "app_label": "shoppingcart"}}, {"pk": 46, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrole", "name": "course access role", "app_label": "student"}}, {"pk": 126, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrulehistory", "name": "course access rule history", "app_label": "embargo"}}, {"pk": 69, "model": "contenttypes.contenttype", "fields": {"model": "courseauthorization", "name": "course authorization", "app_label": "bulk_email"}}, {"pk": 65, "model": "contenttypes.contenttype", "fields": {"model": "coursecohort", "name": "course cohort", "app_label": "course_groups"}}, {"pk": 64, "model": "contenttypes.contenttype", "fields": {"model": "coursecohortssettings", "name": "course cohorts settings", "app_label": "course_groups"}}, {"pk": 165, "model": "contenttypes.contenttype", "fields": {"model": "coursecontentmilestone", "name": "course content milestone", "app_label": "milestones"}}, {"pk": 168, "model": "contenttypes.contenttype", "fields": {"model": "coursecreator", "name": "course creator", "app_label": "course_creators"}}, {"pk": 66, "model": "contenttypes.contenttype", "fields": {"model": "courseemail", "name": "course email", "app_label": "bulk_email"}}, {"pk": 68, "model": "contenttypes.contenttype", "fields": {"model": "courseemailtemplate", "name": "course email template", "app_label": "bulk_email"}}, {"pk": 44, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollment", "name": "course enrollment", "app_label": "student"}}, {"pk": 45, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollmentallowed", "name": "course enrollment allowed", "app_label": "student"}}, {"pk": 164, "model": "contenttypes.contenttype", "fields": {"model": "coursemilestone", "name": "course milestone", "app_label": "milestones"}}, {"pk": 116, "model": "contenttypes.contenttype", "fields": {"model": "coursemode", "name": "course mode", "app_label": "course_modes"}}, {"pk": 117, "model": "contenttypes.contenttype", "fields": {"model": "coursemodesarchive", "name": "course modes archive", "app_label": "course_modes"}}, {"pk": 110, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitem", "name": "course reg code item", "app_label": "shoppingcart"}}, {"pk": 111, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitemannotation", "name": "course reg code item annotation", "app_label": "shoppingcart"}}, {"pk": 105, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcode", "name": "course registration code", "app_label": "shoppingcart"}}, {"pk": 103, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcodeinvoiceitem", "name": "course registration code invoice item", "app_label": "shoppingcart"}}, {"pk": 128, "model": "contenttypes.contenttype", "fields": {"model": "coursererunstate", "name": "course rerun state", "app_label": "course_action_state"}}, {"pk": 60, "model": "contenttypes.contenttype", "fields": {"model": "coursesoftware", "name": "course software", "app_label": "licenses"}}, {"pk": 133, "model": "contenttypes.contenttype", "fields": {"model": "coursestructure", "name": "course structure", "app_label": "course_structures"}}, {"pk": 62, "model": "contenttypes.contenttype", "fields": {"model": "courseusergroup", "name": "course user group", "app_label": "course_groups"}}, {"pk": 63, "model": "contenttypes.contenttype", "fields": {"model": "courseusergrouppartitiongroup", "name": "course user group partition group", "app_label": "course_groups"}}, {"pk": 159, "model": "contenttypes.contenttype", "fields": {"model": "coursevideo", "name": "course video", "app_label": "edxval"}}, {"pk": 139, "model": "contenttypes.contenttype", "fields": {"model": "criterion", "name": "criterion", "app_label": "assessment"}}, {"pk": 140, "model": "contenttypes.contenttype", "fields": {"model": "criterionoption", "name": "criterion option", "app_label": "assessment"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "crontabschedule", "name": "crontab", "app_label": "djcelery"}}, {"pk": 119, "model": "contenttypes.contenttype", "fields": {"model": "darklangconfig", "name": "dark lang config", "app_label": "dark_lang"}}, {"pk": 47, "model": "contenttypes.contenttype", "fields": {"model": "dashboardconfiguration", "name": "dashboard configuration", "app_label": "student"}}, {"pk": 115, "model": "contenttypes.contenttype", "fields": {"model": "donation", "name": "donation", "app_label": "shoppingcart"}}, {"pk": 114, "model": "contenttypes.contenttype", "fields": {"model": "donationconfiguration", "name": "donation configuration", "app_label": "shoppingcart"}}, {"pk": 121, "model": "contenttypes.contenttype", "fields": {"model": "embargoedcourse", "name": "embargoed course", "app_label": "embargo"}}, {"pk": 122, "model": "contenttypes.contenttype", "fields": {"model": "embargoedstate", "name": "embargoed state", "app_label": "embargo"}}, {"pk": 160, "model": "contenttypes.contenttype", "fields": {"model": "encodedvideo", "name": "encoded video", "app_label": "edxval"}}, {"pk": 49, "model": "contenttypes.contenttype", "fields": {"model": "entranceexamconfiguration", "name": "entrance exam configuration", "app_label": "student"}}, {"pk": 55, "model": "contenttypes.contenttype", "fields": {"model": "examplecertificate", "name": "example certificate", "app_label": "certificates"}}, {"pk": 54, "model": "contenttypes.contenttype", "fields": {"model": "examplecertificateset", "name": "example certificate set", "app_label": "certificates"}}, {"pk": 71, "model": "contenttypes.contenttype", "fields": {"model": "externalauthmap", "name": "external auth map", "app_label": "external_auth"}}, {"pk": 53, "model": "contenttypes.contenttype", "fields": {"model": "generatedcertificate", "name": "generated certificate", "app_label": "certificates"}}, {"pk": 73, "model": "contenttypes.contenttype", "fields": {"model": "grant", "name": "grant", "app_label": "oauth2"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 59, "model": "contenttypes.contenttype", "fields": {"model": "instructortask", "name": "instructor task", "app_label": "instructor_task"}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "intervalschedule", "name": "interval", "app_label": "djcelery"}}, {"pk": 100, "model": "contenttypes.contenttype", "fields": {"model": "invoice", "name": "invoice", "app_label": "shoppingcart"}}, {"pk": 104, "model": "contenttypes.contenttype", "fields": {"model": "invoicehistory", "name": "invoice history", "app_label": "shoppingcart"}}, {"pk": 102, "model": "contenttypes.contenttype", "fields": {"model": "invoiceitem", "name": "invoice item", "app_label": "shoppingcart"}}, {"pk": 101, "model": "contenttypes.contenttype", "fields": {"model": "invoicetransaction", "name": "invoice transaction", "app_label": "shoppingcart"}}, {"pk": 127, "model": "contenttypes.contenttype", "fields": {"model": "ipfilter", "name": "ip filter", "app_label": "embargo"}}, {"pk": 48, "model": "contenttypes.contenttype", "fields": {"model": "linkedinaddtoprofileconfiguration", "name": "linked in add to profile configuration", "app_label": "student"}}, {"pk": 21, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 43, "model": "contenttypes.contenttype", "fields": {"model": "loginfailures", "name": "login failures", "app_label": "student"}}, {"pk": 120, "model": "contenttypes.contenttype", "fields": {"model": "midcoursereverificationwindow", "name": "midcourse reverification window", "app_label": "reverification"}}, {"pk": 15, "model": "contenttypes.contenttype", "fields": {"model": "migrationhistory", "name": "migration history", "app_label": "south"}}, {"pk": 162, "model": "contenttypes.contenttype", "fields": {"model": "milestone", "name": "milestone", "app_label": "milestones"}}, {"pk": 163, "model": "contenttypes.contenttype", "fields": {"model": "milestonerelationshiptype", "name": "milestone relationship type", "app_label": "milestones"}}, {"pk": 129, "model": "contenttypes.contenttype", "fields": {"model": "mobileapiconfig", "name": "mobile api config", "app_label": "mobile_api"}}, {"pk": 18, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "django_openid_auth"}}, {"pk": 24, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "default"}}, {"pk": 93, "model": "contenttypes.contenttype", "fields": {"model": "note", "name": "note", "app_label": "notes"}}, {"pk": 90, "model": "contenttypes.contenttype", "fields": {"model": "notification", "name": "notification", "app_label": "django_notify"}}, {"pk": 32, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgrade", "name": "offline computed grade", "app_label": "courseware"}}, {"pk": 33, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgradelog", "name": "offline computed grade log", "app_label": "courseware"}}, {"pk": 67, "model": "contenttypes.contenttype", "fields": {"model": "optout", "name": "optout", "app_label": "bulk_email"}}, {"pk": 98, "model": "contenttypes.contenttype", "fields": {"model": "order", "name": "order", "app_label": "shoppingcart"}}, {"pk": 99, "model": "contenttypes.contenttype", "fields": {"model": "orderitem", "name": "order item", "app_label": "shoppingcart"}}, {"pk": 109, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistration", "name": "paid course registration", "app_label": "shoppingcart"}}, {"pk": 112, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistrationannotation", "name": "paid course registration annotation", "app_label": "shoppingcart"}}, {"pk": 42, "model": "contenttypes.contenttype", "fields": {"model": "passwordhistory", "name": "password history", "app_label": "student"}}, {"pk": 145, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflow", "name": "peer workflow", "app_label": "assessment"}}, {"pk": 146, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflowitem", "name": "peer workflow item", "app_label": "assessment"}}, {"pk": 41, "model": "contenttypes.contenttype", "fields": {"model": "pendingemailchange", "name": "pending email change", "app_label": "student"}}, {"pk": 40, "model": "contenttypes.contenttype", "fields": {"model": "pendingnamechange", "name": "pending name change", "app_label": "student"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "periodictask", "name": "periodic task", "app_label": "djcelery"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "periodictasks", "name": "periodic tasks", "app_label": "djcelery"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 157, "model": "contenttypes.contenttype", "fields": {"model": "profile", "name": "profile", "app_label": "edxval"}}, {"pk": 17, "model": "contenttypes.contenttype", "fields": {"model": "psychometricdata", "name": "psychometric data", "app_label": "psychometrics"}}, {"pk": 92, "model": "contenttypes.contenttype", "fields": {"model": "puzzlecomplete", "name": "puzzle complete", "app_label": "foldit"}}, {"pk": 51, "model": "contenttypes.contenttype", "fields": {"model": "ratelimitconfiguration", "name": "rate limit configuration", "app_label": "util"}}, {"pk": 75, "model": "contenttypes.contenttype", "fields": {"model": "refreshtoken", "name": "refresh token", "app_label": "oauth2"}}, {"pk": 39, "model": "contenttypes.contenttype", "fields": {"model": "registration", "name": "registration", "app_label": "student"}}, {"pk": 106, "model": "contenttypes.contenttype", "fields": {"model": "registrationcoderedemption", "name": "registration code redemption", "app_label": "shoppingcart"}}, {"pk": 123, "model": "contenttypes.contenttype", "fields": {"model": "restrictedcourse", "name": "restricted course", "app_label": "embargo"}}, {"pk": 82, "model": "contenttypes.contenttype", "fields": {"model": "reusableplugin", "name": "reusable plugin", "app_label": "wiki"}}, {"pk": 84, "model": "contenttypes.contenttype", "fields": {"model": "revisionplugin", "name": "revision plugin", "app_label": "wiki"}}, {"pk": 85, "model": "contenttypes.contenttype", "fields": {"model": "revisionpluginrevision", "name": "revision plugin revision", "app_label": "wiki"}}, {"pk": 138, "model": "contenttypes.contenttype", "fields": {"model": "rubric", "name": "rubric", "app_label": "assessment"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "tasksetmeta", "name": "saved group result", "app_label": "djcelery"}}, {"pk": 91, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "foldit"}}, {"pk": 136, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "submissions"}}, {"pk": 137, "model": "contenttypes.contenttype", "fields": {"model": "scoresummary", "name": "score summary", "app_label": "submissions"}}, {"pk": 16, "model": "contenttypes.contenttype", "fields": {"model": "servercircuit", "name": "server circuit", "app_label": "circuit"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 88, "model": "contenttypes.contenttype", "fields": {"model": "settings", "name": "settings", "app_label": "django_notify"}}, {"pk": 83, "model": "contenttypes.contenttype", "fields": {"model": "simpleplugin", "name": "simple plugin", "app_label": "wiki"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 118, "model": "contenttypes.contenttype", "fields": {"model": "softwaresecurephotoverification", "name": "software secure photo verification", "app_label": "verify_student"}}, {"pk": 94, "model": "contenttypes.contenttype", "fields": {"model": "splashconfig", "name": "splash config", "app_label": "splash"}}, {"pk": 134, "model": "contenttypes.contenttype", "fields": {"model": "studentitem", "name": "student item", "app_label": "submissions"}}, {"pk": 27, "model": "contenttypes.contenttype", "fields": {"model": "studentmodule", "name": "student module", "app_label": "courseware"}}, {"pk": 28, "model": "contenttypes.contenttype", "fields": {"model": "studentmodulehistory", "name": "student module history", "app_label": "courseware"}}, {"pk": 148, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflow", "name": "student training workflow", "app_label": "assessment"}}, {"pk": 149, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflowitem", "name": "student training workflow item", "app_label": "assessment"}}, {"pk": 169, "model": "contenttypes.contenttype", "fields": {"model": "studioconfig", "name": "studio config", "app_label": "xblock_config"}}, {"pk": 135, "model": "contenttypes.contenttype", "fields": {"model": "submission", "name": "submission", "app_label": "submissions"}}, {"pk": 89, "model": "contenttypes.contenttype", "fields": {"model": "subscription", "name": "subscription", "app_label": "django_notify"}}, {"pk": 161, "model": "contenttypes.contenttype", "fields": {"model": "subtitle", "name": "subtitle", "app_label": "edxval"}}, {"pk": 131, "model": "contenttypes.contenttype", "fields": {"model": "surveyanswer", "name": "survey answer", "app_label": "survey"}}, {"pk": 130, "model": "contenttypes.contenttype", "fields": {"model": "surveyform", "name": "survey form", "app_label": "survey"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "taskstate", "name": "task", "app_label": "djcelery"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "taskmeta", "name": "task state", "app_label": "djcelery"}}, {"pk": 50, "model": "contenttypes.contenttype", "fields": {"model": "trackinglog", "name": "tracking log", "app_label": "track"}}, {"pk": 147, "model": "contenttypes.contenttype", "fields": {"model": "trainingexample", "name": "training example", "app_label": "assessment"}}, {"pk": 76, "model": "contenttypes.contenttype", "fields": {"model": "trustedclient", "name": "trusted client", "app_label": "oauth2_provider"}}, {"pk": 87, "model": "contenttypes.contenttype", "fields": {"model": "notificationtype", "name": "type", "app_label": "django_notify"}}, {"pk": 80, "model": "contenttypes.contenttype", "fields": {"model": "urlpath", "name": "URL path", "app_label": "wiki"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}, {"pk": 96, "model": "contenttypes.contenttype", "fields": {"model": "usercoursetag", "name": "user course tag", "app_label": "user_api"}}, {"pk": 61, "model": "contenttypes.contenttype", "fields": {"model": "userlicense", "name": "user license", "app_label": "licenses"}}, {"pk": 166, "model": "contenttypes.contenttype", "fields": {"model": "usermilestone", "name": "user milestone", "app_label": "milestones"}}, {"pk": 20, "model": "contenttypes.contenttype", "fields": {"model": "useropenid", "name": "user open id", "app_label": "django_openid_auth"}}, {"pk": 97, "model": "contenttypes.contenttype", "fields": {"model": "userorgtag", "name": "user org tag", "app_label": "user_api"}}, {"pk": 95, "model": "contenttypes.contenttype", "fields": {"model": "userpreference", "name": "user preference", "app_label": "user_api"}}, {"pk": 36, "model": "contenttypes.contenttype", "fields": {"model": "userprofile", "name": "user profile", "app_label": "student"}}, {"pk": 37, "model": "contenttypes.contenttype", "fields": {"model": "usersignupsource", "name": "user signup source", "app_label": "student"}}, {"pk": 23, "model": "contenttypes.contenttype", "fields": {"model": "usersocialauth", "name": "user social auth", "app_label": "default"}}, {"pk": 35, "model": "contenttypes.contenttype", "fields": {"model": "userstanding", "name": "user standing", "app_label": "student"}}, {"pk": 38, "model": "contenttypes.contenttype", "fields": {"model": "usertestgroup", "name": "user test group", "app_label": "student"}}, {"pk": 158, "model": "contenttypes.contenttype", "fields": {"model": "video", "name": "video", "app_label": "edxval"}}, {"pk": 167, "model": "contenttypes.contenttype", "fields": {"model": "videouploadconfig", "name": "video upload config", "app_label": "contentstore"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "workerstate", "name": "worker", "app_label": "djcelery"}}, {"pk": 132, "model": "contenttypes.contenttype", "fields": {"model": "xblockasidesconfig", "name": "x block asides config", "app_label": "lms_xblock"}}, {"pk": 31, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentinfofield", "name": "x module student info field", "app_label": "courseware"}}, {"pk": 30, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentprefsfield", "name": "x module student prefs field", "app_label": "courseware"}}, {"pk": 29, "model": "contenttypes.contenttype", "fields": {"model": "xmoduleuserstatesummaryfield", "name": "x module user state summary field", "app_label": "courseware"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0001_initial"}}, {"pk": 2, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0002_add_indexes"}}, {"pk": 3, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0003_done_grade_cache"}}, {"pk": 4, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0004_add_field_studentmodule_course_id"}}, {"pk": 5, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c"}}, {"pk": 6, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0006_create_student_module_history"}}, {"pk": 7, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0007_allow_null_version_in_history"}}, {"pk": 8, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0008_add_xmodule_storage"}}, {"pk": 9, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0009_add_field_default"}}, {"pk": 10, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0010_rename_xblock_field_content_to_user_state_summary"}}, {"pk": 11, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0001_initial"}}, {"pk": 12, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0002_text_to_varchar_and_indexes"}}, {"pk": 13, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0003_auto__add_usertestgroup"}}, {"pk": 14, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0004_add_email_index"}}, {"pk": 15, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0005_name_change"}}, {"pk": 16, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0006_expand_meta_field"}}, {"pk": 17, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0007_convert_to_utf8"}}, {"pk": 18, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0008__auto__add_courseregistration"}}, {"pk": 19, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0009_auto__del_courseregistration__add_courseenrollment"}}, {"pk": 20, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0010_auto__chg_field_courseenrollment_course_id"}}, {"pk": 21, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0011_auto__chg_field_courseenrollment_user__del_unique_courseenrollment_use"}}, {"pk": 22, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0012_auto__add_field_userprofile_gender__add_field_userprofile_date_of_birt"}}, {"pk": 23, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0013_auto__chg_field_userprofile_meta"}}, {"pk": 24, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0014_auto__del_courseenrollment"}}, {"pk": 25, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0015_auto__add_courseenrollment__add_unique_courseenrollment_user_course_id"}}, {"pk": 26, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0016_auto__add_field_courseenrollment_date__chg_field_userprofile_country"}}, {"pk": 27, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0017_rename_date_to_created"}}, {"pk": 28, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0018_auto"}}, {"pk": 29, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0019_create_approved_demographic_fields_fall_2012"}}, {"pk": 30, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0020_add_test_center_user"}}, {"pk": 31, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0021_remove_askbot"}}, {"pk": 32, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0022_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_"}}, {"pk": 33, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0023_add_test_center_registration"}}, {"pk": 34, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0024_add_allow_certificate"}}, {"pk": 35, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0025_auto__add_field_courseenrollmentallowed_auto_enroll"}}, {"pk": 36, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0026_auto__remove_index_student_testcenterregistration_accommodation_request"}}, {"pk": 37, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0027_add_active_flag_and_mode_to_courseware_enrollment"}}, {"pk": 38, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0028_auto__add_userstanding"}}, {"pk": 39, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0029_add_lookup_table_between_user_and_anonymous_student_id"}}, {"pk": 40, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0029_remove_pearson"}}, {"pk": 41, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0030_auto__chg_field_anonymoususerid_anonymous_user_id"}}, {"pk": 42, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0031_drop_student_anonymoususerid_temp_archive"}}, {"pk": 43, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0032_add_field_UserProfile_country_add_field_UserProfile_city"}}, {"pk": 44, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0032_auto__add_loginfailures"}}, {"pk": 45, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0033_auto__add_passwordhistory"}}, {"pk": 46, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0034_auto__add_courseaccessrole"}}, {"pk": 47, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0035_access_roles"}}, {"pk": 48, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0036_access_roles_orgless"}}, {"pk": 49, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0037_auto__add_courseregistrationcode"}}, {"pk": 50, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0038_auto__add_usersignupsource"}}, {"pk": 51, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0039_auto__del_courseregistrationcode"}}, {"pk": 52, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0040_auto__del_field_usersignupsource_user_id__add_field_usersignupsource_u"}}, {"pk": 53, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0041_add_dashboard_config"}}, {"pk": 54, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0042_grant_sales_admin_roles"}}, {"pk": 55, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0043_auto__add_linkedinaddtoprofileconfiguration"}}, {"pk": 56, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0044_linkedin_add_company_identifier"}}, {"pk": 57, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "student", "migration": "0045_add_trk_partner_to_linkedin_config"}}, {"pk": 58, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "student", "migration": "0046_auto__add_entranceexamconfiguration__add_unique_entranceexamconfigurat"}}, {"pk": 59, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "track", "migration": "0001_initial"}}, {"pk": 60, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "track", "migration": "0002_auto__add_field_trackinglog_host__chg_field_trackinglog_event_type__ch"}}, {"pk": 61, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "util", "migration": "0001_initial"}}, {"pk": 62, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "util", "migration": "0002_default_rate_limit_config"}}, {"pk": 63, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0001_added_generatedcertificates"}}, {"pk": 64, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0002_auto__add_field_generatedcertificate_download_url"}}, {"pk": 65, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0003_auto__add_field_generatedcertificate_enabled"}}, {"pk": 66, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0004_auto__add_field_generatedcertificate_graded_certificate_id__add_field_"}}, {"pk": 67, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0005_auto__add_field_generatedcertificate_name"}}, {"pk": 68, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0006_auto__chg_field_generatedcertificate_certificate_id"}}, {"pk": 69, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0007_auto__add_revokedcertificate"}}, {"pk": 70, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0008_auto__del_revokedcertificate__del_field_generatedcertificate_name__add"}}, {"pk": 71, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0009_auto__del_field_generatedcertificate_graded_download_url__del_field_ge"}}, {"pk": 72, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0010_auto__del_field_generatedcertificate_enabled__add_field_generatedcerti"}}, {"pk": 73, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0011_auto__del_field_generatedcertificate_certificate_id__add_field_generat"}}, {"pk": 74, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0012_auto__add_field_generatedcertificate_name__add_field_generatedcertific"}}, {"pk": 75, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0013_auto__add_field_generatedcertificate_error_reason"}}, {"pk": 76, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0014_adding_whitelist"}}, {"pk": 77, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0015_adding_mode_for_verified_certs"}}, {"pk": 78, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0016_change_course_key_fields"}}, {"pk": 79, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0017_auto__add_certificategenerationconfiguration"}}, {"pk": 80, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0018_add_example_cert_models"}}, {"pk": 81, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0019_auto__add_certificatehtmlviewconfiguration"}}, {"pk": 82, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0020_certificatehtmlviewconfiguration_data"}}, {"pk": 83, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "instructor_task", "migration": "0001_initial"}}, {"pk": 84, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "instructor_task", "migration": "0002_add_subtask_field"}}, {"pk": 85, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "licenses", "migration": "0001_initial"}}, {"pk": 86, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0001_initial"}}, {"pk": 87, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0002_add_model_CourseUserGroupPartitionGroup"}}, {"pk": 88, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0003_auto__add_coursecohort__add_coursecohortssettings"}}, {"pk": 89, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0004_auto__del_field_coursecohortssettings_cohorted_discussions__add_field_"}}, {"pk": 90, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0001_initial"}}, {"pk": 91, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0002_change_field_names"}}, {"pk": 92, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0003_add_optout_user"}}, {"pk": 93, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0004_migrate_optout_user"}}, {"pk": 94, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0005_remove_optout_email"}}, {"pk": 95, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0006_add_course_email_template"}}, {"pk": 96, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0007_load_course_email_template"}}, {"pk": 97, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0008_add_course_authorizations"}}, {"pk": 98, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0009_force_unique_course_ids"}}, {"pk": 99, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0010_auto__chg_field_optout_course_id__add_field_courseemail_template_name_"}}, {"pk": 100, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "branding", "migration": "0001_initial"}}, {"pk": 101, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "external_auth", "migration": "0001_initial"}}, {"pk": 102, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "oauth2", "migration": "0001_initial"}}, {"pk": 103, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "oauth2", "migration": "0002_auto__chg_field_client_user"}}, {"pk": 104, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2", "migration": "0003_auto__add_field_client_name"}}, {"pk": 105, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2", "migration": "0004_auto__add_index_accesstoken_token"}}, {"pk": 106, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2_provider", "migration": "0001_initial"}}, {"pk": 107, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0001_initial"}}, {"pk": 108, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0002_auto__add_field_articleplugin_created"}}, {"pk": 109, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0003_auto__add_field_urlpath_article"}}, {"pk": 110, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0004_populate_urlpath__article"}}, {"pk": 111, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0005_auto__chg_field_urlpath_article"}}, {"pk": 112, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0006_auto__add_attachmentrevision__add_image__add_attachment"}}, {"pk": 113, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0007_auto__add_articlesubscription"}}, {"pk": 114, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0008_auto__add_simpleplugin__add_revisionpluginrevision__add_imagerevision_"}}, {"pk": 115, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0009_auto__add_field_imagerevision_width__add_field_imagerevision_height"}}, {"pk": 116, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "wiki", "migration": "0010_auto__chg_field_imagerevision_image"}}, {"pk": 117, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "wiki", "migration": "0011_auto__chg_field_imagerevision_width__chg_field_imagerevision_height"}}, {"pk": 118, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "django_notify", "migration": "0001_initial"}}, {"pk": 119, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "notifications", "migration": "0001_initial"}}, {"pk": 120, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "foldit", "migration": "0001_initial"}}, {"pk": 121, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "django_comment_client", "migration": "0001_initial"}}, {"pk": 122, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "django_comment_common", "migration": "0001_initial"}}, {"pk": 123, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "notes", "migration": "0001_initial"}}, {"pk": 124, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "splash", "migration": "0001_initial"}}, {"pk": 125, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "splash", "migration": "0002_auto__add_field_splashconfig_unaffected_url_paths"}}, {"pk": 126, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0001_initial"}}, {"pk": 127, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0002_auto__add_usercoursetags__add_unique_usercoursetags_user_course_id_key"}}, {"pk": 128, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0003_rename_usercoursetags"}}, {"pk": 129, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0004_auto__add_userorgtag__add_unique_userorgtag_user_org_key__chg_field_us"}}, {"pk": 130, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0001_initial"}}, {"pk": 131, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0002_auto__add_field_paidcourseregistration_mode"}}, {"pk": 132, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0003_auto__del_field_orderitem_line_cost"}}, {"pk": 133, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0004_auto__add_field_orderitem_fulfilled_time"}}, {"pk": 134, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0005_auto__add_paidcourseregistrationannotation__add_field_orderitem_report"}}, {"pk": 135, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0006_auto__add_field_order_refunded_time__add_field_orderitem_refund_reques"}}, {"pk": 136, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0007_auto__add_field_orderitem_service_fee"}}, {"pk": 137, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou"}}, {"pk": 138, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c"}}, {"pk": 139, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0010_auto__add_registrationcoderedemption__del_field_courseregistrationcode"}}, {"pk": 140, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0011_auto__add_invoice__add_field_courseregistrationcode_invoice"}}, {"pk": 141, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0012_auto__del_field_courseregistrationcode_transaction_group_name__del_fie"}}, {"pk": 142, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0013_auto__add_field_invoice_is_valid"}}, {"pk": 143, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0014_auto__del_field_invoice_tax_id__add_field_invoice_address_line_1__add_"}}, {"pk": 144, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0015_auto__del_field_invoice_purchase_order_number__del_field_invoice_compa"}}, {"pk": 145, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0016_auto__del_field_invoice_company_email__del_field_invoice_company_refer"}}, {"pk": 146, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0017_auto__add_field_courseregistrationcode_order__chg_field_registrationco"}}, {"pk": 147, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0018_auto__add_donation"}}, {"pk": 148, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0019_auto__add_donationconfiguration"}}, {"pk": 149, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0020_auto__add_courseregcodeitem__add_courseregcodeitemannotation__add_fiel"}}, {"pk": 150, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0021_auto__add_field_orderitem_created__add_field_orderitem_modified"}}, {"pk": 151, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0022_auto__add_field_registrationcoderedemption_course_enrollment__add_fiel"}}, {"pk": 152, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0023_auto__add_field_coupon_expiration_date"}}, {"pk": 153, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0024_auto__add_field_courseregistrationcode_mode_slug"}}, {"pk": 154, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0025_update_invoice_models"}}, {"pk": 155, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0026_migrate_invoices"}}, {"pk": 156, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0027_add_invoice_history"}}, {"pk": 157, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0001_initial"}}, {"pk": 158, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0002_auto__add_field_coursemode_currency"}}, {"pk": 159, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0003_auto__add_unique_coursemode_course_id_currency_mode_slug"}}, {"pk": 160, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0004_auto__add_field_coursemode_expiration_date"}}, {"pk": 161, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0005_auto__add_field_coursemode_expiration_datetime"}}, {"pk": 162, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0006_expiration_date_to_datetime"}}, {"pk": 163, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0007_add_description"}}, {"pk": 164, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0007_auto__add_coursemodesarchive__chg_field_coursemode_course_id"}}, {"pk": 165, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0008_auto__del_field_coursemodesarchive_description__add_field_coursemode_s"}}, {"pk": 166, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0001_initial"}}, {"pk": 167, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0002_auto__add_field_softwaresecurephotoverification_window"}}, {"pk": 168, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0003_auto__add_field_softwaresecurephotoverification_display"}}, {"pk": 169, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "dark_lang", "migration": "0001_initial"}}, {"pk": 170, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "dark_lang", "migration": "0002_enable_on_install"}}, {"pk": 171, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "reverification", "migration": "0001_initial"}}, {"pk": 172, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "embargo", "migration": "0001_initial"}}, {"pk": 173, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0002_add_country_access_models"}}, {"pk": 174, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0003_add_countries"}}, {"pk": 175, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0004_migrate_embargo_config"}}, {"pk": 176, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0005_add_courseaccessrulehistory"}}, {"pk": 177, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "course_action_state", "migration": "0001_initial"}}, {"pk": 178, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "course_action_state", "migration": "0002_add_rerun_display_name"}}, {"pk": 179, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "mobile_api", "migration": "0001_initial"}}, {"pk": 180, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "survey", "migration": "0001_initial"}}, {"pk": 181, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "lms_xblock", "migration": "0001_initial"}}, {"pk": 182, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "course_structures", "migration": "0001_initial"}}, {"pk": 183, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0001_initial"}}, {"pk": 184, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0002_auto__add_scoresummary"}}, {"pk": 185, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0003_auto__del_field_submission_answer__add_field_submission_raw_answer"}}, {"pk": 186, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0004_auto__add_field_score_reset"}}, {"pk": 187, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0001_initial"}}, {"pk": 188, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0002_auto__add_assessmentfeedbackoption__del_field_assessmentfeedback_feedb"}}, {"pk": 189, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0003_add_index_pw_course_item_student"}}, {"pk": 190, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0004_auto__add_field_peerworkflow_graded_count"}}, {"pk": 191, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0005_auto__del_field_peerworkflow_graded_count__add_field_peerworkflow_grad"}}, {"pk": 192, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0006_auto__add_field_assessmentpart_feedback"}}, {"pk": 193, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0007_auto__chg_field_assessmentpart_feedback"}}, {"pk": 194, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0008_student_training"}}, {"pk": 195, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0009_auto__add_unique_studenttrainingworkflowitem_order_num_workflow"}}, {"pk": 196, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0010_auto__add_unique_studenttrainingworkflow_submission_uuid"}}, {"pk": 197, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0011_ai_training"}}, {"pk": 198, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0012_move_algorithm_id_to_classifier_set"}}, {"pk": 199, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0013_auto__add_field_aigradingworkflow_essay_text"}}, {"pk": 200, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0014_auto__add_field_aitrainingworkflow_item_id__add_field_aitrainingworkfl"}}, {"pk": 201, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0015_auto__add_unique_aitrainingworkflow_uuid__add_unique_aigradingworkflow"}}, {"pk": 202, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0016_auto__add_field_aiclassifierset_course_id__add_field_aiclassifierset_i"}}, {"pk": 203, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0016_auto__add_field_rubric_structure_hash"}}, {"pk": 204, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0017_rubric_structure_hash"}}, {"pk": 205, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0018_auto__add_field_assessmentpart_criterion"}}, {"pk": 206, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0019_assessmentpart_criterion_field"}}, {"pk": 207, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0020_assessmentpart_criterion_not_null"}}, {"pk": 208, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0021_assessmentpart_option_nullable"}}, {"pk": 209, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0022__add_label_fields"}}, {"pk": 210, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0023_assign_criteria_and_option_labels"}}, {"pk": 211, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0024_auto__chg_field_assessmentpart_criterion"}}, {"pk": 212, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0025_auto__add_field_peerworkflow_cancelled_at"}}, {"pk": 213, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0001_initial"}}, {"pk": 214, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0002_auto__add_field_assessmentworkflow_course_id__add_field_assessmentwork"}}, {"pk": 215, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0003_auto__add_assessmentworkflowstep"}}, {"pk": 216, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0004_auto__add_assessmentworkflowcancellation"}}, {"pk": 217, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0001_initial"}}, {"pk": 218, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0002_default_profiles"}}, {"pk": 219, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0003_status_and_created_fields"}}, {"pk": 220, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0004_remove_profile_fields"}}, {"pk": 221, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "milestones", "migration": "0001_initial"}}, {"pk": 222, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "milestones", "migration": "0002_seed_relationship_types"}}, {"pk": 223, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "django_extensions", "migration": "0001_empty"}}, {"pk": 224, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "contentstore", "migration": "0001_initial"}}, {"pk": 225, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "contentstore", "migration": "0002_auto__del_field_videouploadconfig_status_whitelist"}}, {"pk": 226, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "course_creators", "migration": "0001_initial"}}, {"pk": 227, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:16Z", "app_name": "xblock_config", "migration": "0001_initial"}}, {"pk": 5, "model": "embargo.country", "fields": {"country": "AD"}}, {"pk": 233, "model": "embargo.country", "fields": {"country": "AE"}}, {"pk": 1, "model": "embargo.country", "fields": {"country": "AF"}}, {"pk": 9, "model": "embargo.country", "fields": {"country": "AG"}}, {"pk": 7, "model": "embargo.country", "fields": {"country": "AI"}}, {"pk": 2, "model": "embargo.country", "fields": {"country": "AL"}}, {"pk": 11, "model": "embargo.country", "fields": {"country": "AM"}}, {"pk": 6, "model": "embargo.country", "fields": {"country": "AO"}}, {"pk": 8, "model": "embargo.country", "fields": {"country": "AQ"}}, {"pk": 10, "model": "embargo.country", "fields": {"country": "AR"}}, {"pk": 4, "model": "embargo.country", "fields": {"country": "AS"}}, {"pk": 14, "model": "embargo.country", "fields": {"country": "AT"}}, {"pk": 13, "model": "embargo.country", "fields": {"country": "AU"}}, {"pk": 12, "model": "embargo.country", "fields": {"country": "AW"}}, {"pk": 249, "model": "embargo.country", "fields": {"country": "AX"}}, {"pk": 15, "model": "embargo.country", "fields": {"country": "AZ"}}, {"pk": 28, "model": "embargo.country", "fields": {"country": "BA"}}, {"pk": 19, "model": "embargo.country", "fields": {"country": "BB"}}, {"pk": 18, "model": "embargo.country", "fields": {"country": "BD"}}, {"pk": 21, "model": "embargo.country", "fields": {"country": "BE"}}, {"pk": 35, "model": "embargo.country", "fields": {"country": "BF"}}, {"pk": 34, "model": "embargo.country", "fields": {"country": "BG"}}, {"pk": 17, "model": "embargo.country", "fields": {"country": "BH"}}, {"pk": 36, "model": "embargo.country", "fields": {"country": "BI"}}, {"pk": 23, "model": "embargo.country", "fields": {"country": "BJ"}}, {"pk": 184, "model": "embargo.country", "fields": {"country": "BL"}}, {"pk": 24, "model": "embargo.country", "fields": {"country": "BM"}}, {"pk": 33, "model": "embargo.country", "fields": {"country": "BN"}}, {"pk": 26, "model": "embargo.country", "fields": {"country": "BO"}}, {"pk": 27, "model": "embargo.country", "fields": {"country": "BQ"}}, {"pk": 31, "model": "embargo.country", "fields": {"country": "BR"}}, {"pk": 16, "model": "embargo.country", "fields": {"country": "BS"}}, {"pk": 25, "model": "embargo.country", "fields": {"country": "BT"}}, {"pk": 30, "model": "embargo.country", "fields": {"country": "BV"}}, {"pk": 29, "model": "embargo.country", "fields": {"country": "BW"}}, {"pk": 20, "model": "embargo.country", "fields": {"country": "BY"}}, {"pk": 22, "model": "embargo.country", "fields": {"country": "BZ"}}, {"pk": 39, "model": "embargo.country", "fields": {"country": "CA"}}, {"pk": 47, "model": "embargo.country", "fields": {"country": "CC"}}, {"pk": 51, "model": "embargo.country", "fields": {"country": "CD"}}, {"pk": 42, "model": "embargo.country", "fields": {"country": "CF"}}, {"pk": 50, "model": "embargo.country", "fields": {"country": "CG"}}, {"pk": 215, "model": "embargo.country", "fields": {"country": "CH"}}, {"pk": 59, "model": "embargo.country", "fields": {"country": "CI"}}, {"pk": 52, "model": "embargo.country", "fields": {"country": "CK"}}, {"pk": 44, "model": "embargo.country", "fields": {"country": "CL"}}, {"pk": 38, "model": "embargo.country", "fields": {"country": "CM"}}, {"pk": 45, "model": "embargo.country", "fields": {"country": "CN"}}, {"pk": 48, "model": "embargo.country", "fields": {"country": "CO"}}, {"pk": 53, "model": "embargo.country", "fields": {"country": "CR"}}, {"pk": 55, "model": "embargo.country", "fields": {"country": "CU"}}, {"pk": 40, "model": "embargo.country", "fields": {"country": "CV"}}, {"pk": 56, "model": "embargo.country", "fields": {"country": "CW"}}, {"pk": 46, "model": "embargo.country", "fields": {"country": "CX"}}, {"pk": 57, "model": "embargo.country", "fields": {"country": "CY"}}, {"pk": 58, "model": "embargo.country", "fields": {"country": "CZ"}}, {"pk": 82, "model": "embargo.country", "fields": {"country": "DE"}}, {"pk": 61, "model": "embargo.country", "fields": {"country": "DJ"}}, {"pk": 60, "model": "embargo.country", "fields": {"country": "DK"}}, {"pk": 62, "model": "embargo.country", "fields": {"country": "DM"}}, {"pk": 63, "model": "embargo.country", "fields": {"country": "DO"}}, {"pk": 3, "model": "embargo.country", "fields": {"country": "DZ"}}, {"pk": 64, "model": "embargo.country", "fields": {"country": "EC"}}, {"pk": 69, "model": "embargo.country", "fields": {"country": "EE"}}, {"pk": 65, "model": "embargo.country", "fields": {"country": "EG"}}, {"pk": 245, "model": "embargo.country", "fields": {"country": "EH"}}, {"pk": 68, "model": "embargo.country", "fields": {"country": "ER"}}, {"pk": 208, "model": "embargo.country", "fields": {"country": "ES"}}, {"pk": 70, "model": "embargo.country", "fields": {"country": "ET"}}, {"pk": 74, "model": "embargo.country", "fields": {"country": "FI"}}, {"pk": 73, "model": "embargo.country", "fields": {"country": "FJ"}}, {"pk": 71, "model": "embargo.country", "fields": {"country": "FK"}}, {"pk": 144, "model": "embargo.country", "fields": {"country": "FM"}}, {"pk": 72, "model": "embargo.country", "fields": {"country": "FO"}}, {"pk": 75, "model": "embargo.country", "fields": {"country": "FR"}}, {"pk": 79, "model": "embargo.country", "fields": {"country": "GA"}}, {"pk": 234, "model": "embargo.country", "fields": {"country": "GB"}}, {"pk": 87, "model": "embargo.country", "fields": {"country": "GD"}}, {"pk": 81, "model": "embargo.country", "fields": {"country": "GE"}}, {"pk": 76, "model": "embargo.country", "fields": {"country": "GF"}}, {"pk": 91, "model": "embargo.country", "fields": {"country": "GG"}}, {"pk": 83, "model": "embargo.country", "fields": {"country": "GH"}}, {"pk": 84, "model": "embargo.country", "fields": {"country": "GI"}}, {"pk": 86, "model": "embargo.country", "fields": {"country": "GL"}}, {"pk": 80, "model": "embargo.country", "fields": {"country": "GM"}}, {"pk": 92, "model": "embargo.country", "fields": {"country": "GN"}}, {"pk": 88, "model": "embargo.country", "fields": {"country": "GP"}}, {"pk": 67, "model": "embargo.country", "fields": {"country": "GQ"}}, {"pk": 85, "model": "embargo.country", "fields": {"country": "GR"}}, {"pk": 206, "model": "embargo.country", "fields": {"country": "GS"}}, {"pk": 90, "model": "embargo.country", "fields": {"country": "GT"}}, {"pk": 89, "model": "embargo.country", "fields": {"country": "GU"}}, {"pk": 93, "model": "embargo.country", "fields": {"country": "GW"}}, {"pk": 94, "model": "embargo.country", "fields": {"country": "GY"}}, {"pk": 99, "model": "embargo.country", "fields": {"country": "HK"}}, {"pk": 96, "model": "embargo.country", "fields": {"country": "HM"}}, {"pk": 98, "model": "embargo.country", "fields": {"country": "HN"}}, {"pk": 54, "model": "embargo.country", "fields": {"country": "HR"}}, {"pk": 95, "model": "embargo.country", "fields": {"country": "HT"}}, {"pk": 100, "model": "embargo.country", "fields": {"country": "HU"}}, {"pk": 103, "model": "embargo.country", "fields": {"country": "ID"}}, {"pk": 106, "model": "embargo.country", "fields": {"country": "IE"}}, {"pk": 108, "model": "embargo.country", "fields": {"country": "IL"}}, {"pk": 107, "model": "embargo.country", "fields": {"country": "IM"}}, {"pk": 102, "model": "embargo.country", "fields": {"country": "IN"}}, {"pk": 32, "model": "embargo.country", "fields": {"country": "IO"}}, {"pk": 105, "model": "embargo.country", "fields": {"country": "IQ"}}, {"pk": 104, "model": "embargo.country", "fields": {"country": "IR"}}, {"pk": 101, "model": "embargo.country", "fields": {"country": "IS"}}, {"pk": 109, "model": "embargo.country", "fields": {"country": "IT"}}, {"pk": 112, "model": "embargo.country", "fields": {"country": "JE"}}, {"pk": 110, "model": "embargo.country", "fields": {"country": "JM"}}, {"pk": 113, "model": "embargo.country", "fields": {"country": "JO"}}, {"pk": 111, "model": "embargo.country", "fields": {"country": "JP"}}, {"pk": 115, "model": "embargo.country", "fields": {"country": "KE"}}, {"pk": 120, "model": "embargo.country", "fields": {"country": "KG"}}, {"pk": 37, "model": "embargo.country", "fields": {"country": "KH"}}, {"pk": 116, "model": "embargo.country", "fields": {"country": "KI"}}, {"pk": 49, "model": "embargo.country", "fields": {"country": "KM"}}, {"pk": 186, "model": "embargo.country", "fields": {"country": "KN"}}, {"pk": 117, "model": "embargo.country", "fields": {"country": "KP"}}, {"pk": 118, "model": "embargo.country", "fields": {"country": "KR"}}, {"pk": 119, "model": "embargo.country", "fields": {"country": "KW"}}, {"pk": 41, "model": "embargo.country", "fields": {"country": "KY"}}, {"pk": 114, "model": "embargo.country", "fields": {"country": "KZ"}}, {"pk": 121, "model": "embargo.country", "fields": {"country": "LA"}}, {"pk": 123, "model": "embargo.country", "fields": {"country": "LB"}}, {"pk": 187, "model": "embargo.country", "fields": {"country": "LC"}}, {"pk": 127, "model": "embargo.country", "fields": {"country": "LI"}}, {"pk": 209, "model": "embargo.country", "fields": {"country": "LK"}}, {"pk": 125, "model": "embargo.country", "fields": {"country": "LR"}}, {"pk": 124, "model": "embargo.country", "fields": {"country": "LS"}}, {"pk": 128, "model": "embargo.country", "fields": {"country": "LT"}}, {"pk": 129, "model": "embargo.country", "fields": {"country": "LU"}}, {"pk": 122, "model": "embargo.country", "fields": {"country": "LV"}}, {"pk": 126, "model": "embargo.country", "fields": {"country": "LY"}}, {"pk": 150, "model": "embargo.country", "fields": {"country": "MA"}}, {"pk": 146, "model": "embargo.country", "fields": {"country": "MC"}}, {"pk": 145, "model": "embargo.country", "fields": {"country": "MD"}}, {"pk": 148, "model": "embargo.country", "fields": {"country": "ME"}}, {"pk": 188, "model": "embargo.country", "fields": {"country": "MF"}}, {"pk": 132, "model": "embargo.country", "fields": {"country": "MG"}}, {"pk": 138, "model": "embargo.country", "fields": {"country": "MH"}}, {"pk": 131, "model": "embargo.country", "fields": {"country": "MK"}}, {"pk": 136, "model": "embargo.country", "fields": {"country": "ML"}}, {"pk": 152, "model": "embargo.country", "fields": {"country": "MM"}}, {"pk": 147, "model": "embargo.country", "fields": {"country": "MN"}}, {"pk": 130, "model": "embargo.country", "fields": {"country": "MO"}}, {"pk": 164, "model": "embargo.country", "fields": {"country": "MP"}}, {"pk": 139, "model": "embargo.country", "fields": {"country": "MQ"}}, {"pk": 140, "model": "embargo.country", "fields": {"country": "MR"}}, {"pk": 149, "model": "embargo.country", "fields": {"country": "MS"}}, {"pk": 137, "model": "embargo.country", "fields": {"country": "MT"}}, {"pk": 141, "model": "embargo.country", "fields": {"country": "MU"}}, {"pk": 135, "model": "embargo.country", "fields": {"country": "MV"}}, {"pk": 133, "model": "embargo.country", "fields": {"country": "MW"}}, {"pk": 143, "model": "embargo.country", "fields": {"country": "MX"}}, {"pk": 134, "model": "embargo.country", "fields": {"country": "MY"}}, {"pk": 151, "model": "embargo.country", "fields": {"country": "MZ"}}, {"pk": 153, "model": "embargo.country", "fields": {"country": "NA"}}, {"pk": 157, "model": "embargo.country", "fields": {"country": "NC"}}, {"pk": 160, "model": "embargo.country", "fields": {"country": "NE"}}, {"pk": 163, "model": "embargo.country", "fields": {"country": "NF"}}, {"pk": 161, "model": "embargo.country", "fields": {"country": "NG"}}, {"pk": 159, "model": "embargo.country", "fields": {"country": "NI"}}, {"pk": 156, "model": "embargo.country", "fields": {"country": "NL"}}, {"pk": 165, "model": "embargo.country", "fields": {"country": "NO"}}, {"pk": 155, "model": "embargo.country", "fields": {"country": "NP"}}, {"pk": 154, "model": "embargo.country", "fields": {"country": "NR"}}, {"pk": 162, "model": "embargo.country", "fields": {"country": "NU"}}, {"pk": 158, "model": "embargo.country", "fields": {"country": "NZ"}}, {"pk": 166, "model": "embargo.country", "fields": {"country": "OM"}}, {"pk": 170, "model": "embargo.country", "fields": {"country": "PA"}}, {"pk": 173, "model": "embargo.country", "fields": {"country": "PE"}}, {"pk": 77, "model": "embargo.country", "fields": {"country": "PF"}}, {"pk": 171, "model": "embargo.country", "fields": {"country": "PG"}}, {"pk": 174, "model": "embargo.country", "fields": {"country": "PH"}}, {"pk": 167, "model": "embargo.country", "fields": {"country": "PK"}}, {"pk": 176, "model": "embargo.country", "fields": {"country": "PL"}}, {"pk": 189, "model": "embargo.country", "fields": {"country": "PM"}}, {"pk": 175, "model": "embargo.country", "fields": {"country": "PN"}}, {"pk": 178, "model": "embargo.country", "fields": {"country": "PR"}}, {"pk": 169, "model": "embargo.country", "fields": {"country": "PS"}}, {"pk": 177, "model": "embargo.country", "fields": {"country": "PT"}}, {"pk": 168, "model": "embargo.country", "fields": {"country": "PW"}}, {"pk": 172, "model": "embargo.country", "fields": {"country": "PY"}}, {"pk": 179, "model": "embargo.country", "fields": {"country": "QA"}}, {"pk": 183, "model": "embargo.country", "fields": {"country": "RE"}}, {"pk": 180, "model": "embargo.country", "fields": {"country": "RO"}}, {"pk": 196, "model": "embargo.country", "fields": {"country": "RS"}}, {"pk": 181, "model": "embargo.country", "fields": {"country": "RU"}}, {"pk": 182, "model": "embargo.country", "fields": {"country": "RW"}}, {"pk": 194, "model": "embargo.country", "fields": {"country": "SA"}}, {"pk": 203, "model": "embargo.country", "fields": {"country": "SB"}}, {"pk": 197, "model": "embargo.country", "fields": {"country": "SC"}}, {"pk": 210, "model": "embargo.country", "fields": {"country": "SD"}}, {"pk": 214, "model": "embargo.country", "fields": {"country": "SE"}}, {"pk": 199, "model": "embargo.country", "fields": {"country": "SG"}}, {"pk": 185, "model": "embargo.country", "fields": {"country": "SH"}}, {"pk": 202, "model": "embargo.country", "fields": {"country": "SI"}}, {"pk": 212, "model": "embargo.country", "fields": {"country": "SJ"}}, {"pk": 201, "model": "embargo.country", "fields": {"country": "SK"}}, {"pk": 198, "model": "embargo.country", "fields": {"country": "SL"}}, {"pk": 192, "model": "embargo.country", "fields": {"country": "SM"}}, {"pk": 195, "model": "embargo.country", "fields": {"country": "SN"}}, {"pk": 204, "model": "embargo.country", "fields": {"country": "SO"}}, {"pk": 211, "model": "embargo.country", "fields": {"country": "SR"}}, {"pk": 207, "model": "embargo.country", "fields": {"country": "SS"}}, {"pk": 193, "model": "embargo.country", "fields": {"country": "ST"}}, {"pk": 66, "model": "embargo.country", "fields": {"country": "SV"}}, {"pk": 200, "model": "embargo.country", "fields": {"country": "SX"}}, {"pk": 216, "model": "embargo.country", "fields": {"country": "SY"}}, {"pk": 213, "model": "embargo.country", "fields": {"country": "SZ"}}, {"pk": 229, "model": "embargo.country", "fields": {"country": "TC"}}, {"pk": 43, "model": "embargo.country", "fields": {"country": "TD"}}, {"pk": 78, "model": "embargo.country", "fields": {"country": "TF"}}, {"pk": 222, "model": "embargo.country", "fields": {"country": "TG"}}, {"pk": 220, "model": "embargo.country", "fields": {"country": "TH"}}, {"pk": 218, "model": "embargo.country", "fields": {"country": "TJ"}}, {"pk": 223, "model": "embargo.country", "fields": {"country": "TK"}}, {"pk": 221, "model": "embargo.country", "fields": {"country": "TL"}}, {"pk": 228, "model": "embargo.country", "fields": {"country": "TM"}}, {"pk": 226, "model": "embargo.country", "fields": {"country": "TN"}}, {"pk": 224, "model": "embargo.country", "fields": {"country": "TO"}}, {"pk": 227, "model": "embargo.country", "fields": {"country": "TR"}}, {"pk": 225, "model": "embargo.country", "fields": {"country": "TT"}}, {"pk": 230, "model": "embargo.country", "fields": {"country": "TV"}}, {"pk": 217, "model": "embargo.country", "fields": {"country": "TW"}}, {"pk": 219, "model": "embargo.country", "fields": {"country": "TZ"}}, {"pk": 232, "model": "embargo.country", "fields": {"country": "UA"}}, {"pk": 231, "model": "embargo.country", "fields": {"country": "UG"}}, {"pk": 236, "model": "embargo.country", "fields": {"country": "UM"}}, {"pk": 235, "model": "embargo.country", "fields": {"country": "US"}}, {"pk": 237, "model": "embargo.country", "fields": {"country": "UY"}}, {"pk": 238, "model": "embargo.country", "fields": {"country": "UZ"}}, {"pk": 97, "model": "embargo.country", "fields": {"country": "VA"}}, {"pk": 190, "model": "embargo.country", "fields": {"country": "VC"}}, {"pk": 240, "model": "embargo.country", "fields": {"country": "VE"}}, {"pk": 242, "model": "embargo.country", "fields": {"country": "VG"}}, {"pk": 243, "model": "embargo.country", "fields": {"country": "VI"}}, {"pk": 241, "model": "embargo.country", "fields": {"country": "VN"}}, {"pk": 239, "model": "embargo.country", "fields": {"country": "VU"}}, {"pk": 244, "model": "embargo.country", "fields": {"country": "WF"}}, {"pk": 191, "model": "embargo.country", "fields": {"country": "WS"}}, {"pk": 246, "model": "embargo.country", "fields": {"country": "YE"}}, {"pk": 142, "model": "embargo.country", "fields": {"country": "YT"}}, {"pk": 205, "model": "embargo.country", "fields": {"country": "ZA"}}, {"pk": 247, "model": "embargo.country", "fields": {"country": "ZM"}}, {"pk": 248, "model": "embargo.country", "fields": {"country": "ZW"}}, {"pk": 1, "model": "edxval.profile", "fields": {"profile_name": "desktop_mp4"}}, {"pk": 2, "model": "edxval.profile", "fields": {"profile_name": "desktop_webm"}}, {"pk": 3, "model": "edxval.profile", "fields": {"profile_name": "mobile_high"}}, {"pk": 4, "model": "edxval.profile", "fields": {"profile_name": "mobile_low"}}, {"pk": 5, "model": "edxval.profile", "fields": {"profile_name": "youtube"}}, {"pk": 1, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"fulfills\"", "modified": "2015-03-31T06:26:10Z", "name": "fulfills", "created": "2015-03-31T06:26:10Z"}}, {"pk": 2, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"requires\"", "modified": "2015-03-31T06:26:10Z", "name": "requires", "created": "2015-03-31T06:26:10Z"}}, {"pk": 61, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 21}}, {"pk": 62, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 21}}, {"pk": 63, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 21}}, {"pk": 454, "model": "auth.permission", "fields": {"codename": "add_aiclassifier", "name": "Can add ai classifier", "content_type": 151}}, {"pk": 455, "model": "auth.permission", "fields": {"codename": "change_aiclassifier", "name": "Can change ai classifier", "content_type": 151}}, {"pk": 456, "model": "auth.permission", "fields": {"codename": "delete_aiclassifier", "name": "Can delete ai classifier", "content_type": 151}}, {"pk": 451, "model": "auth.permission", "fields": {"codename": "add_aiclassifierset", "name": "Can add ai classifier set", "content_type": 150}}, {"pk": 452, "model": "auth.permission", "fields": {"codename": "change_aiclassifierset", "name": "Can change ai classifier set", "content_type": 150}}, {"pk": 453, "model": "auth.permission", "fields": {"codename": "delete_aiclassifierset", "name": "Can delete ai classifier set", "content_type": 150}}, {"pk": 460, "model": "auth.permission", "fields": {"codename": "add_aigradingworkflow", "name": "Can add ai grading workflow", "content_type": 153}}, {"pk": 461, "model": "auth.permission", "fields": {"codename": "change_aigradingworkflow", "name": "Can change ai grading workflow", "content_type": 153}}, {"pk": 462, "model": "auth.permission", "fields": {"codename": "delete_aigradingworkflow", "name": "Can delete ai grading workflow", "content_type": 153}}, {"pk": 457, "model": "auth.permission", "fields": {"codename": "add_aitrainingworkflow", "name": "Can add ai training workflow", "content_type": 152}}, {"pk": 458, "model": "auth.permission", "fields": {"codename": "change_aitrainingworkflow", "name": "Can change ai training workflow", "content_type": 152}}, {"pk": 459, "model": "auth.permission", "fields": {"codename": "delete_aitrainingworkflow", "name": "Can delete ai training workflow", "content_type": 152}}, {"pk": 424, "model": "auth.permission", "fields": {"codename": "add_assessment", "name": "Can add assessment", "content_type": 141}}, {"pk": 425, "model": "auth.permission", "fields": {"codename": "change_assessment", "name": "Can change assessment", "content_type": 141}}, {"pk": 426, "model": "auth.permission", "fields": {"codename": "delete_assessment", "name": "Can delete assessment", "content_type": 141}}, {"pk": 433, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedback", "name": "Can add assessment feedback", "content_type": 144}}, {"pk": 434, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedback", "name": "Can change assessment feedback", "content_type": 144}}, {"pk": 435, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedback", "name": "Can delete assessment feedback", "content_type": 144}}, {"pk": 430, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedbackoption", "name": "Can add assessment feedback option", "content_type": 143}}, {"pk": 431, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedbackoption", "name": "Can change assessment feedback option", "content_type": 143}}, {"pk": 432, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedbackoption", "name": "Can delete assessment feedback option", "content_type": 143}}, {"pk": 427, "model": "auth.permission", "fields": {"codename": "add_assessmentpart", "name": "Can add assessment part", "content_type": 142}}, {"pk": 428, "model": "auth.permission", "fields": {"codename": "change_assessmentpart", "name": "Can change assessment part", "content_type": 142}}, {"pk": 429, "model": "auth.permission", "fields": {"codename": "delete_assessmentpart", "name": "Can delete assessment part", "content_type": 142}}, {"pk": 418, "model": "auth.permission", "fields": {"codename": "add_criterion", "name": "Can add criterion", "content_type": 139}}, {"pk": 419, "model": "auth.permission", "fields": {"codename": "change_criterion", "name": "Can change criterion", "content_type": 139}}, {"pk": 420, "model": "auth.permission", "fields": {"codename": "delete_criterion", "name": "Can delete criterion", "content_type": 139}}, {"pk": 421, "model": "auth.permission", "fields": {"codename": "add_criterionoption", "name": "Can add criterion option", "content_type": 140}}, {"pk": 422, "model": "auth.permission", "fields": {"codename": "change_criterionoption", "name": "Can change criterion option", "content_type": 140}}, {"pk": 423, "model": "auth.permission", "fields": {"codename": "delete_criterionoption", "name": "Can delete criterion option", "content_type": 140}}, {"pk": 436, "model": "auth.permission", "fields": {"codename": "add_peerworkflow", "name": "Can add peer workflow", "content_type": 145}}, {"pk": 437, "model": "auth.permission", "fields": {"codename": "change_peerworkflow", "name": "Can change peer workflow", "content_type": 145}}, {"pk": 438, "model": "auth.permission", "fields": {"codename": "delete_peerworkflow", "name": "Can delete peer workflow", "content_type": 145}}, {"pk": 439, "model": "auth.permission", "fields": {"codename": "add_peerworkflowitem", "name": "Can add peer workflow item", "content_type": 146}}, {"pk": 440, "model": "auth.permission", "fields": {"codename": "change_peerworkflowitem", "name": "Can change peer workflow item", "content_type": 146}}, {"pk": 441, "model": "auth.permission", "fields": {"codename": "delete_peerworkflowitem", "name": "Can delete peer workflow item", "content_type": 146}}, {"pk": 415, "model": "auth.permission", "fields": {"codename": "add_rubric", "name": "Can add rubric", "content_type": 138}}, {"pk": 416, "model": "auth.permission", "fields": {"codename": "change_rubric", "name": "Can change rubric", "content_type": 138}}, {"pk": 417, "model": "auth.permission", "fields": {"codename": "delete_rubric", "name": "Can delete rubric", "content_type": 138}}, {"pk": 445, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflow", "name": "Can add student training workflow", "content_type": 148}}, {"pk": 446, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflow", "name": "Can change student training workflow", "content_type": 148}}, {"pk": 447, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflow", "name": "Can delete student training workflow", "content_type": 148}}, {"pk": 448, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflowitem", "name": "Can add student training workflow item", "content_type": 149}}, {"pk": 449, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflowitem", "name": "Can change student training workflow item", "content_type": 149}}, {"pk": 450, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflowitem", "name": "Can delete student training workflow item", "content_type": 149}}, {"pk": 442, "model": "auth.permission", "fields": {"codename": "add_trainingexample", "name": "Can add training example", "content_type": 147}}, {"pk": 443, "model": "auth.permission", "fields": {"codename": "change_trainingexample", "name": "Can change training example", "content_type": 147}}, {"pk": 444, "model": "auth.permission", "fields": {"codename": "delete_trainingexample", "name": "Can delete training example", "content_type": 147}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 208, "model": "auth.permission", "fields": {"codename": "add_brandinginfoconfig", "name": "Can add branding info config", "content_type": 70}}, {"pk": 209, "model": "auth.permission", "fields": {"codename": "change_brandinginfoconfig", "name": "Can change branding info config", "content_type": 70}}, {"pk": 210, "model": "auth.permission", "fields": {"codename": "delete_brandinginfoconfig", "name": "Can delete branding info config", "content_type": 70}}, {"pk": 205, "model": "auth.permission", "fields": {"codename": "add_courseauthorization", "name": "Can add course authorization", "content_type": 69}}, {"pk": 206, "model": "auth.permission", "fields": {"codename": "change_courseauthorization", "name": "Can change course authorization", "content_type": 69}}, {"pk": 207, "model": "auth.permission", "fields": {"codename": "delete_courseauthorization", "name": "Can delete course authorization", "content_type": 69}}, {"pk": 196, "model": "auth.permission", "fields": {"codename": "add_courseemail", "name": "Can add course email", "content_type": 66}}, {"pk": 197, "model": "auth.permission", "fields": {"codename": "change_courseemail", "name": "Can change course email", "content_type": 66}}, {"pk": 198, "model": "auth.permission", "fields": {"codename": "delete_courseemail", "name": "Can delete course email", "content_type": 66}}, {"pk": 202, "model": "auth.permission", "fields": {"codename": "add_courseemailtemplate", "name": "Can add course email template", "content_type": 68}}, {"pk": 203, "model": "auth.permission", "fields": {"codename": "change_courseemailtemplate", "name": "Can change course email template", "content_type": 68}}, {"pk": 204, "model": "auth.permission", "fields": {"codename": "delete_courseemailtemplate", "name": "Can delete course email template", "content_type": 68}}, {"pk": 199, "model": "auth.permission", "fields": {"codename": "add_optout", "name": "Can add optout", "content_type": 67}}, {"pk": 200, "model": "auth.permission", "fields": {"codename": "change_optout", "name": "Can change optout", "content_type": 67}}, {"pk": 201, "model": "auth.permission", "fields": {"codename": "delete_optout", "name": "Can delete optout", "content_type": 67}}, {"pk": 169, "model": "auth.permission", "fields": {"codename": "add_certificategenerationconfiguration", "name": "Can add certificate generation configuration", "content_type": 57}}, {"pk": 170, "model": "auth.permission", "fields": {"codename": "change_certificategenerationconfiguration", "name": "Can change certificate generation configuration", "content_type": 57}}, {"pk": 171, "model": "auth.permission", "fields": {"codename": "delete_certificategenerationconfiguration", "name": "Can delete certificate generation configuration", "content_type": 57}}, {"pk": 166, "model": "auth.permission", "fields": {"codename": "add_certificategenerationcoursesetting", "name": "Can add certificate generation course setting", "content_type": 56}}, {"pk": 167, "model": "auth.permission", "fields": {"codename": "change_certificategenerationcoursesetting", "name": "Can change certificate generation course setting", "content_type": 56}}, {"pk": 168, "model": "auth.permission", "fields": {"codename": "delete_certificategenerationcoursesetting", "name": "Can delete certificate generation course setting", "content_type": 56}}, {"pk": 172, "model": "auth.permission", "fields": {"codename": "add_certificatehtmlviewconfiguration", "name": "Can add certificate html view configuration", "content_type": 58}}, {"pk": 173, "model": "auth.permission", "fields": {"codename": "change_certificatehtmlviewconfiguration", "name": "Can change certificate html view configuration", "content_type": 58}}, {"pk": 174, "model": "auth.permission", "fields": {"codename": "delete_certificatehtmlviewconfiguration", "name": "Can delete certificate html view configuration", "content_type": 58}}, {"pk": 154, "model": "auth.permission", "fields": {"codename": "add_certificatewhitelist", "name": "Can add certificate whitelist", "content_type": 52}}, {"pk": 155, "model": "auth.permission", "fields": {"codename": "change_certificatewhitelist", "name": "Can change certificate whitelist", "content_type": 52}}, {"pk": 156, "model": "auth.permission", "fields": {"codename": "delete_certificatewhitelist", "name": "Can delete certificate whitelist", "content_type": 52}}, {"pk": 163, "model": "auth.permission", "fields": {"codename": "add_examplecertificate", "name": "Can add example certificate", "content_type": 55}}, {"pk": 164, "model": "auth.permission", "fields": {"codename": "change_examplecertificate", "name": "Can change example certificate", "content_type": 55}}, {"pk": 165, "model": "auth.permission", "fields": {"codename": "delete_examplecertificate", "name": "Can delete example certificate", "content_type": 55}}, {"pk": 160, "model": "auth.permission", "fields": {"codename": "add_examplecertificateset", "name": "Can add example certificate set", "content_type": 54}}, {"pk": 161, "model": "auth.permission", "fields": {"codename": "change_examplecertificateset", "name": "Can change example certificate set", "content_type": 54}}, {"pk": 162, "model": "auth.permission", "fields": {"codename": "delete_examplecertificateset", "name": "Can delete example certificate set", "content_type": 54}}, {"pk": 157, "model": "auth.permission", "fields": {"codename": "add_generatedcertificate", "name": "Can add generated certificate", "content_type": 53}}, {"pk": 158, "model": "auth.permission", "fields": {"codename": "change_generatedcertificate", "name": "Can change generated certificate", "content_type": 53}}, {"pk": 159, "model": "auth.permission", "fields": {"codename": "delete_generatedcertificate", "name": "Can delete generated certificate", "content_type": 53}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_servercircuit", "name": "Can add server circuit", "content_type": 16}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_servercircuit", "name": "Can change server circuit", "content_type": 16}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_servercircuit", "name": "Can delete server circuit", "content_type": 16}}, {"pk": 502, "model": "auth.permission", "fields": {"codename": "add_videouploadconfig", "name": "Can add video upload config", "content_type": 167}}, {"pk": 503, "model": "auth.permission", "fields": {"codename": "change_videouploadconfig", "name": "Can change video upload config", "content_type": 167}}, {"pk": 504, "model": "auth.permission", "fields": {"codename": "delete_videouploadconfig", "name": "Can delete video upload config", "content_type": 167}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 64, "model": "auth.permission", "fields": {"codename": "add_corsmodel", "name": "Can add cors model", "content_type": 22}}, {"pk": 65, "model": "auth.permission", "fields": {"codename": "change_corsmodel", "name": "Can change cors model", "content_type": 22}}, {"pk": 66, "model": "auth.permission", "fields": {"codename": "delete_corsmodel", "name": "Can delete cors model", "content_type": 22}}, {"pk": 94, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgrade", "name": "Can add offline computed grade", "content_type": 32}}, {"pk": 95, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgrade", "name": "Can change offline computed grade", "content_type": 32}}, {"pk": 96, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgrade", "name": "Can delete offline computed grade", "content_type": 32}}, {"pk": 97, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgradelog", "name": "Can add offline computed grade log", "content_type": 33}}, {"pk": 98, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgradelog", "name": "Can change offline computed grade log", "content_type": 33}}, {"pk": 99, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgradelog", "name": "Can delete offline computed grade log", "content_type": 33}}, {"pk": 79, "model": "auth.permission", "fields": {"codename": "add_studentmodule", "name": "Can add student module", "content_type": 27}}, {"pk": 80, "model": "auth.permission", "fields": {"codename": "change_studentmodule", "name": "Can change student module", "content_type": 27}}, {"pk": 81, "model": "auth.permission", "fields": {"codename": "delete_studentmodule", "name": "Can delete student module", "content_type": 27}}, {"pk": 82, "model": "auth.permission", "fields": {"codename": "add_studentmodulehistory", "name": "Can add student module history", "content_type": 28}}, {"pk": 83, "model": "auth.permission", "fields": {"codename": "change_studentmodulehistory", "name": "Can change student module history", "content_type": 28}}, {"pk": 84, "model": "auth.permission", "fields": {"codename": "delete_studentmodulehistory", "name": "Can delete student module history", "content_type": 28}}, {"pk": 91, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentinfofield", "name": "Can add x module student info field", "content_type": 31}}, {"pk": 92, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentinfofield", "name": "Can change x module student info field", "content_type": 31}}, {"pk": 93, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentinfofield", "name": "Can delete x module student info field", "content_type": 31}}, {"pk": 88, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentprefsfield", "name": "Can add x module student prefs field", "content_type": 30}}, {"pk": 89, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentprefsfield", "name": "Can change x module student prefs field", "content_type": 30}}, {"pk": 90, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentprefsfield", "name": "Can delete x module student prefs field", "content_type": 30}}, {"pk": 85, "model": "auth.permission", "fields": {"codename": "add_xmoduleuserstatesummaryfield", "name": "Can add x module user state summary field", "content_type": 29}}, {"pk": 86, "model": "auth.permission", "fields": {"codename": "change_xmoduleuserstatesummaryfield", "name": "Can change x module user state summary field", "content_type": 29}}, {"pk": 87, "model": "auth.permission", "fields": {"codename": "delete_xmoduleuserstatesummaryfield", "name": "Can delete x module user state summary field", "content_type": 29}}, {"pk": 385, "model": "auth.permission", "fields": {"codename": "add_coursererunstate", "name": "Can add course rerun state", "content_type": 128}}, {"pk": 386, "model": "auth.permission", "fields": {"codename": "change_coursererunstate", "name": "Can change course rerun state", "content_type": 128}}, {"pk": 387, "model": "auth.permission", "fields": {"codename": "delete_coursererunstate", "name": "Can delete course rerun state", "content_type": 128}}, {"pk": 505, "model": "auth.permission", "fields": {"codename": "add_coursecreator", "name": "Can add course creator", "content_type": 168}}, {"pk": 506, "model": "auth.permission", "fields": {"codename": "change_coursecreator", "name": "Can change course creator", "content_type": 168}}, {"pk": 507, "model": "auth.permission", "fields": {"codename": "delete_coursecreator", "name": "Can delete course creator", "content_type": 168}}, {"pk": 193, "model": "auth.permission", "fields": {"codename": "add_coursecohort", "name": "Can add course cohort", "content_type": 65}}, {"pk": 194, "model": "auth.permission", "fields": {"codename": "change_coursecohort", "name": "Can change course cohort", "content_type": 65}}, {"pk": 195, "model": "auth.permission", "fields": {"codename": "delete_coursecohort", "name": "Can delete course cohort", "content_type": 65}}, {"pk": 190, "model": "auth.permission", "fields": {"codename": "add_coursecohortssettings", "name": "Can add course cohorts settings", "content_type": 64}}, {"pk": 191, "model": "auth.permission", "fields": {"codename": "change_coursecohortssettings", "name": "Can change course cohorts settings", "content_type": 64}}, {"pk": 192, "model": "auth.permission", "fields": {"codename": "delete_coursecohortssettings", "name": "Can delete course cohorts settings", "content_type": 64}}, {"pk": 184, "model": "auth.permission", "fields": {"codename": "add_courseusergroup", "name": "Can add course user group", "content_type": 62}}, {"pk": 185, "model": "auth.permission", "fields": {"codename": "change_courseusergroup", "name": "Can change course user group", "content_type": 62}}, {"pk": 186, "model": "auth.permission", "fields": {"codename": "delete_courseusergroup", "name": "Can delete course user group", "content_type": 62}}, {"pk": 187, "model": "auth.permission", "fields": {"codename": "add_courseusergrouppartitiongroup", "name": "Can add course user group partition group", "content_type": 63}}, {"pk": 188, "model": "auth.permission", "fields": {"codename": "change_courseusergrouppartitiongroup", "name": "Can change course user group partition group", "content_type": 63}}, {"pk": 189, "model": "auth.permission", "fields": {"codename": "delete_courseusergrouppartitiongroup", "name": "Can delete course user group partition group", "content_type": 63}}, {"pk": 349, "model": "auth.permission", "fields": {"codename": "add_coursemode", "name": "Can add course mode", "content_type": 116}}, {"pk": 350, "model": "auth.permission", "fields": {"codename": "change_coursemode", "name": "Can change course mode", "content_type": 116}}, {"pk": 351, "model": "auth.permission", "fields": {"codename": "delete_coursemode", "name": "Can delete course mode", "content_type": 116}}, {"pk": 352, "model": "auth.permission", "fields": {"codename": "add_coursemodesarchive", "name": "Can add course modes archive", "content_type": 117}}, {"pk": 353, "model": "auth.permission", "fields": {"codename": "change_coursemodesarchive", "name": "Can change course modes archive", "content_type": 117}}, {"pk": 354, "model": "auth.permission", "fields": {"codename": "delete_coursemodesarchive", "name": "Can delete course modes archive", "content_type": 117}}, {"pk": 400, "model": "auth.permission", "fields": {"codename": "add_coursestructure", "name": "Can add course structure", "content_type": 133}}, {"pk": 401, "model": "auth.permission", "fields": {"codename": "change_coursestructure", "name": "Can change course structure", "content_type": 133}}, {"pk": 402, "model": "auth.permission", "fields": {"codename": "delete_coursestructure", "name": "Can delete course structure", "content_type": 133}}, {"pk": 358, "model": "auth.permission", "fields": {"codename": "add_darklangconfig", "name": "Can add dark lang config", "content_type": 119}}, {"pk": 359, "model": "auth.permission", "fields": {"codename": "change_darklangconfig", "name": "Can change dark lang config", "content_type": 119}}, {"pk": 360, "model": "auth.permission", "fields": {"codename": "delete_darklangconfig", "name": "Can delete dark lang config", "content_type": 119}}, {"pk": 73, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 25}}, {"pk": 74, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 25}}, {"pk": 75, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 25}}, {"pk": 76, "model": "auth.permission", "fields": {"codename": "add_code", "name": "Can add code", "content_type": 26}}, {"pk": 77, "model": "auth.permission", "fields": {"codename": "change_code", "name": "Can change code", "content_type": 26}}, {"pk": 78, "model": "auth.permission", "fields": {"codename": "delete_code", "name": "Can delete code", "content_type": 26}}, {"pk": 70, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 24}}, {"pk": 71, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 24}}, {"pk": 72, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 24}}, {"pk": 67, "model": "auth.permission", "fields": {"codename": "add_usersocialauth", "name": "Can add user social auth", "content_type": 23}}, {"pk": 68, "model": "auth.permission", "fields": {"codename": "change_usersocialauth", "name": "Can change user social auth", "content_type": 23}}, {"pk": 69, "model": "auth.permission", "fields": {"codename": "delete_usersocialauth", "name": "Can delete user social auth", "content_type": 23}}, {"pk": 271, "model": "auth.permission", "fields": {"codename": "add_notification", "name": "Can add notification", "content_type": 90}}, {"pk": 272, "model": "auth.permission", "fields": {"codename": "change_notification", "name": "Can change notification", "content_type": 90}}, {"pk": 273, "model": "auth.permission", "fields": {"codename": "delete_notification", "name": "Can delete notification", "content_type": 90}}, {"pk": 262, "model": "auth.permission", "fields": {"codename": "add_notificationtype", "name": "Can add type", "content_type": 87}}, {"pk": 263, "model": "auth.permission", "fields": {"codename": "change_notificationtype", "name": "Can change type", "content_type": 87}}, {"pk": 264, "model": "auth.permission", "fields": {"codename": "delete_notificationtype", "name": "Can delete type", "content_type": 87}}, {"pk": 265, "model": "auth.permission", "fields": {"codename": "add_settings", "name": "Can add settings", "content_type": 88}}, {"pk": 266, "model": "auth.permission", "fields": {"codename": "change_settings", "name": "Can change settings", "content_type": 88}}, {"pk": 267, "model": "auth.permission", "fields": {"codename": "delete_settings", "name": "Can delete settings", "content_type": 88}}, {"pk": 268, "model": "auth.permission", "fields": {"codename": "add_subscription", "name": "Can add subscription", "content_type": 89}}, {"pk": 269, "model": "auth.permission", "fields": {"codename": "change_subscription", "name": "Can change subscription", "content_type": 89}}, {"pk": 270, "model": "auth.permission", "fields": {"codename": "delete_subscription", "name": "Can delete subscription", "content_type": 89}}, {"pk": 55, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 19}}, {"pk": 56, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 19}}, {"pk": 57, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 19}}, {"pk": 52, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 18}}, {"pk": 53, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 18}}, {"pk": 54, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 18}}, {"pk": 58, "model": "auth.permission", "fields": {"codename": "add_useropenid", "name": "Can add user open id", "content_type": 20}}, {"pk": 59, "model": "auth.permission", "fields": {"codename": "change_useropenid", "name": "Can change user open id", "content_type": 20}}, {"pk": 60, "model": "auth.permission", "fields": {"codename": "delete_useropenid", "name": "Can delete user open id", "content_type": 20}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_crontabschedule", "name": "Can add crontab", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_crontabschedule", "name": "Can change crontab", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_crontabschedule", "name": "Can delete crontab", "content_type": 10}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_intervalschedule", "name": "Can add interval", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_intervalschedule", "name": "Can change interval", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_intervalschedule", "name": "Can delete interval", "content_type": 9}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_periodictask", "name": "Can add periodic task", "content_type": 12}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_periodictask", "name": "Can change periodic task", "content_type": 12}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_periodictask", "name": "Can delete periodic task", "content_type": 12}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_periodictasks", "name": "Can add periodic tasks", "content_type": 11}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_periodictasks", "name": "Can change periodic tasks", "content_type": 11}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_periodictasks", "name": "Can delete periodic tasks", "content_type": 11}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_taskmeta", "name": "Can add task state", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_taskmeta", "name": "Can change task state", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_taskmeta", "name": "Can delete task state", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_tasksetmeta", "name": "Can add saved group result", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_tasksetmeta", "name": "Can change saved group result", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_tasksetmeta", "name": "Can delete saved group result", "content_type": 8}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_taskstate", "name": "Can add task", "content_type": 14}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_taskstate", "name": "Can change task", "content_type": 14}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_taskstate", "name": "Can delete task", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_workerstate", "name": "Can add worker", "content_type": 13}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_workerstate", "name": "Can change worker", "content_type": 13}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_workerstate", "name": "Can delete worker", "content_type": 13}}, {"pk": 478, "model": "auth.permission", "fields": {"codename": "add_coursevideo", "name": "Can add course video", "content_type": 159}}, {"pk": 479, "model": "auth.permission", "fields": {"codename": "change_coursevideo", "name": "Can change course video", "content_type": 159}}, {"pk": 480, "model": "auth.permission", "fields": {"codename": "delete_coursevideo", "name": "Can delete course video", "content_type": 159}}, {"pk": 481, "model": "auth.permission", "fields": {"codename": "add_encodedvideo", "name": "Can add encoded video", "content_type": 160}}, {"pk": 482, "model": "auth.permission", "fields": {"codename": "change_encodedvideo", "name": "Can change encoded video", "content_type": 160}}, {"pk": 483, "model": "auth.permission", "fields": {"codename": "delete_encodedvideo", "name": "Can delete encoded video", "content_type": 160}}, {"pk": 472, "model": "auth.permission", "fields": {"codename": "add_profile", "name": "Can add profile", "content_type": 157}}, {"pk": 473, "model": "auth.permission", "fields": {"codename": "change_profile", "name": "Can change profile", "content_type": 157}}, {"pk": 474, "model": "auth.permission", "fields": {"codename": "delete_profile", "name": "Can delete profile", "content_type": 157}}, {"pk": 484, "model": "auth.permission", "fields": {"codename": "add_subtitle", "name": "Can add subtitle", "content_type": 161}}, {"pk": 485, "model": "auth.permission", "fields": {"codename": "change_subtitle", "name": "Can change subtitle", "content_type": 161}}, {"pk": 486, "model": "auth.permission", "fields": {"codename": "delete_subtitle", "name": "Can delete subtitle", "content_type": 161}}, {"pk": 475, "model": "auth.permission", "fields": {"codename": "add_video", "name": "Can add video", "content_type": 158}}, {"pk": 476, "model": "auth.permission", "fields": {"codename": "change_video", "name": "Can change video", "content_type": 158}}, {"pk": 477, "model": "auth.permission", "fields": {"codename": "delete_video", "name": "Can delete video", "content_type": 158}}, {"pk": 373, "model": "auth.permission", "fields": {"codename": "add_country", "name": "Can add country", "content_type": 124}}, {"pk": 374, "model": "auth.permission", "fields": {"codename": "change_country", "name": "Can change country", "content_type": 124}}, {"pk": 375, "model": "auth.permission", "fields": {"codename": "delete_country", "name": "Can delete country", "content_type": 124}}, {"pk": 376, "model": "auth.permission", "fields": {"codename": "add_countryaccessrule", "name": "Can add country access rule", "content_type": 125}}, {"pk": 377, "model": "auth.permission", "fields": {"codename": "change_countryaccessrule", "name": "Can change country access rule", "content_type": 125}}, {"pk": 378, "model": "auth.permission", "fields": {"codename": "delete_countryaccessrule", "name": "Can delete country access rule", "content_type": 125}}, {"pk": 379, "model": "auth.permission", "fields": {"codename": "add_courseaccessrulehistory", "name": "Can add course access rule history", "content_type": 126}}, {"pk": 380, "model": "auth.permission", "fields": {"codename": "change_courseaccessrulehistory", "name": "Can change course access rule history", "content_type": 126}}, {"pk": 381, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrulehistory", "name": "Can delete course access rule history", "content_type": 126}}, {"pk": 364, "model": "auth.permission", "fields": {"codename": "add_embargoedcourse", "name": "Can add embargoed course", "content_type": 121}}, {"pk": 365, "model": "auth.permission", "fields": {"codename": "change_embargoedcourse", "name": "Can change embargoed course", "content_type": 121}}, {"pk": 366, "model": "auth.permission", "fields": {"codename": "delete_embargoedcourse", "name": "Can delete embargoed course", "content_type": 121}}, {"pk": 367, "model": "auth.permission", "fields": {"codename": "add_embargoedstate", "name": "Can add embargoed state", "content_type": 122}}, {"pk": 368, "model": "auth.permission", "fields": {"codename": "change_embargoedstate", "name": "Can change embargoed state", "content_type": 122}}, {"pk": 369, "model": "auth.permission", "fields": {"codename": "delete_embargoedstate", "name": "Can delete embargoed state", "content_type": 122}}, {"pk": 382, "model": "auth.permission", "fields": {"codename": "add_ipfilter", "name": "Can add ip filter", "content_type": 127}}, {"pk": 383, "model": "auth.permission", "fields": {"codename": "change_ipfilter", "name": "Can change ip filter", "content_type": 127}}, {"pk": 384, "model": "auth.permission", "fields": {"codename": "delete_ipfilter", "name": "Can delete ip filter", "content_type": 127}}, {"pk": 370, "model": "auth.permission", "fields": {"codename": "add_restrictedcourse", "name": "Can add restricted course", "content_type": 123}}, {"pk": 371, "model": "auth.permission", "fields": {"codename": "change_restrictedcourse", "name": "Can change restricted course", "content_type": 123}}, {"pk": 372, "model": "auth.permission", "fields": {"codename": "delete_restrictedcourse", "name": "Can delete restricted course", "content_type": 123}}, {"pk": 211, "model": "auth.permission", "fields": {"codename": "add_externalauthmap", "name": "Can add external auth map", "content_type": 71}}, {"pk": 212, "model": "auth.permission", "fields": {"codename": "change_externalauthmap", "name": "Can change external auth map", "content_type": 71}}, {"pk": 213, "model": "auth.permission", "fields": {"codename": "delete_externalauthmap", "name": "Can delete external auth map", "content_type": 71}}, {"pk": 277, "model": "auth.permission", "fields": {"codename": "add_puzzlecomplete", "name": "Can add puzzle complete", "content_type": 92}}, {"pk": 278, "model": "auth.permission", "fields": {"codename": "change_puzzlecomplete", "name": "Can change puzzle complete", "content_type": 92}}, {"pk": 279, "model": "auth.permission", "fields": {"codename": "delete_puzzlecomplete", "name": "Can delete puzzle complete", "content_type": 92}}, {"pk": 274, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 91}}, {"pk": 275, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 91}}, {"pk": 276, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 91}}, {"pk": 175, "model": "auth.permission", "fields": {"codename": "add_instructortask", "name": "Can add instructor task", "content_type": 59}}, {"pk": 176, "model": "auth.permission", "fields": {"codename": "change_instructortask", "name": "Can change instructor task", "content_type": 59}}, {"pk": 177, "model": "auth.permission", "fields": {"codename": "delete_instructortask", "name": "Can delete instructor task", "content_type": 59}}, {"pk": 178, "model": "auth.permission", "fields": {"codename": "add_coursesoftware", "name": "Can add course software", "content_type": 60}}, {"pk": 179, "model": "auth.permission", "fields": {"codename": "change_coursesoftware", "name": "Can change course software", "content_type": 60}}, {"pk": 180, "model": "auth.permission", "fields": {"codename": "delete_coursesoftware", "name": "Can delete course software", "content_type": 60}}, {"pk": 181, "model": "auth.permission", "fields": {"codename": "add_userlicense", "name": "Can add user license", "content_type": 61}}, {"pk": 182, "model": "auth.permission", "fields": {"codename": "change_userlicense", "name": "Can change user license", "content_type": 61}}, {"pk": 183, "model": "auth.permission", "fields": {"codename": "delete_userlicense", "name": "Can delete user license", "content_type": 61}}, {"pk": 397, "model": "auth.permission", "fields": {"codename": "add_xblockasidesconfig", "name": "Can add x block asides config", "content_type": 132}}, {"pk": 398, "model": "auth.permission", "fields": {"codename": "change_xblockasidesconfig", "name": "Can change x block asides config", "content_type": 132}}, {"pk": 399, "model": "auth.permission", "fields": {"codename": "delete_xblockasidesconfig", "name": "Can delete x block asides config", "content_type": 132}}, {"pk": 496, "model": "auth.permission", "fields": {"codename": "add_coursecontentmilestone", "name": "Can add course content milestone", "content_type": 165}}, {"pk": 497, "model": "auth.permission", "fields": {"codename": "change_coursecontentmilestone", "name": "Can change course content milestone", "content_type": 165}}, {"pk": 498, "model": "auth.permission", "fields": {"codename": "delete_coursecontentmilestone", "name": "Can delete course content milestone", "content_type": 165}}, {"pk": 493, "model": "auth.permission", "fields": {"codename": "add_coursemilestone", "name": "Can add course milestone", "content_type": 164}}, {"pk": 494, "model": "auth.permission", "fields": {"codename": "change_coursemilestone", "name": "Can change course milestone", "content_type": 164}}, {"pk": 495, "model": "auth.permission", "fields": {"codename": "delete_coursemilestone", "name": "Can delete course milestone", "content_type": 164}}, {"pk": 487, "model": "auth.permission", "fields": {"codename": "add_milestone", "name": "Can add milestone", "content_type": 162}}, {"pk": 488, "model": "auth.permission", "fields": {"codename": "change_milestone", "name": "Can change milestone", "content_type": 162}}, {"pk": 489, "model": "auth.permission", "fields": {"codename": "delete_milestone", "name": "Can delete milestone", "content_type": 162}}, {"pk": 490, "model": "auth.permission", "fields": {"codename": "add_milestonerelationshiptype", "name": "Can add milestone relationship type", "content_type": 163}}, {"pk": 491, "model": "auth.permission", "fields": {"codename": "change_milestonerelationshiptype", "name": "Can change milestone relationship type", "content_type": 163}}, {"pk": 492, "model": "auth.permission", "fields": {"codename": "delete_milestonerelationshiptype", "name": "Can delete milestone relationship type", "content_type": 163}}, {"pk": 499, "model": "auth.permission", "fields": {"codename": "add_usermilestone", "name": "Can add user milestone", "content_type": 166}}, {"pk": 500, "model": "auth.permission", "fields": {"codename": "change_usermilestone", "name": "Can change user milestone", "content_type": 166}}, {"pk": 501, "model": "auth.permission", "fields": {"codename": "delete_usermilestone", "name": "Can delete user milestone", "content_type": 166}}, {"pk": 388, "model": "auth.permission", "fields": {"codename": "add_mobileapiconfig", "name": "Can add mobile api config", "content_type": 129}}, {"pk": 389, "model": "auth.permission", "fields": {"codename": "change_mobileapiconfig", "name": "Can change mobile api config", "content_type": 129}}, {"pk": 390, "model": "auth.permission", "fields": {"codename": "delete_mobileapiconfig", "name": "Can delete mobile api config", "content_type": 129}}, {"pk": 280, "model": "auth.permission", "fields": {"codename": "add_note", "name": "Can add note", "content_type": 93}}, {"pk": 281, "model": "auth.permission", "fields": {"codename": "change_note", "name": "Can change note", "content_type": 93}}, {"pk": 282, "model": "auth.permission", "fields": {"codename": "delete_note", "name": "Can delete note", "content_type": 93}}, {"pk": 220, "model": "auth.permission", "fields": {"codename": "add_accesstoken", "name": "Can add access token", "content_type": 74}}, {"pk": 221, "model": "auth.permission", "fields": {"codename": "change_accesstoken", "name": "Can change access token", "content_type": 74}}, {"pk": 222, "model": "auth.permission", "fields": {"codename": "delete_accesstoken", "name": "Can delete access token", "content_type": 74}}, {"pk": 214, "model": "auth.permission", "fields": {"codename": "add_client", "name": "Can add client", "content_type": 72}}, {"pk": 215, "model": "auth.permission", "fields": {"codename": "change_client", "name": "Can change client", "content_type": 72}}, {"pk": 216, "model": "auth.permission", "fields": {"codename": "delete_client", "name": "Can delete client", "content_type": 72}}, {"pk": 217, "model": "auth.permission", "fields": {"codename": "add_grant", "name": "Can add grant", "content_type": 73}}, {"pk": 218, "model": "auth.permission", "fields": {"codename": "change_grant", "name": "Can change grant", "content_type": 73}}, {"pk": 219, "model": "auth.permission", "fields": {"codename": "delete_grant", "name": "Can delete grant", "content_type": 73}}, {"pk": 223, "model": "auth.permission", "fields": {"codename": "add_refreshtoken", "name": "Can add refresh token", "content_type": 75}}, {"pk": 224, "model": "auth.permission", "fields": {"codename": "change_refreshtoken", "name": "Can change refresh token", "content_type": 75}}, {"pk": 225, "model": "auth.permission", "fields": {"codename": "delete_refreshtoken", "name": "Can delete refresh token", "content_type": 75}}, {"pk": 226, "model": "auth.permission", "fields": {"codename": "add_trustedclient", "name": "Can add trusted client", "content_type": 76}}, {"pk": 227, "model": "auth.permission", "fields": {"codename": "change_trustedclient", "name": "Can change trusted client", "content_type": 76}}, {"pk": 228, "model": "auth.permission", "fields": {"codename": "delete_trustedclient", "name": "Can delete trusted client", "content_type": 76}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_psychometricdata", "name": "Can add psychometric data", "content_type": 17}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_psychometricdata", "name": "Can change psychometric data", "content_type": 17}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_psychometricdata", "name": "Can delete psychometric data", "content_type": 17}}, {"pk": 361, "model": "auth.permission", "fields": {"codename": "add_midcoursereverificationwindow", "name": "Can add midcourse reverification window", "content_type": 120}}, {"pk": 362, "model": "auth.permission", "fields": {"codename": "change_midcoursereverificationwindow", "name": "Can change midcourse reverification window", "content_type": 120}}, {"pk": 363, "model": "auth.permission", "fields": {"codename": "delete_midcoursereverificationwindow", "name": "Can delete midcourse reverification window", "content_type": 120}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 340, "model": "auth.permission", "fields": {"codename": "add_certificateitem", "name": "Can add certificate item", "content_type": 113}}, {"pk": 341, "model": "auth.permission", "fields": {"codename": "change_certificateitem", "name": "Can change certificate item", "content_type": 113}}, {"pk": 342, "model": "auth.permission", "fields": {"codename": "delete_certificateitem", "name": "Can delete certificate item", "content_type": 113}}, {"pk": 322, "model": "auth.permission", "fields": {"codename": "add_coupon", "name": "Can add coupon", "content_type": 107}}, {"pk": 323, "model": "auth.permission", "fields": {"codename": "change_coupon", "name": "Can change coupon", "content_type": 107}}, {"pk": 324, "model": "auth.permission", "fields": {"codename": "delete_coupon", "name": "Can delete coupon", "content_type": 107}}, {"pk": 325, "model": "auth.permission", "fields": {"codename": "add_couponredemption", "name": "Can add coupon redemption", "content_type": 108}}, {"pk": 326, "model": "auth.permission", "fields": {"codename": "change_couponredemption", "name": "Can change coupon redemption", "content_type": 108}}, {"pk": 327, "model": "auth.permission", "fields": {"codename": "delete_couponredemption", "name": "Can delete coupon redemption", "content_type": 108}}, {"pk": 331, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitem", "name": "Can add course reg code item", "content_type": 110}}, {"pk": 332, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitem", "name": "Can change course reg code item", "content_type": 110}}, {"pk": 333, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitem", "name": "Can delete course reg code item", "content_type": 110}}, {"pk": 334, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitemannotation", "name": "Can add course reg code item annotation", "content_type": 111}}, {"pk": 335, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitemannotation", "name": "Can change course reg code item annotation", "content_type": 111}}, {"pk": 336, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitemannotation", "name": "Can delete course reg code item annotation", "content_type": 111}}, {"pk": 316, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcode", "name": "Can add course registration code", "content_type": 105}}, {"pk": 317, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcode", "name": "Can change course registration code", "content_type": 105}}, {"pk": 318, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcode", "name": "Can delete course registration code", "content_type": 105}}, {"pk": 310, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcodeinvoiceitem", "name": "Can add course registration code invoice item", "content_type": 103}}, {"pk": 311, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcodeinvoiceitem", "name": "Can change course registration code invoice item", "content_type": 103}}, {"pk": 312, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcodeinvoiceitem", "name": "Can delete course registration code invoice item", "content_type": 103}}, {"pk": 346, "model": "auth.permission", "fields": {"codename": "add_donation", "name": "Can add donation", "content_type": 115}}, {"pk": 347, "model": "auth.permission", "fields": {"codename": "change_donation", "name": "Can change donation", "content_type": 115}}, {"pk": 348, "model": "auth.permission", "fields": {"codename": "delete_donation", "name": "Can delete donation", "content_type": 115}}, {"pk": 343, "model": "auth.permission", "fields": {"codename": "add_donationconfiguration", "name": "Can add donation configuration", "content_type": 114}}, {"pk": 344, "model": "auth.permission", "fields": {"codename": "change_donationconfiguration", "name": "Can change donation configuration", "content_type": 114}}, {"pk": 345, "model": "auth.permission", "fields": {"codename": "delete_donationconfiguration", "name": "Can delete donation configuration", "content_type": 114}}, {"pk": 301, "model": "auth.permission", "fields": {"codename": "add_invoice", "name": "Can add invoice", "content_type": 100}}, {"pk": 302, "model": "auth.permission", "fields": {"codename": "change_invoice", "name": "Can change invoice", "content_type": 100}}, {"pk": 303, "model": "auth.permission", "fields": {"codename": "delete_invoice", "name": "Can delete invoice", "content_type": 100}}, {"pk": 313, "model": "auth.permission", "fields": {"codename": "add_invoicehistory", "name": "Can add invoice history", "content_type": 104}}, {"pk": 314, "model": "auth.permission", "fields": {"codename": "change_invoicehistory", "name": "Can change invoice history", "content_type": 104}}, {"pk": 315, "model": "auth.permission", "fields": {"codename": "delete_invoicehistory", "name": "Can delete invoice history", "content_type": 104}}, {"pk": 307, "model": "auth.permission", "fields": {"codename": "add_invoiceitem", "name": "Can add invoice item", "content_type": 102}}, {"pk": 308, "model": "auth.permission", "fields": {"codename": "change_invoiceitem", "name": "Can change invoice item", "content_type": 102}}, {"pk": 309, "model": "auth.permission", "fields": {"codename": "delete_invoiceitem", "name": "Can delete invoice item", "content_type": 102}}, {"pk": 304, "model": "auth.permission", "fields": {"codename": "add_invoicetransaction", "name": "Can add invoice transaction", "content_type": 101}}, {"pk": 305, "model": "auth.permission", "fields": {"codename": "change_invoicetransaction", "name": "Can change invoice transaction", "content_type": 101}}, {"pk": 306, "model": "auth.permission", "fields": {"codename": "delete_invoicetransaction", "name": "Can delete invoice transaction", "content_type": 101}}, {"pk": 295, "model": "auth.permission", "fields": {"codename": "add_order", "name": "Can add order", "content_type": 98}}, {"pk": 296, "model": "auth.permission", "fields": {"codename": "change_order", "name": "Can change order", "content_type": 98}}, {"pk": 297, "model": "auth.permission", "fields": {"codename": "delete_order", "name": "Can delete order", "content_type": 98}}, {"pk": 298, "model": "auth.permission", "fields": {"codename": "add_orderitem", "name": "Can add order item", "content_type": 99}}, {"pk": 299, "model": "auth.permission", "fields": {"codename": "change_orderitem", "name": "Can change order item", "content_type": 99}}, {"pk": 300, "model": "auth.permission", "fields": {"codename": "delete_orderitem", "name": "Can delete order item", "content_type": 99}}, {"pk": 328, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistration", "name": "Can add paid course registration", "content_type": 109}}, {"pk": 329, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistration", "name": "Can change paid course registration", "content_type": 109}}, {"pk": 330, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistration", "name": "Can delete paid course registration", "content_type": 109}}, {"pk": 337, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistrationannotation", "name": "Can add paid course registration annotation", "content_type": 112}}, {"pk": 338, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistrationannotation", "name": "Can change paid course registration annotation", "content_type": 112}}, {"pk": 339, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistrationannotation", "name": "Can delete paid course registration annotation", "content_type": 112}}, {"pk": 319, "model": "auth.permission", "fields": {"codename": "add_registrationcoderedemption", "name": "Can add registration code redemption", "content_type": 106}}, {"pk": 320, "model": "auth.permission", "fields": {"codename": "change_registrationcoderedemption", "name": "Can change registration code redemption", "content_type": 106}}, {"pk": 321, "model": "auth.permission", "fields": {"codename": "delete_registrationcoderedemption", "name": "Can delete registration code redemption", "content_type": 106}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 6}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 15}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 15}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 15}}, {"pk": 283, "model": "auth.permission", "fields": {"codename": "add_splashconfig", "name": "Can add splash config", "content_type": 94}}, {"pk": 284, "model": "auth.permission", "fields": {"codename": "change_splashconfig", "name": "Can change splash config", "content_type": 94}}, {"pk": 285, "model": "auth.permission", "fields": {"codename": "delete_splashconfig", "name": "Can delete splash config", "content_type": 94}}, {"pk": 100, "model": "auth.permission", "fields": {"codename": "add_anonymoususerid", "name": "Can add anonymous user id", "content_type": 34}}, {"pk": 101, "model": "auth.permission", "fields": {"codename": "change_anonymoususerid", "name": "Can change anonymous user id", "content_type": 34}}, {"pk": 102, "model": "auth.permission", "fields": {"codename": "delete_anonymoususerid", "name": "Can delete anonymous user id", "content_type": 34}}, {"pk": 136, "model": "auth.permission", "fields": {"codename": "add_courseaccessrole", "name": "Can add course access role", "content_type": 46}}, {"pk": 137, "model": "auth.permission", "fields": {"codename": "change_courseaccessrole", "name": "Can change course access role", "content_type": 46}}, {"pk": 138, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrole", "name": "Can delete course access role", "content_type": 46}}, {"pk": 130, "model": "auth.permission", "fields": {"codename": "add_courseenrollment", "name": "Can add course enrollment", "content_type": 44}}, {"pk": 131, "model": "auth.permission", "fields": {"codename": "change_courseenrollment", "name": "Can change course enrollment", "content_type": 44}}, {"pk": 132, "model": "auth.permission", "fields": {"codename": "delete_courseenrollment", "name": "Can delete course enrollment", "content_type": 44}}, {"pk": 133, "model": "auth.permission", "fields": {"codename": "add_courseenrollmentallowed", "name": "Can add course enrollment allowed", "content_type": 45}}, {"pk": 134, "model": "auth.permission", "fields": {"codename": "change_courseenrollmentallowed", "name": "Can change course enrollment allowed", "content_type": 45}}, {"pk": 135, "model": "auth.permission", "fields": {"codename": "delete_courseenrollmentallowed", "name": "Can delete course enrollment allowed", "content_type": 45}}, {"pk": 139, "model": "auth.permission", "fields": {"codename": "add_dashboardconfiguration", "name": "Can add dashboard configuration", "content_type": 47}}, {"pk": 140, "model": "auth.permission", "fields": {"codename": "change_dashboardconfiguration", "name": "Can change dashboard configuration", "content_type": 47}}, {"pk": 141, "model": "auth.permission", "fields": {"codename": "delete_dashboardconfiguration", "name": "Can delete dashboard configuration", "content_type": 47}}, {"pk": 145, "model": "auth.permission", "fields": {"codename": "add_entranceexamconfiguration", "name": "Can add entrance exam configuration", "content_type": 49}}, {"pk": 146, "model": "auth.permission", "fields": {"codename": "change_entranceexamconfiguration", "name": "Can change entrance exam configuration", "content_type": 49}}, {"pk": 147, "model": "auth.permission", "fields": {"codename": "delete_entranceexamconfiguration", "name": "Can delete entrance exam configuration", "content_type": 49}}, {"pk": 142, "model": "auth.permission", "fields": {"codename": "add_linkedinaddtoprofileconfiguration", "name": "Can add linked in add to profile configuration", "content_type": 48}}, {"pk": 143, "model": "auth.permission", "fields": {"codename": "change_linkedinaddtoprofileconfiguration", "name": "Can change linked in add to profile configuration", "content_type": 48}}, {"pk": 144, "model": "auth.permission", "fields": {"codename": "delete_linkedinaddtoprofileconfiguration", "name": "Can delete linked in add to profile configuration", "content_type": 48}}, {"pk": 127, "model": "auth.permission", "fields": {"codename": "add_loginfailures", "name": "Can add login failures", "content_type": 43}}, {"pk": 128, "model": "auth.permission", "fields": {"codename": "change_loginfailures", "name": "Can change login failures", "content_type": 43}}, {"pk": 129, "model": "auth.permission", "fields": {"codename": "delete_loginfailures", "name": "Can delete login failures", "content_type": 43}}, {"pk": 124, "model": "auth.permission", "fields": {"codename": "add_passwordhistory", "name": "Can add password history", "content_type": 42}}, {"pk": 125, "model": "auth.permission", "fields": {"codename": "change_passwordhistory", "name": "Can change password history", "content_type": 42}}, {"pk": 126, "model": "auth.permission", "fields": {"codename": "delete_passwordhistory", "name": "Can delete password history", "content_type": 42}}, {"pk": 121, "model": "auth.permission", "fields": {"codename": "add_pendingemailchange", "name": "Can add pending email change", "content_type": 41}}, {"pk": 122, "model": "auth.permission", "fields": {"codename": "change_pendingemailchange", "name": "Can change pending email change", "content_type": 41}}, {"pk": 123, "model": "auth.permission", "fields": {"codename": "delete_pendingemailchange", "name": "Can delete pending email change", "content_type": 41}}, {"pk": 118, "model": "auth.permission", "fields": {"codename": "add_pendingnamechange", "name": "Can add pending name change", "content_type": 40}}, {"pk": 119, "model": "auth.permission", "fields": {"codename": "change_pendingnamechange", "name": "Can change pending name change", "content_type": 40}}, {"pk": 120, "model": "auth.permission", "fields": {"codename": "delete_pendingnamechange", "name": "Can delete pending name change", "content_type": 40}}, {"pk": 115, "model": "auth.permission", "fields": {"codename": "add_registration", "name": "Can add registration", "content_type": 39}}, {"pk": 116, "model": "auth.permission", "fields": {"codename": "change_registration", "name": "Can change registration", "content_type": 39}}, {"pk": 117, "model": "auth.permission", "fields": {"codename": "delete_registration", "name": "Can delete registration", "content_type": 39}}, {"pk": 106, "model": "auth.permission", "fields": {"codename": "add_userprofile", "name": "Can add user profile", "content_type": 36}}, {"pk": 107, "model": "auth.permission", "fields": {"codename": "change_userprofile", "name": "Can change user profile", "content_type": 36}}, {"pk": 108, "model": "auth.permission", "fields": {"codename": "delete_userprofile", "name": "Can delete user profile", "content_type": 36}}, {"pk": 109, "model": "auth.permission", "fields": {"codename": "add_usersignupsource", "name": "Can add user signup source", "content_type": 37}}, {"pk": 110, "model": "auth.permission", "fields": {"codename": "change_usersignupsource", "name": "Can change user signup source", "content_type": 37}}, {"pk": 111, "model": "auth.permission", "fields": {"codename": "delete_usersignupsource", "name": "Can delete user signup source", "content_type": 37}}, {"pk": 103, "model": "auth.permission", "fields": {"codename": "add_userstanding", "name": "Can add user standing", "content_type": 35}}, {"pk": 104, "model": "auth.permission", "fields": {"codename": "change_userstanding", "name": "Can change user standing", "content_type": 35}}, {"pk": 105, "model": "auth.permission", "fields": {"codename": "delete_userstanding", "name": "Can delete user standing", "content_type": 35}}, {"pk": 112, "model": "auth.permission", "fields": {"codename": "add_usertestgroup", "name": "Can add user test group", "content_type": 38}}, {"pk": 113, "model": "auth.permission", "fields": {"codename": "change_usertestgroup", "name": "Can change user test group", "content_type": 38}}, {"pk": 114, "model": "auth.permission", "fields": {"codename": "delete_usertestgroup", "name": "Can delete user test group", "content_type": 38}}, {"pk": 409, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 136}}, {"pk": 410, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 136}}, {"pk": 411, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 136}}, {"pk": 412, "model": "auth.permission", "fields": {"codename": "add_scoresummary", "name": "Can add score summary", "content_type": 137}}, {"pk": 413, "model": "auth.permission", "fields": {"codename": "change_scoresummary", "name": "Can change score summary", "content_type": 137}}, {"pk": 414, "model": "auth.permission", "fields": {"codename": "delete_scoresummary", "name": "Can delete score summary", "content_type": 137}}, {"pk": 403, "model": "auth.permission", "fields": {"codename": "add_studentitem", "name": "Can add student item", "content_type": 134}}, {"pk": 404, "model": "auth.permission", "fields": {"codename": "change_studentitem", "name": "Can change student item", "content_type": 134}}, {"pk": 405, "model": "auth.permission", "fields": {"codename": "delete_studentitem", "name": "Can delete student item", "content_type": 134}}, {"pk": 406, "model": "auth.permission", "fields": {"codename": "add_submission", "name": "Can add submission", "content_type": 135}}, {"pk": 407, "model": "auth.permission", "fields": {"codename": "change_submission", "name": "Can change submission", "content_type": 135}}, {"pk": 408, "model": "auth.permission", "fields": {"codename": "delete_submission", "name": "Can delete submission", "content_type": 135}}, {"pk": 394, "model": "auth.permission", "fields": {"codename": "add_surveyanswer", "name": "Can add survey answer", "content_type": 131}}, {"pk": 395, "model": "auth.permission", "fields": {"codename": "change_surveyanswer", "name": "Can change survey answer", "content_type": 131}}, {"pk": 396, "model": "auth.permission", "fields": {"codename": "delete_surveyanswer", "name": "Can delete survey answer", "content_type": 131}}, {"pk": 391, "model": "auth.permission", "fields": {"codename": "add_surveyform", "name": "Can add survey form", "content_type": 130}}, {"pk": 392, "model": "auth.permission", "fields": {"codename": "change_surveyform", "name": "Can change survey form", "content_type": 130}}, {"pk": 393, "model": "auth.permission", "fields": {"codename": "delete_surveyform", "name": "Can delete survey form", "content_type": 130}}, {"pk": 148, "model": "auth.permission", "fields": {"codename": "add_trackinglog", "name": "Can add tracking log", "content_type": 50}}, {"pk": 149, "model": "auth.permission", "fields": {"codename": "change_trackinglog", "name": "Can change tracking log", "content_type": 50}}, {"pk": 150, "model": "auth.permission", "fields": {"codename": "delete_trackinglog", "name": "Can delete tracking log", "content_type": 50}}, {"pk": 289, "model": "auth.permission", "fields": {"codename": "add_usercoursetag", "name": "Can add user course tag", "content_type": 96}}, {"pk": 290, "model": "auth.permission", "fields": {"codename": "change_usercoursetag", "name": "Can change user course tag", "content_type": 96}}, {"pk": 291, "model": "auth.permission", "fields": {"codename": "delete_usercoursetag", "name": "Can delete user course tag", "content_type": 96}}, {"pk": 292, "model": "auth.permission", "fields": {"codename": "add_userorgtag", "name": "Can add user org tag", "content_type": 97}}, {"pk": 293, "model": "auth.permission", "fields": {"codename": "change_userorgtag", "name": "Can change user org tag", "content_type": 97}}, {"pk": 294, "model": "auth.permission", "fields": {"codename": "delete_userorgtag", "name": "Can delete user org tag", "content_type": 97}}, {"pk": 286, "model": "auth.permission", "fields": {"codename": "add_userpreference", "name": "Can add user preference", "content_type": 95}}, {"pk": 287, "model": "auth.permission", "fields": {"codename": "change_userpreference", "name": "Can change user preference", "content_type": 95}}, {"pk": 288, "model": "auth.permission", "fields": {"codename": "delete_userpreference", "name": "Can delete user preference", "content_type": 95}}, {"pk": 151, "model": "auth.permission", "fields": {"codename": "add_ratelimitconfiguration", "name": "Can add rate limit configuration", "content_type": 51}}, {"pk": 152, "model": "auth.permission", "fields": {"codename": "change_ratelimitconfiguration", "name": "Can change rate limit configuration", "content_type": 51}}, {"pk": 153, "model": "auth.permission", "fields": {"codename": "delete_ratelimitconfiguration", "name": "Can delete rate limit configuration", "content_type": 51}}, {"pk": 355, "model": "auth.permission", "fields": {"codename": "add_softwaresecurephotoverification", "name": "Can add software secure photo verification", "content_type": 118}}, {"pk": 356, "model": "auth.permission", "fields": {"codename": "change_softwaresecurephotoverification", "name": "Can change software secure photo verification", "content_type": 118}}, {"pk": 357, "model": "auth.permission", "fields": {"codename": "delete_softwaresecurephotoverification", "name": "Can delete software secure photo verification", "content_type": 118}}, {"pk": 229, "model": "auth.permission", "fields": {"codename": "add_article", "name": "Can add article", "content_type": 77}}, {"pk": 233, "model": "auth.permission", "fields": {"codename": "assign", "name": "Can change ownership of any article", "content_type": 77}}, {"pk": 230, "model": "auth.permission", "fields": {"codename": "change_article", "name": "Can change article", "content_type": 77}}, {"pk": 231, "model": "auth.permission", "fields": {"codename": "delete_article", "name": "Can delete article", "content_type": 77}}, {"pk": 234, "model": "auth.permission", "fields": {"codename": "grant", "name": "Can assign permissions to other users", "content_type": 77}}, {"pk": 232, "model": "auth.permission", "fields": {"codename": "moderate", "name": "Can edit all articles and lock/unlock/restore", "content_type": 77}}, {"pk": 235, "model": "auth.permission", "fields": {"codename": "add_articleforobject", "name": "Can add Article for object", "content_type": 78}}, {"pk": 236, "model": "auth.permission", "fields": {"codename": "change_articleforobject", "name": "Can change Article for object", "content_type": 78}}, {"pk": 237, "model": "auth.permission", "fields": {"codename": "delete_articleforobject", "name": "Can delete Article for object", "content_type": 78}}, {"pk": 244, "model": "auth.permission", "fields": {"codename": "add_articleplugin", "name": "Can add article plugin", "content_type": 81}}, {"pk": 245, "model": "auth.permission", "fields": {"codename": "change_articleplugin", "name": "Can change article plugin", "content_type": 81}}, {"pk": 246, "model": "auth.permission", "fields": {"codename": "delete_articleplugin", "name": "Can delete article plugin", "content_type": 81}}, {"pk": 238, "model": "auth.permission", "fields": {"codename": "add_articlerevision", "name": "Can add article revision", "content_type": 79}}, {"pk": 239, "model": "auth.permission", "fields": {"codename": "change_articlerevision", "name": "Can change article revision", "content_type": 79}}, {"pk": 240, "model": "auth.permission", "fields": {"codename": "delete_articlerevision", "name": "Can delete article revision", "content_type": 79}}, {"pk": 259, "model": "auth.permission", "fields": {"codename": "add_articlesubscription", "name": "Can add article subscription", "content_type": 86}}, {"pk": 260, "model": "auth.permission", "fields": {"codename": "change_articlesubscription", "name": "Can change article subscription", "content_type": 86}}, {"pk": 261, "model": "auth.permission", "fields": {"codename": "delete_articlesubscription", "name": "Can delete article subscription", "content_type": 86}}, {"pk": 247, "model": "auth.permission", "fields": {"codename": "add_reusableplugin", "name": "Can add reusable plugin", "content_type": 82}}, {"pk": 248, "model": "auth.permission", "fields": {"codename": "change_reusableplugin", "name": "Can change reusable plugin", "content_type": 82}}, {"pk": 249, "model": "auth.permission", "fields": {"codename": "delete_reusableplugin", "name": "Can delete reusable plugin", "content_type": 82}}, {"pk": 253, "model": "auth.permission", "fields": {"codename": "add_revisionplugin", "name": "Can add revision plugin", "content_type": 84}}, {"pk": 254, "model": "auth.permission", "fields": {"codename": "change_revisionplugin", "name": "Can change revision plugin", "content_type": 84}}, {"pk": 255, "model": "auth.permission", "fields": {"codename": "delete_revisionplugin", "name": "Can delete revision plugin", "content_type": 84}}, {"pk": 256, "model": "auth.permission", "fields": {"codename": "add_revisionpluginrevision", "name": "Can add revision plugin revision", "content_type": 85}}, {"pk": 257, "model": "auth.permission", "fields": {"codename": "change_revisionpluginrevision", "name": "Can change revision plugin revision", "content_type": 85}}, {"pk": 258, "model": "auth.permission", "fields": {"codename": "delete_revisionpluginrevision", "name": "Can delete revision plugin revision", "content_type": 85}}, {"pk": 250, "model": "auth.permission", "fields": {"codename": "add_simpleplugin", "name": "Can add simple plugin", "content_type": 83}}, {"pk": 251, "model": "auth.permission", "fields": {"codename": "change_simpleplugin", "name": "Can change simple plugin", "content_type": 83}}, {"pk": 252, "model": "auth.permission", "fields": {"codename": "delete_simpleplugin", "name": "Can delete simple plugin", "content_type": 83}}, {"pk": 241, "model": "auth.permission", "fields": {"codename": "add_urlpath", "name": "Can add URL path", "content_type": 80}}, {"pk": 242, "model": "auth.permission", "fields": {"codename": "change_urlpath", "name": "Can change URL path", "content_type": 80}}, {"pk": 243, "model": "auth.permission", "fields": {"codename": "delete_urlpath", "name": "Can delete URL path", "content_type": 80}}, {"pk": 463, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflow", "name": "Can add assessment workflow", "content_type": 154}}, {"pk": 464, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflow", "name": "Can change assessment workflow", "content_type": 154}}, {"pk": 465, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflow", "name": "Can delete assessment workflow", "content_type": 154}}, {"pk": 469, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowcancellation", "name": "Can add assessment workflow cancellation", "content_type": 156}}, {"pk": 470, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowcancellation", "name": "Can change assessment workflow cancellation", "content_type": 156}}, {"pk": 471, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowcancellation", "name": "Can delete assessment workflow cancellation", "content_type": 156}}, {"pk": 466, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowstep", "name": "Can add assessment workflow step", "content_type": 155}}, {"pk": 467, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowstep", "name": "Can change assessment workflow step", "content_type": 155}}, {"pk": 468, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowstep", "name": "Can delete assessment workflow step", "content_type": 155}}, {"pk": 508, "model": "auth.permission", "fields": {"codename": "add_studioconfig", "name": "Can add studio config", "content_type": 169}}, {"pk": 509, "model": "auth.permission", "fields": {"codename": "change_studioconfig", "name": "Can change studio config", "content_type": 169}}, {"pk": 510, "model": "auth.permission", "fields": {"codename": "delete_studioconfig", "name": "Can delete studio config", "content_type": 169}}, {"pk": 1, "model": "util.ratelimitconfiguration", "fields": {"change_date": "2015-03-31T06:25:45Z", "changed_by": null, "enabled": true}}, {"pk": 1, "model": "certificates.certificatehtmlviewconfiguration", "fields": {"change_date": "2015-03-31T06:25:47Z", "changed_by": null, "configuration": "{\n            {\n    \"default\": {\n        \"accomplishment_class_append\": \"accomplishment-certificate\",\n        \"platform_name\": \"edX\",\n        \"company_privacy_url\": \"http://www.edx.org/edx-privacy-policy\",\n        \"company_tos_url\": \"http://www.edx.org/edx-terms-service\",\n        \"company_verified_certificate_url\": \"http://www.edx.org/verified-certificate\",\n        \"document_stylesheet_url_application\": \"/static/certificates/sass/main-ltr.css\",\n        \"logo_src\": \"/static/certificates/images/logo-edx.svg\",\n        \"logo_url\": \"http://www.edx.org\"\n    },\n    \"honor\": {\n        \"certificate_type\": \"Honor Code\",\n        \"document_body_class_append\": \"is-honorcode\"\n    },\n    \"verified\": {\n        \"certificate_type\": \"Verified\",\n        \"document_body_class_append\": \"is-idverified\"\n    },\n    \"xseries\": {\n        \"certificate_type\": \"XSeries\",\n        \"document_body_class_append\": \"is-xseries\"\n    }\n}\n        }", "enabled": false}}, {"pk": 1, "model": "dark_lang.darklangconfig", "fields": {"change_date": "2015-03-31T06:26:01Z", "changed_by": null, "enabled": true, "released_languages": ""}}, {"pk": 1, "model": "mobile_api.mobileapiconfig", "fields": {"change_date": "2015-03-31T06:26:03Z", "video_profiles": "mobile_low,mobile_high,youtube", "changed_by": null, "enabled": false}}]
\ No newline at end of file
+[{"pk": 74, "model": "contenttypes.contenttype", "fields": {"model": "accesstoken", "name": "access token", "app_label": "oauth2"}}, {"pk": 151, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifier", "name": "ai classifier", "app_label": "assessment"}}, {"pk": 150, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifierset", "name": "ai classifier set", "app_label": "assessment"}}, {"pk": 153, "model": "contenttypes.contenttype", "fields": {"model": "aigradingworkflow", "name": "ai grading workflow", "app_label": "assessment"}}, {"pk": 152, "model": "contenttypes.contenttype", "fields": {"model": "aitrainingworkflow", "name": "ai training workflow", "app_label": "assessment"}}, {"pk": 34, "model": "contenttypes.contenttype", "fields": {"model": "anonymoususerid", "name": "anonymous user id", "app_label": "student"}}, {"pk": 77, "model": "contenttypes.contenttype", "fields": {"model": "article", "name": "article", "app_label": "wiki"}}, {"pk": 78, "model": "contenttypes.contenttype", "fields": {"model": "articleforobject", "name": "Article for object", "app_label": "wiki"}}, {"pk": 81, "model": "contenttypes.contenttype", "fields": {"model": "articleplugin", "name": "article plugin", "app_label": "wiki"}}, {"pk": 79, "model": "contenttypes.contenttype", "fields": {"model": "articlerevision", "name": "article revision", "app_label": "wiki"}}, {"pk": 86, "model": "contenttypes.contenttype", "fields": {"model": "articlesubscription", "name": "article subscription", "app_label": "wiki"}}, {"pk": 141, "model": "contenttypes.contenttype", "fields": {"model": "assessment", "name": "assessment", "app_label": "assessment"}}, {"pk": 144, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedback", "name": "assessment feedback", "app_label": "assessment"}}, {"pk": 143, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedbackoption", "name": "assessment feedback option", "app_label": "assessment"}}, {"pk": 142, "model": "contenttypes.contenttype", "fields": {"model": "assessmentpart", "name": "assessment part", "app_label": "assessment"}}, {"pk": 154, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflow", "name": "assessment workflow", "app_label": "workflow"}}, {"pk": 156, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowcancellation", "name": "assessment workflow cancellation", "app_label": "workflow"}}, {"pk": 155, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowstep", "name": "assessment workflow step", "app_label": "workflow"}}, {"pk": 19, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "django_openid_auth"}}, {"pk": 25, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "default"}}, {"pk": 70, "model": "contenttypes.contenttype", "fields": {"model": "brandinginfoconfig", "name": "branding info config", "app_label": "branding"}}, {"pk": 57, "model": "contenttypes.contenttype", "fields": {"model": "certificategenerationconfiguration", "name": "certificate generation configuration", "app_label": "certificates"}}, {"pk": 56, "model": "contenttypes.contenttype", "fields": {"model": "certificategenerationcoursesetting", "name": "certificate generation course setting", "app_label": "certificates"}}, {"pk": 58, "model": "contenttypes.contenttype", "fields": {"model": "certificatehtmlviewconfiguration", "name": "certificate html view configuration", "app_label": "certificates"}}, {"pk": 113, "model": "contenttypes.contenttype", "fields": {"model": "certificateitem", "name": "certificate item", "app_label": "shoppingcart"}}, {"pk": 52, "model": "contenttypes.contenttype", "fields": {"model": "certificatewhitelist", "name": "certificate whitelist", "app_label": "certificates"}}, {"pk": 72, "model": "contenttypes.contenttype", "fields": {"model": "client", "name": "client", "app_label": "oauth2"}}, {"pk": 26, "model": "contenttypes.contenttype", "fields": {"model": "code", "name": "code", "app_label": "default"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 22, "model": "contenttypes.contenttype", "fields": {"model": "corsmodel", "name": "cors model", "app_label": "corsheaders"}}, {"pk": 124, "model": "contenttypes.contenttype", "fields": {"model": "country", "name": "country", "app_label": "embargo"}}, {"pk": 125, "model": "contenttypes.contenttype", "fields": {"model": "countryaccessrule", "name": "country access rule", "app_label": "embargo"}}, {"pk": 107, "model": "contenttypes.contenttype", "fields": {"model": "coupon", "name": "coupon", "app_label": "shoppingcart"}}, {"pk": 108, "model": "contenttypes.contenttype", "fields": {"model": "couponredemption", "name": "coupon redemption", "app_label": "shoppingcart"}}, {"pk": 46, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrole", "name": "course access role", "app_label": "student"}}, {"pk": 126, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrulehistory", "name": "course access rule history", "app_label": "embargo"}}, {"pk": 69, "model": "contenttypes.contenttype", "fields": {"model": "courseauthorization", "name": "course authorization", "app_label": "bulk_email"}}, {"pk": 65, "model": "contenttypes.contenttype", "fields": {"model": "coursecohort", "name": "course cohort", "app_label": "course_groups"}}, {"pk": 64, "model": "contenttypes.contenttype", "fields": {"model": "coursecohortssettings", "name": "course cohorts settings", "app_label": "course_groups"}}, {"pk": 165, "model": "contenttypes.contenttype", "fields": {"model": "coursecontentmilestone", "name": "course content milestone", "app_label": "milestones"}}, {"pk": 168, "model": "contenttypes.contenttype", "fields": {"model": "coursecreator", "name": "course creator", "app_label": "course_creators"}}, {"pk": 66, "model": "contenttypes.contenttype", "fields": {"model": "courseemail", "name": "course email", "app_label": "bulk_email"}}, {"pk": 68, "model": "contenttypes.contenttype", "fields": {"model": "courseemailtemplate", "name": "course email template", "app_label": "bulk_email"}}, {"pk": 44, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollment", "name": "course enrollment", "app_label": "student"}}, {"pk": 45, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollmentallowed", "name": "course enrollment allowed", "app_label": "student"}}, {"pk": 164, "model": "contenttypes.contenttype", "fields": {"model": "coursemilestone", "name": "course milestone", "app_label": "milestones"}}, {"pk": 116, "model": "contenttypes.contenttype", "fields": {"model": "coursemode", "name": "course mode", "app_label": "course_modes"}}, {"pk": 117, "model": "contenttypes.contenttype", "fields": {"model": "coursemodesarchive", "name": "course modes archive", "app_label": "course_modes"}}, {"pk": 110, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitem", "name": "course reg code item", "app_label": "shoppingcart"}}, {"pk": 111, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitemannotation", "name": "course reg code item annotation", "app_label": "shoppingcart"}}, {"pk": 105, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcode", "name": "course registration code", "app_label": "shoppingcart"}}, {"pk": 103, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcodeinvoiceitem", "name": "course registration code invoice item", "app_label": "shoppingcart"}}, {"pk": 128, "model": "contenttypes.contenttype", "fields": {"model": "coursererunstate", "name": "course rerun state", "app_label": "course_action_state"}}, {"pk": 60, "model": "contenttypes.contenttype", "fields": {"model": "coursesoftware", "name": "course software", "app_label": "licenses"}}, {"pk": 133, "model": "contenttypes.contenttype", "fields": {"model": "coursestructure", "name": "course structure", "app_label": "course_structures"}}, {"pk": 62, "model": "contenttypes.contenttype", "fields": {"model": "courseusergroup", "name": "course user group", "app_label": "course_groups"}}, {"pk": 63, "model": "contenttypes.contenttype", "fields": {"model": "courseusergrouppartitiongroup", "name": "course user group partition group", "app_label": "course_groups"}}, {"pk": 159, "model": "contenttypes.contenttype", "fields": {"model": "coursevideo", "name": "course video", "app_label": "edxval"}}, {"pk": 139, "model": "contenttypes.contenttype", "fields": {"model": "criterion", "name": "criterion", "app_label": "assessment"}}, {"pk": 140, "model": "contenttypes.contenttype", "fields": {"model": "criterionoption", "name": "criterion option", "app_label": "assessment"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "crontabschedule", "name": "crontab", "app_label": "djcelery"}}, {"pk": 119, "model": "contenttypes.contenttype", "fields": {"model": "darklangconfig", "name": "dark lang config", "app_label": "dark_lang"}}, {"pk": 47, "model": "contenttypes.contenttype", "fields": {"model": "dashboardconfiguration", "name": "dashboard configuration", "app_label": "student"}}, {"pk": 115, "model": "contenttypes.contenttype", "fields": {"model": "donation", "name": "donation", "app_label": "shoppingcart"}}, {"pk": 114, "model": "contenttypes.contenttype", "fields": {"model": "donationconfiguration", "name": "donation configuration", "app_label": "shoppingcart"}}, {"pk": 121, "model": "contenttypes.contenttype", "fields": {"model": "embargoedcourse", "name": "embargoed course", "app_label": "embargo"}}, {"pk": 122, "model": "contenttypes.contenttype", "fields": {"model": "embargoedstate", "name": "embargoed state", "app_label": "embargo"}}, {"pk": 160, "model": "contenttypes.contenttype", "fields": {"model": "encodedvideo", "name": "encoded video", "app_label": "edxval"}}, {"pk": 49, "model": "contenttypes.contenttype", "fields": {"model": "entranceexamconfiguration", "name": "entrance exam configuration", "app_label": "student"}}, {"pk": 55, "model": "contenttypes.contenttype", "fields": {"model": "examplecertificate", "name": "example certificate", "app_label": "certificates"}}, {"pk": 54, "model": "contenttypes.contenttype", "fields": {"model": "examplecertificateset", "name": "example certificate set", "app_label": "certificates"}}, {"pk": 71, "model": "contenttypes.contenttype", "fields": {"model": "externalauthmap", "name": "external auth map", "app_label": "external_auth"}}, {"pk": 53, "model": "contenttypes.contenttype", "fields": {"model": "generatedcertificate", "name": "generated certificate", "app_label": "certificates"}}, {"pk": 73, "model": "contenttypes.contenttype", "fields": {"model": "grant", "name": "grant", "app_label": "oauth2"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 59, "model": "contenttypes.contenttype", "fields": {"model": "instructortask", "name": "instructor task", "app_label": "instructor_task"}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "intervalschedule", "name": "interval", "app_label": "djcelery"}}, {"pk": 100, "model": "contenttypes.contenttype", "fields": {"model": "invoice", "name": "invoice", "app_label": "shoppingcart"}}, {"pk": 104, "model": "contenttypes.contenttype", "fields": {"model": "invoicehistory", "name": "invoice history", "app_label": "shoppingcart"}}, {"pk": 102, "model": "contenttypes.contenttype", "fields": {"model": "invoiceitem", "name": "invoice item", "app_label": "shoppingcart"}}, {"pk": 101, "model": "contenttypes.contenttype", "fields": {"model": "invoicetransaction", "name": "invoice transaction", "app_label": "shoppingcart"}}, {"pk": 127, "model": "contenttypes.contenttype", "fields": {"model": "ipfilter", "name": "ip filter", "app_label": "embargo"}}, {"pk": 48, "model": "contenttypes.contenttype", "fields": {"model": "linkedinaddtoprofileconfiguration", "name": "linked in add to profile configuration", "app_label": "student"}}, {"pk": 21, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 43, "model": "contenttypes.contenttype", "fields": {"model": "loginfailures", "name": "login failures", "app_label": "student"}}, {"pk": 120, "model": "contenttypes.contenttype", "fields": {"model": "midcoursereverificationwindow", "name": "midcourse reverification window", "app_label": "reverification"}}, {"pk": 15, "model": "contenttypes.contenttype", "fields": {"model": "migrationhistory", "name": "migration history", "app_label": "south"}}, {"pk": 162, "model": "contenttypes.contenttype", "fields": {"model": "milestone", "name": "milestone", "app_label": "milestones"}}, {"pk": 163, "model": "contenttypes.contenttype", "fields": {"model": "milestonerelationshiptype", "name": "milestone relationship type", "app_label": "milestones"}}, {"pk": 129, "model": "contenttypes.contenttype", "fields": {"model": "mobileapiconfig", "name": "mobile api config", "app_label": "mobile_api"}}, {"pk": 18, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "django_openid_auth"}}, {"pk": 24, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "default"}}, {"pk": 93, "model": "contenttypes.contenttype", "fields": {"model": "note", "name": "note", "app_label": "notes"}}, {"pk": 90, "model": "contenttypes.contenttype", "fields": {"model": "notification", "name": "notification", "app_label": "django_notify"}}, {"pk": 32, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgrade", "name": "offline computed grade", "app_label": "courseware"}}, {"pk": 33, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgradelog", "name": "offline computed grade log", "app_label": "courseware"}}, {"pk": 67, "model": "contenttypes.contenttype", "fields": {"model": "optout", "name": "optout", "app_label": "bulk_email"}}, {"pk": 98, "model": "contenttypes.contenttype", "fields": {"model": "order", "name": "order", "app_label": "shoppingcart"}}, {"pk": 99, "model": "contenttypes.contenttype", "fields": {"model": "orderitem", "name": "order item", "app_label": "shoppingcart"}}, {"pk": 109, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistration", "name": "paid course registration", "app_label": "shoppingcart"}}, {"pk": 112, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistrationannotation", "name": "paid course registration annotation", "app_label": "shoppingcart"}}, {"pk": 42, "model": "contenttypes.contenttype", "fields": {"model": "passwordhistory", "name": "password history", "app_label": "student"}}, {"pk": 145, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflow", "name": "peer workflow", "app_label": "assessment"}}, {"pk": 146, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflowitem", "name": "peer workflow item", "app_label": "assessment"}}, {"pk": 41, "model": "contenttypes.contenttype", "fields": {"model": "pendingemailchange", "name": "pending email change", "app_label": "student"}}, {"pk": 40, "model": "contenttypes.contenttype", "fields": {"model": "pendingnamechange", "name": "pending name change", "app_label": "student"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "periodictask", "name": "periodic task", "app_label": "djcelery"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "periodictasks", "name": "periodic tasks", "app_label": "djcelery"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 157, "model": "contenttypes.contenttype", "fields": {"model": "profile", "name": "profile", "app_label": "edxval"}}, {"pk": 17, "model": "contenttypes.contenttype", "fields": {"model": "psychometricdata", "name": "psychometric data", "app_label": "psychometrics"}}, {"pk": 92, "model": "contenttypes.contenttype", "fields": {"model": "puzzlecomplete", "name": "puzzle complete", "app_label": "foldit"}}, {"pk": 51, "model": "contenttypes.contenttype", "fields": {"model": "ratelimitconfiguration", "name": "rate limit configuration", "app_label": "util"}}, {"pk": 75, "model": "contenttypes.contenttype", "fields": {"model": "refreshtoken", "name": "refresh token", "app_label": "oauth2"}}, {"pk": 39, "model": "contenttypes.contenttype", "fields": {"model": "registration", "name": "registration", "app_label": "student"}}, {"pk": 106, "model": "contenttypes.contenttype", "fields": {"model": "registrationcoderedemption", "name": "registration code redemption", "app_label": "shoppingcart"}}, {"pk": 123, "model": "contenttypes.contenttype", "fields": {"model": "restrictedcourse", "name": "restricted course", "app_label": "embargo"}}, {"pk": 82, "model": "contenttypes.contenttype", "fields": {"model": "reusableplugin", "name": "reusable plugin", "app_label": "wiki"}}, {"pk": 84, "model": "contenttypes.contenttype", "fields": {"model": "revisionplugin", "name": "revision plugin", "app_label": "wiki"}}, {"pk": 85, "model": "contenttypes.contenttype", "fields": {"model": "revisionpluginrevision", "name": "revision plugin revision", "app_label": "wiki"}}, {"pk": 138, "model": "contenttypes.contenttype", "fields": {"model": "rubric", "name": "rubric", "app_label": "assessment"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "tasksetmeta", "name": "saved group result", "app_label": "djcelery"}}, {"pk": 91, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "foldit"}}, {"pk": 136, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "submissions"}}, {"pk": 137, "model": "contenttypes.contenttype", "fields": {"model": "scoresummary", "name": "score summary", "app_label": "submissions"}}, {"pk": 16, "model": "contenttypes.contenttype", "fields": {"model": "servercircuit", "name": "server circuit", "app_label": "circuit"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 88, "model": "contenttypes.contenttype", "fields": {"model": "settings", "name": "settings", "app_label": "django_notify"}}, {"pk": 83, "model": "contenttypes.contenttype", "fields": {"model": "simpleplugin", "name": "simple plugin", "app_label": "wiki"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 118, "model": "contenttypes.contenttype", "fields": {"model": "softwaresecurephotoverification", "name": "software secure photo verification", "app_label": "verify_student"}}, {"pk": 94, "model": "contenttypes.contenttype", "fields": {"model": "splashconfig", "name": "splash config", "app_label": "splash"}}, {"pk": 134, "model": "contenttypes.contenttype", "fields": {"model": "studentitem", "name": "student item", "app_label": "submissions"}}, {"pk": 27, "model": "contenttypes.contenttype", "fields": {"model": "studentmodule", "name": "student module", "app_label": "courseware"}}, {"pk": 28, "model": "contenttypes.contenttype", "fields": {"model": "studentmodulehistory", "name": "student module history", "app_label": "courseware"}}, {"pk": 148, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflow", "name": "student training workflow", "app_label": "assessment"}}, {"pk": 149, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflowitem", "name": "student training workflow item", "app_label": "assessment"}}, {"pk": 169, "model": "contenttypes.contenttype", "fields": {"model": "studioconfig", "name": "studio config", "app_label": "xblock_config"}}, {"pk": 135, "model": "contenttypes.contenttype", "fields": {"model": "submission", "name": "submission", "app_label": "submissions"}}, {"pk": 89, "model": "contenttypes.contenttype", "fields": {"model": "subscription", "name": "subscription", "app_label": "django_notify"}}, {"pk": 161, "model": "contenttypes.contenttype", "fields": {"model": "subtitle", "name": "subtitle", "app_label": "edxval"}}, {"pk": 131, "model": "contenttypes.contenttype", "fields": {"model": "surveyanswer", "name": "survey answer", "app_label": "survey"}}, {"pk": 130, "model": "contenttypes.contenttype", "fields": {"model": "surveyform", "name": "survey form", "app_label": "survey"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "taskstate", "name": "task", "app_label": "djcelery"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "taskmeta", "name": "task state", "app_label": "djcelery"}}, {"pk": 50, "model": "contenttypes.contenttype", "fields": {"model": "trackinglog", "name": "tracking log", "app_label": "track"}}, {"pk": 147, "model": "contenttypes.contenttype", "fields": {"model": "trainingexample", "name": "training example", "app_label": "assessment"}}, {"pk": 76, "model": "contenttypes.contenttype", "fields": {"model": "trustedclient", "name": "trusted client", "app_label": "oauth2_provider"}}, {"pk": 87, "model": "contenttypes.contenttype", "fields": {"model": "notificationtype", "name": "type", "app_label": "django_notify"}}, {"pk": 80, "model": "contenttypes.contenttype", "fields": {"model": "urlpath", "name": "URL path", "app_label": "wiki"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}, {"pk": 96, "model": "contenttypes.contenttype", "fields": {"model": "usercoursetag", "name": "user course tag", "app_label": "user_api"}}, {"pk": 61, "model": "contenttypes.contenttype", "fields": {"model": "userlicense", "name": "user license", "app_label": "licenses"}}, {"pk": 166, "model": "contenttypes.contenttype", "fields": {"model": "usermilestone", "name": "user milestone", "app_label": "milestones"}}, {"pk": 20, "model": "contenttypes.contenttype", "fields": {"model": "useropenid", "name": "user open id", "app_label": "django_openid_auth"}}, {"pk": 97, "model": "contenttypes.contenttype", "fields": {"model": "userorgtag", "name": "user org tag", "app_label": "user_api"}}, {"pk": 95, "model": "contenttypes.contenttype", "fields": {"model": "userpreference", "name": "user preference", "app_label": "user_api"}}, {"pk": 36, "model": "contenttypes.contenttype", "fields": {"model": "userprofile", "name": "user profile", "app_label": "student"}}, {"pk": 37, "model": "contenttypes.contenttype", "fields": {"model": "usersignupsource", "name": "user signup source", "app_label": "student"}}, {"pk": 23, "model": "contenttypes.contenttype", "fields": {"model": "usersocialauth", "name": "user social auth", "app_label": "default"}}, {"pk": 35, "model": "contenttypes.contenttype", "fields": {"model": "userstanding", "name": "user standing", "app_label": "student"}}, {"pk": 38, "model": "contenttypes.contenttype", "fields": {"model": "usertestgroup", "name": "user test group", "app_label": "student"}}, {"pk": 158, "model": "contenttypes.contenttype", "fields": {"model": "video", "name": "video", "app_label": "edxval"}}, {"pk": 167, "model": "contenttypes.contenttype", "fields": {"model": "videouploadconfig", "name": "video upload config", "app_label": "contentstore"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "workerstate", "name": "worker", "app_label": "djcelery"}}, {"pk": 132, "model": "contenttypes.contenttype", "fields": {"model": "xblockasidesconfig", "name": "x block asides config", "app_label": "lms_xblock"}}, {"pk": 31, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentinfofield", "name": "x module student info field", "app_label": "courseware"}}, {"pk": 30, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentprefsfield", "name": "x module student prefs field", "app_label": "courseware"}}, {"pk": 29, "model": "contenttypes.contenttype", "fields": {"model": "xmoduleuserstatesummaryfield", "name": "x module user state summary field", "app_label": "courseware"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0001_initial"}}, {"pk": 2, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0002_add_indexes"}}, {"pk": 3, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0003_done_grade_cache"}}, {"pk": 4, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0004_add_field_studentmodule_course_id"}}, {"pk": 5, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c"}}, {"pk": 6, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0006_create_student_module_history"}}, {"pk": 7, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:39Z", "app_name": "courseware", "migration": "0007_allow_null_version_in_history"}}, {"pk": 8, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0008_add_xmodule_storage"}}, {"pk": 9, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0009_add_field_default"}}, {"pk": 10, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "courseware", "migration": "0010_rename_xblock_field_content_to_user_state_summary"}}, {"pk": 11, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0001_initial"}}, {"pk": 12, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0002_text_to_varchar_and_indexes"}}, {"pk": 13, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:40Z", "app_name": "student", "migration": "0003_auto__add_usertestgroup"}}, {"pk": 14, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0004_add_email_index"}}, {"pk": 15, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0005_name_change"}}, {"pk": 16, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0006_expand_meta_field"}}, {"pk": 17, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0007_convert_to_utf8"}}, {"pk": 18, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0008__auto__add_courseregistration"}}, {"pk": 19, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0009_auto__del_courseregistration__add_courseenrollment"}}, {"pk": 20, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0010_auto__chg_field_courseenrollment_course_id"}}, {"pk": 21, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0011_auto__chg_field_courseenrollment_user__del_unique_courseenrollment_use"}}, {"pk": 22, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0012_auto__add_field_userprofile_gender__add_field_userprofile_date_of_birt"}}, {"pk": 23, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0013_auto__chg_field_userprofile_meta"}}, {"pk": 24, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0014_auto__del_courseenrollment"}}, {"pk": 25, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0015_auto__add_courseenrollment__add_unique_courseenrollment_user_course_id"}}, {"pk": 26, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0016_auto__add_field_courseenrollment_date__chg_field_userprofile_country"}}, {"pk": 27, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0017_rename_date_to_created"}}, {"pk": 28, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0018_auto"}}, {"pk": 29, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:41Z", "app_name": "student", "migration": "0019_create_approved_demographic_fields_fall_2012"}}, {"pk": 30, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0020_add_test_center_user"}}, {"pk": 31, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0021_remove_askbot"}}, {"pk": 32, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0022_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_"}}, {"pk": 33, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0023_add_test_center_registration"}}, {"pk": 34, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0024_add_allow_certificate"}}, {"pk": 35, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0025_auto__add_field_courseenrollmentallowed_auto_enroll"}}, {"pk": 36, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0026_auto__remove_index_student_testcenterregistration_accommodation_request"}}, {"pk": 37, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0027_add_active_flag_and_mode_to_courseware_enrollment"}}, {"pk": 38, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0028_auto__add_userstanding"}}, {"pk": 39, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0029_add_lookup_table_between_user_and_anonymous_student_id"}}, {"pk": 40, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0029_remove_pearson"}}, {"pk": 41, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0030_auto__chg_field_anonymoususerid_anonymous_user_id"}}, {"pk": 42, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0031_drop_student_anonymoususerid_temp_archive"}}, {"pk": 43, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:42Z", "app_name": "student", "migration": "0032_add_field_UserProfile_country_add_field_UserProfile_city"}}, {"pk": 44, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0032_auto__add_loginfailures"}}, {"pk": 45, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0033_auto__add_passwordhistory"}}, {"pk": 46, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:43Z", "app_name": "student", "migration": "0034_auto__add_courseaccessrole"}}, {"pk": 47, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0035_access_roles"}}, {"pk": 48, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0036_access_roles_orgless"}}, {"pk": 49, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0037_auto__add_courseregistrationcode"}}, {"pk": 50, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0038_auto__add_usersignupsource"}}, {"pk": 51, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0039_auto__del_courseregistrationcode"}}, {"pk": 52, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0040_auto__del_field_usersignupsource_user_id__add_field_usersignupsource_u"}}, {"pk": 53, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0041_add_dashboard_config"}}, {"pk": 54, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0042_grant_sales_admin_roles"}}, {"pk": 55, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0043_auto__add_linkedinaddtoprofileconfiguration"}}, {"pk": 56, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:44Z", "app_name": "student", "migration": "0044_linkedin_add_company_identifier"}}, {"pk": 57, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "student", "migration": "0045_add_trk_partner_to_linkedin_config"}}, {"pk": 58, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "student", "migration": "0046_auto__add_entranceexamconfiguration__add_unique_entranceexamconfigurat"}}, {"pk": 59, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "track", "migration": "0001_initial"}}, {"pk": 60, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "track", "migration": "0002_auto__add_field_trackinglog_host__chg_field_trackinglog_event_type__ch"}}, {"pk": 61, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "util", "migration": "0001_initial"}}, {"pk": 62, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:45Z", "app_name": "util", "migration": "0002_default_rate_limit_config"}}, {"pk": 63, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0001_added_generatedcertificates"}}, {"pk": 64, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0002_auto__add_field_generatedcertificate_download_url"}}, {"pk": 65, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0003_auto__add_field_generatedcertificate_enabled"}}, {"pk": 66, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0004_auto__add_field_generatedcertificate_graded_certificate_id__add_field_"}}, {"pk": 67, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0005_auto__add_field_generatedcertificate_name"}}, {"pk": 68, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0006_auto__chg_field_generatedcertificate_certificate_id"}}, {"pk": 69, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0007_auto__add_revokedcertificate"}}, {"pk": 70, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0008_auto__del_revokedcertificate__del_field_generatedcertificate_name__add"}}, {"pk": 71, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0009_auto__del_field_generatedcertificate_graded_download_url__del_field_ge"}}, {"pk": 72, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0010_auto__del_field_generatedcertificate_enabled__add_field_generatedcerti"}}, {"pk": 73, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0011_auto__del_field_generatedcertificate_certificate_id__add_field_generat"}}, {"pk": 74, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0012_auto__add_field_generatedcertificate_name__add_field_generatedcertific"}}, {"pk": 75, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0013_auto__add_field_generatedcertificate_error_reason"}}, {"pk": 76, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:46Z", "app_name": "certificates", "migration": "0014_adding_whitelist"}}, {"pk": 77, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0015_adding_mode_for_verified_certs"}}, {"pk": 78, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0016_change_course_key_fields"}}, {"pk": 79, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0017_auto__add_certificategenerationconfiguration"}}, {"pk": 80, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0018_add_example_cert_models"}}, {"pk": 81, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0019_auto__add_certificatehtmlviewconfiguration"}}, {"pk": 82, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "certificates", "migration": "0020_certificatehtmlviewconfiguration_data"}}, {"pk": 83, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "instructor_task", "migration": "0001_initial"}}, {"pk": 84, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:47Z", "app_name": "instructor_task", "migration": "0002_add_subtask_field"}}, {"pk": 85, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "licenses", "migration": "0001_initial"}}, {"pk": 86, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0001_initial"}}, {"pk": 87, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0002_add_model_CourseUserGroupPartitionGroup"}}, {"pk": 88, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0003_auto__add_coursecohort__add_coursecohortssettings"}}, {"pk": 89, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:48Z", "app_name": "course_groups", "migration": "0004_auto__del_field_coursecohortssettings_cohorted_discussions__add_field_"}}, {"pk": 90, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0001_initial"}}, {"pk": 91, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0002_change_field_names"}}, {"pk": 92, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0003_add_optout_user"}}, {"pk": 93, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0004_migrate_optout_user"}}, {"pk": 94, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0005_remove_optout_email"}}, {"pk": 95, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0006_add_course_email_template"}}, {"pk": 96, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0007_load_course_email_template"}}, {"pk": 97, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0008_add_course_authorizations"}}, {"pk": 98, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0009_force_unique_course_ids"}}, {"pk": 99, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:49Z", "app_name": "bulk_email", "migration": "0010_auto__chg_field_optout_course_id__add_field_courseemail_template_name_"}}, {"pk": 100, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "branding", "migration": "0001_initial"}}, {"pk": 101, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "external_auth", "migration": "0001_initial"}}, {"pk": 102, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "oauth2", "migration": "0001_initial"}}, {"pk": 103, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:50Z", "app_name": "oauth2", "migration": "0002_auto__chg_field_client_user"}}, {"pk": 104, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2", "migration": "0003_auto__add_field_client_name"}}, {"pk": 105, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2", "migration": "0004_auto__add_index_accesstoken_token"}}, {"pk": 106, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:51Z", "app_name": "oauth2_provider", "migration": "0001_initial"}}, {"pk": 107, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0001_initial"}}, {"pk": 108, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0002_auto__add_field_articleplugin_created"}}, {"pk": 109, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0003_auto__add_field_urlpath_article"}}, {"pk": 110, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0004_populate_urlpath__article"}}, {"pk": 111, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0005_auto__chg_field_urlpath_article"}}, {"pk": 112, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0006_auto__add_attachmentrevision__add_image__add_attachment"}}, {"pk": 113, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0007_auto__add_articlesubscription"}}, {"pk": 114, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0008_auto__add_simpleplugin__add_revisionpluginrevision__add_imagerevision_"}}, {"pk": 115, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:52Z", "app_name": "wiki", "migration": "0009_auto__add_field_imagerevision_width__add_field_imagerevision_height"}}, {"pk": 116, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "wiki", "migration": "0010_auto__chg_field_imagerevision_image"}}, {"pk": 117, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "wiki", "migration": "0011_auto__chg_field_imagerevision_width__chg_field_imagerevision_height"}}, {"pk": 118, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "django_notify", "migration": "0001_initial"}}, {"pk": 119, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:53Z", "app_name": "notifications", "migration": "0001_initial"}}, {"pk": 120, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "foldit", "migration": "0001_initial"}}, {"pk": 121, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "django_comment_client", "migration": "0001_initial"}}, {"pk": 122, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:54Z", "app_name": "django_comment_common", "migration": "0001_initial"}}, {"pk": 123, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "notes", "migration": "0001_initial"}}, {"pk": 124, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "splash", "migration": "0001_initial"}}, {"pk": 125, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:55Z", "app_name": "splash", "migration": "0002_auto__add_field_splashconfig_unaffected_url_paths"}}, {"pk": 126, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0001_initial"}}, {"pk": 127, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0002_auto__add_usercoursetags__add_unique_usercoursetags_user_course_id_key"}}, {"pk": 128, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0003_rename_usercoursetags"}}, {"pk": 129, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "user_api", "migration": "0004_auto__add_userorgtag__add_unique_userorgtag_user_org_key__chg_field_us"}}, {"pk": 130, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0001_initial"}}, {"pk": 131, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0002_auto__add_field_paidcourseregistration_mode"}}, {"pk": 132, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0003_auto__del_field_orderitem_line_cost"}}, {"pk": 133, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:56Z", "app_name": "shoppingcart", "migration": "0004_auto__add_field_orderitem_fulfilled_time"}}, {"pk": 134, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0005_auto__add_paidcourseregistrationannotation__add_field_orderitem_report"}}, {"pk": 135, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0006_auto__add_field_order_refunded_time__add_field_orderitem_refund_reques"}}, {"pk": 136, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0007_auto__add_field_orderitem_service_fee"}}, {"pk": 137, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou"}}, {"pk": 138, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c"}}, {"pk": 139, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0010_auto__add_registrationcoderedemption__del_field_courseregistrationcode"}}, {"pk": 140, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:57Z", "app_name": "shoppingcart", "migration": "0011_auto__add_invoice__add_field_courseregistrationcode_invoice"}}, {"pk": 141, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0012_auto__del_field_courseregistrationcode_transaction_group_name__del_fie"}}, {"pk": 142, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0013_auto__add_field_invoice_is_valid"}}, {"pk": 143, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0014_auto__del_field_invoice_tax_id__add_field_invoice_address_line_1__add_"}}, {"pk": 144, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0015_auto__del_field_invoice_purchase_order_number__del_field_invoice_compa"}}, {"pk": 145, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0016_auto__del_field_invoice_company_email__del_field_invoice_company_refer"}}, {"pk": 146, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0017_auto__add_field_courseregistrationcode_order__chg_field_registrationco"}}, {"pk": 147, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0018_auto__add_donation"}}, {"pk": 148, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0019_auto__add_donationconfiguration"}}, {"pk": 149, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0020_auto__add_courseregcodeitem__add_courseregcodeitemannotation__add_fiel"}}, {"pk": 150, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:58Z", "app_name": "shoppingcart", "migration": "0021_auto__add_field_orderitem_created__add_field_orderitem_modified"}}, {"pk": 151, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0022_auto__add_field_registrationcoderedemption_course_enrollment__add_fiel"}}, {"pk": 152, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0023_auto__add_field_coupon_expiration_date"}}, {"pk": 153, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0024_auto__add_field_courseregistrationcode_mode_slug"}}, {"pk": 154, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0025_update_invoice_models"}}, {"pk": 155, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0026_migrate_invoices"}}, {"pk": 156, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:25:59Z", "app_name": "shoppingcart", "migration": "0027_add_invoice_history"}}, {"pk": 157, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0001_initial"}}, {"pk": 158, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0002_auto__add_field_coursemode_currency"}}, {"pk": 159, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0003_auto__add_unique_coursemode_course_id_currency_mode_slug"}}, {"pk": 160, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0004_auto__add_field_coursemode_expiration_date"}}, {"pk": 161, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0005_auto__add_field_coursemode_expiration_datetime"}}, {"pk": 162, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0006_expiration_date_to_datetime"}}, {"pk": 163, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0007_add_description"}}, {"pk": 164, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0007_auto__add_coursemodesarchive__chg_field_coursemode_course_id"}}, {"pk": 165, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "course_modes", "migration": "0008_auto__del_field_coursemodesarchive_description__add_field_coursemode_s"}}, {"pk": 166, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0001_initial"}}, {"pk": 167, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0002_auto__add_field_softwaresecurephotoverification_window"}}, {"pk": 168, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:00Z", "app_name": "verify_student", "migration": "0003_auto__add_field_softwaresecurephotoverification_display"}}, {"pk": 169, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "dark_lang", "migration": "0001_initial"}}, {"pk": 170, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "dark_lang", "migration": "0002_enable_on_install"}}, {"pk": 171, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "reverification", "migration": "0001_initial"}}, {"pk": 172, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:01Z", "app_name": "embargo", "migration": "0001_initial"}}, {"pk": 173, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0002_add_country_access_models"}}, {"pk": 174, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0003_add_countries"}}, {"pk": 175, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0004_migrate_embargo_config"}}, {"pk": 176, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:02Z", "app_name": "embargo", "migration": "0005_add_courseaccessrulehistory"}}, {"pk": 177, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "course_action_state", "migration": "0001_initial"}}, {"pk": 178, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "course_action_state", "migration": "0002_add_rerun_display_name"}}, {"pk": 179, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:03Z", "app_name": "mobile_api", "migration": "0001_initial"}}, {"pk": 180, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "survey", "migration": "0001_initial"}}, {"pk": 181, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "lms_xblock", "migration": "0001_initial"}}, {"pk": 182, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:04Z", "app_name": "course_structures", "migration": "0001_initial"}}, {"pk": 183, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0001_initial"}}, {"pk": 184, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0002_auto__add_scoresummary"}}, {"pk": 185, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0003_auto__del_field_submission_answer__add_field_submission_raw_answer"}}, {"pk": 186, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:05Z", "app_name": "submissions", "migration": "0004_auto__add_field_score_reset"}}, {"pk": 187, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0001_initial"}}, {"pk": 188, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0002_auto__add_assessmentfeedbackoption__del_field_assessmentfeedback_feedb"}}, {"pk": 189, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0003_add_index_pw_course_item_student"}}, {"pk": 190, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0004_auto__add_field_peerworkflow_graded_count"}}, {"pk": 191, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0005_auto__del_field_peerworkflow_graded_count__add_field_peerworkflow_grad"}}, {"pk": 192, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0006_auto__add_field_assessmentpart_feedback"}}, {"pk": 193, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0007_auto__chg_field_assessmentpart_feedback"}}, {"pk": 194, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0008_student_training"}}, {"pk": 195, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0009_auto__add_unique_studenttrainingworkflowitem_order_num_workflow"}}, {"pk": 196, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:06Z", "app_name": "assessment", "migration": "0010_auto__add_unique_studenttrainingworkflow_submission_uuid"}}, {"pk": 197, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0011_ai_training"}}, {"pk": 198, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0012_move_algorithm_id_to_classifier_set"}}, {"pk": 199, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0013_auto__add_field_aigradingworkflow_essay_text"}}, {"pk": 200, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0014_auto__add_field_aitrainingworkflow_item_id__add_field_aitrainingworkfl"}}, {"pk": 201, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0015_auto__add_unique_aitrainingworkflow_uuid__add_unique_aigradingworkflow"}}, {"pk": 202, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0016_auto__add_field_aiclassifierset_course_id__add_field_aiclassifierset_i"}}, {"pk": 203, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0016_auto__add_field_rubric_structure_hash"}}, {"pk": 204, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0017_rubric_structure_hash"}}, {"pk": 205, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0018_auto__add_field_assessmentpart_criterion"}}, {"pk": 206, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0019_assessmentpart_criterion_field"}}, {"pk": 207, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0020_assessmentpart_criterion_not_null"}}, {"pk": 208, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:07Z", "app_name": "assessment", "migration": "0021_assessmentpart_option_nullable"}}, {"pk": 209, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0022__add_label_fields"}}, {"pk": 210, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0023_assign_criteria_and_option_labels"}}, {"pk": 211, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0024_auto__chg_field_assessmentpart_criterion"}}, {"pk": 212, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "assessment", "migration": "0025_auto__add_field_peerworkflow_cancelled_at"}}, {"pk": 213, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0001_initial"}}, {"pk": 214, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0002_auto__add_field_assessmentworkflow_course_id__add_field_assessmentwork"}}, {"pk": 215, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0003_auto__add_assessmentworkflowstep"}}, {"pk": 216, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:08Z", "app_name": "workflow", "migration": "0004_auto__add_assessmentworkflowcancellation"}}, {"pk": 217, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0001_initial"}}, {"pk": 218, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0002_default_profiles"}}, {"pk": 219, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0003_status_and_created_fields"}}, {"pk": 220, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:09Z", "app_name": "edxval", "migration": "0004_remove_profile_fields"}}, {"pk": 221, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "milestones", "migration": "0001_initial"}}, {"pk": 222, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "milestones", "migration": "0002_seed_relationship_types"}}, {"pk": 223, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:10Z", "app_name": "django_extensions", "migration": "0001_empty"}}, {"pk": 224, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "contentstore", "migration": "0001_initial"}}, {"pk": 225, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "contentstore", "migration": "0002_auto__del_field_videouploadconfig_status_whitelist"}}, {"pk": 226, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:15Z", "app_name": "course_creators", "migration": "0001_initial"}}, {"pk": 227, "model": "south.migrationhistory", "fields": {"applied": "2015-03-31T06:26:16Z", "app_name": "xblock_config", "migration": "0001_initial"}}, {"pk": 5, "model": "embargo.country", "fields": {"country": "AD"}}, {"pk": 233, "model": "embargo.country", "fields": {"country": "AE"}}, {"pk": 1, "model": "embargo.country", "fields": {"country": "AF"}}, {"pk": 9, "model": "embargo.country", "fields": {"country": "AG"}}, {"pk": 7, "model": "embargo.country", "fields": {"country": "AI"}}, {"pk": 2, "model": "embargo.country", "fields": {"country": "AL"}}, {"pk": 11, "model": "embargo.country", "fields": {"country": "AM"}}, {"pk": 6, "model": "embargo.country", "fields": {"country": "AO"}}, {"pk": 8, "model": "embargo.country", "fields": {"country": "AQ"}}, {"pk": 10, "model": "embargo.country", "fields": {"country": "AR"}}, {"pk": 4, "model": "embargo.country", "fields": {"country": "AS"}}, {"pk": 14, "model": "embargo.country", "fields": {"country": "AT"}}, {"pk": 13, "model": "embargo.country", "fields": {"country": "AU"}}, {"pk": 12, "model": "embargo.country", "fields": {"country": "AW"}}, {"pk": 249, "model": "embargo.country", "fields": {"country": "AX"}}, {"pk": 15, "model": "embargo.country", "fields": {"country": "AZ"}}, {"pk": 28, "model": "embargo.country", "fields": {"country": "BA"}}, {"pk": 19, "model": "embargo.country", "fields": {"country": "BB"}}, {"pk": 18, "model": "embargo.country", "fields": {"country": "BD"}}, {"pk": 21, "model": "embargo.country", "fields": {"country": "BE"}}, {"pk": 35, "model": "embargo.country", "fields": {"country": "BF"}}, {"pk": 34, "model": "embargo.country", "fields": {"country": "BG"}}, {"pk": 17, "model": "embargo.country", "fields": {"country": "BH"}}, {"pk": 36, "model": "embargo.country", "fields": {"country": "BI"}}, {"pk": 23, "model": "embargo.country", "fields": {"country": "BJ"}}, {"pk": 184, "model": "embargo.country", "fields": {"country": "BL"}}, {"pk": 24, "model": "embargo.country", "fields": {"country": "BM"}}, {"pk": 33, "model": "embargo.country", "fields": {"country": "BN"}}, {"pk": 26, "model": "embargo.country", "fields": {"country": "BO"}}, {"pk": 27, "model": "embargo.country", "fields": {"country": "BQ"}}, {"pk": 31, "model": "embargo.country", "fields": {"country": "BR"}}, {"pk": 16, "model": "embargo.country", "fields": {"country": "BS"}}, {"pk": 25, "model": "embargo.country", "fields": {"country": "BT"}}, {"pk": 30, "model": "embargo.country", "fields": {"country": "BV"}}, {"pk": 29, "model": "embargo.country", "fields": {"country": "BW"}}, {"pk": 20, "model": "embargo.country", "fields": {"country": "BY"}}, {"pk": 22, "model": "embargo.country", "fields": {"country": "BZ"}}, {"pk": 39, "model": "embargo.country", "fields": {"country": "CA"}}, {"pk": 47, "model": "embargo.country", "fields": {"country": "CC"}}, {"pk": 51, "model": "embargo.country", "fields": {"country": "CD"}}, {"pk": 42, "model": "embargo.country", "fields": {"country": "CF"}}, {"pk": 50, "model": "embargo.country", "fields": {"country": "CG"}}, {"pk": 215, "model": "embargo.country", "fields": {"country": "CH"}}, {"pk": 59, "model": "embargo.country", "fields": {"country": "CI"}}, {"pk": 52, "model": "embargo.country", "fields": {"country": "CK"}}, {"pk": 44, "model": "embargo.country", "fields": {"country": "CL"}}, {"pk": 38, "model": "embargo.country", "fields": {"country": "CM"}}, {"pk": 45, "model": "embargo.country", "fields": {"country": "CN"}}, {"pk": 48, "model": "embargo.country", "fields": {"country": "CO"}}, {"pk": 53, "model": "embargo.country", "fields": {"country": "CR"}}, {"pk": 55, "model": "embargo.country", "fields": {"country": "CU"}}, {"pk": 40, "model": "embargo.country", "fields": {"country": "CV"}}, {"pk": 56, "model": "embargo.country", "fields": {"country": "CW"}}, {"pk": 46, "model": "embargo.country", "fields": {"country": "CX"}}, {"pk": 57, "model": "embargo.country", "fields": {"country": "CY"}}, {"pk": 58, "model": "embargo.country", "fields": {"country": "CZ"}}, {"pk": 82, "model": "embargo.country", "fields": {"country": "DE"}}, {"pk": 61, "model": "embargo.country", "fields": {"country": "DJ"}}, {"pk": 60, "model": "embargo.country", "fields": {"country": "DK"}}, {"pk": 62, "model": "embargo.country", "fields": {"country": "DM"}}, {"pk": 63, "model": "embargo.country", "fields": {"country": "DO"}}, {"pk": 3, "model": "embargo.country", "fields": {"country": "DZ"}}, {"pk": 64, "model": "embargo.country", "fields": {"country": "EC"}}, {"pk": 69, "model": "embargo.country", "fields": {"country": "EE"}}, {"pk": 65, "model": "embargo.country", "fields": {"country": "EG"}}, {"pk": 245, "model": "embargo.country", "fields": {"country": "EH"}}, {"pk": 68, "model": "embargo.country", "fields": {"country": "ER"}}, {"pk": 208, "model": "embargo.country", "fields": {"country": "ES"}}, {"pk": 70, "model": "embargo.country", "fields": {"country": "ET"}}, {"pk": 74, "model": "embargo.country", "fields": {"country": "FI"}}, {"pk": 73, "model": "embargo.country", "fields": {"country": "FJ"}}, {"pk": 71, "model": "embargo.country", "fields": {"country": "FK"}}, {"pk": 144, "model": "embargo.country", "fields": {"country": "FM"}}, {"pk": 72, "model": "embargo.country", "fields": {"country": "FO"}}, {"pk": 75, "model": "embargo.country", "fields": {"country": "FR"}}, {"pk": 79, "model": "embargo.country", "fields": {"country": "GA"}}, {"pk": 234, "model": "embargo.country", "fields": {"country": "GB"}}, {"pk": 87, "model": "embargo.country", "fields": {"country": "GD"}}, {"pk": 81, "model": "embargo.country", "fields": {"country": "GE"}}, {"pk": 76, "model": "embargo.country", "fields": {"country": "GF"}}, {"pk": 91, "model": "embargo.country", "fields": {"country": "GG"}}, {"pk": 83, "model": "embargo.country", "fields": {"country": "GH"}}, {"pk": 84, "model": "embargo.country", "fields": {"country": "GI"}}, {"pk": 86, "model": "embargo.country", "fields": {"country": "GL"}}, {"pk": 80, "model": "embargo.country", "fields": {"country": "GM"}}, {"pk": 92, "model": "embargo.country", "fields": {"country": "GN"}}, {"pk": 88, "model": "embargo.country", "fields": {"country": "GP"}}, {"pk": 67, "model": "embargo.country", "fields": {"country": "GQ"}}, {"pk": 85, "model": "embargo.country", "fields": {"country": "GR"}}, {"pk": 206, "model": "embargo.country", "fields": {"country": "GS"}}, {"pk": 90, "model": "embargo.country", "fields": {"country": "GT"}}, {"pk": 89, "model": "embargo.country", "fields": {"country": "GU"}}, {"pk": 93, "model": "embargo.country", "fields": {"country": "GW"}}, {"pk": 94, "model": "embargo.country", "fields": {"country": "GY"}}, {"pk": 99, "model": "embargo.country", "fields": {"country": "HK"}}, {"pk": 96, "model": "embargo.country", "fields": {"country": "HM"}}, {"pk": 98, "model": "embargo.country", "fields": {"country": "HN"}}, {"pk": 54, "model": "embargo.country", "fields": {"country": "HR"}}, {"pk": 95, "model": "embargo.country", "fields": {"country": "HT"}}, {"pk": 100, "model": "embargo.country", "fields": {"country": "HU"}}, {"pk": 103, "model": "embargo.country", "fields": {"country": "ID"}}, {"pk": 106, "model": "embargo.country", "fields": {"country": "IE"}}, {"pk": 108, "model": "embargo.country", "fields": {"country": "IL"}}, {"pk": 107, "model": "embargo.country", "fields": {"country": "IM"}}, {"pk": 102, "model": "embargo.country", "fields": {"country": "IN"}}, {"pk": 32, "model": "embargo.country", "fields": {"country": "IO"}}, {"pk": 105, "model": "embargo.country", "fields": {"country": "IQ"}}, {"pk": 104, "model": "embargo.country", "fields": {"country": "IR"}}, {"pk": 101, "model": "embargo.country", "fields": {"country": "IS"}}, {"pk": 109, "model": "embargo.country", "fields": {"country": "IT"}}, {"pk": 112, "model": "embargo.country", "fields": {"country": "JE"}}, {"pk": 110, "model": "embargo.country", "fields": {"country": "JM"}}, {"pk": 113, "model": "embargo.country", "fields": {"country": "JO"}}, {"pk": 111, "model": "embargo.country", "fields": {"country": "JP"}}, {"pk": 115, "model": "embargo.country", "fields": {"country": "KE"}}, {"pk": 120, "model": "embargo.country", "fields": {"country": "KG"}}, {"pk": 37, "model": "embargo.country", "fields": {"country": "KH"}}, {"pk": 116, "model": "embargo.country", "fields": {"country": "KI"}}, {"pk": 49, "model": "embargo.country", "fields": {"country": "KM"}}, {"pk": 186, "model": "embargo.country", "fields": {"country": "KN"}}, {"pk": 117, "model": "embargo.country", "fields": {"country": "KP"}}, {"pk": 118, "model": "embargo.country", "fields": {"country": "KR"}}, {"pk": 119, "model": "embargo.country", "fields": {"country": "KW"}}, {"pk": 41, "model": "embargo.country", "fields": {"country": "KY"}}, {"pk": 114, "model": "embargo.country", "fields": {"country": "KZ"}}, {"pk": 121, "model": "embargo.country", "fields": {"country": "LA"}}, {"pk": 123, "model": "embargo.country", "fields": {"country": "LB"}}, {"pk": 187, "model": "embargo.country", "fields": {"country": "LC"}}, {"pk": 127, "model": "embargo.country", "fields": {"country": "LI"}}, {"pk": 209, "model": "embargo.country", "fields": {"country": "LK"}}, {"pk": 125, "model": "embargo.country", "fields": {"country": "LR"}}, {"pk": 124, "model": "embargo.country", "fields": {"country": "LS"}}, {"pk": 128, "model": "embargo.country", "fields": {"country": "LT"}}, {"pk": 129, "model": "embargo.country", "fields": {"country": "LU"}}, {"pk": 122, "model": "embargo.country", "fields": {"country": "LV"}}, {"pk": 126, "model": "embargo.country", "fields": {"country": "LY"}}, {"pk": 150, "model": "embargo.country", "fields": {"country": "MA"}}, {"pk": 146, "model": "embargo.country", "fields": {"country": "MC"}}, {"pk": 145, "model": "embargo.country", "fields": {"country": "MD"}}, {"pk": 148, "model": "embargo.country", "fields": {"country": "ME"}}, {"pk": 188, "model": "embargo.country", "fields": {"country": "MF"}}, {"pk": 132, "model": "embargo.country", "fields": {"country": "MG"}}, {"pk": 138, "model": "embargo.country", "fields": {"country": "MH"}}, {"pk": 131, "model": "embargo.country", "fields": {"country": "MK"}}, {"pk": 136, "model": "embargo.country", "fields": {"country": "ML"}}, {"pk": 152, "model": "embargo.country", "fields": {"country": "MM"}}, {"pk": 147, "model": "embargo.country", "fields": {"country": "MN"}}, {"pk": 130, "model": "embargo.country", "fields": {"country": "MO"}}, {"pk": 164, "model": "embargo.country", "fields": {"country": "MP"}}, {"pk": 139, "model": "embargo.country", "fields": {"country": "MQ"}}, {"pk": 140, "model": "embargo.country", "fields": {"country": "MR"}}, {"pk": 149, "model": "embargo.country", "fields": {"country": "MS"}}, {"pk": 137, "model": "embargo.country", "fields": {"country": "MT"}}, {"pk": 141, "model": "embargo.country", "fields": {"country": "MU"}}, {"pk": 135, "model": "embargo.country", "fields": {"country": "MV"}}, {"pk": 133, "model": "embargo.country", "fields": {"country": "MW"}}, {"pk": 143, "model": "embargo.country", "fields": {"country": "MX"}}, {"pk": 134, "model": "embargo.country", "fields": {"country": "MY"}}, {"pk": 151, "model": "embargo.country", "fields": {"country": "MZ"}}, {"pk": 153, "model": "embargo.country", "fields": {"country": "NA"}}, {"pk": 157, "model": "embargo.country", "fields": {"country": "NC"}}, {"pk": 160, "model": "embargo.country", "fields": {"country": "NE"}}, {"pk": 163, "model": "embargo.country", "fields": {"country": "NF"}}, {"pk": 161, "model": "embargo.country", "fields": {"country": "NG"}}, {"pk": 159, "model": "embargo.country", "fields": {"country": "NI"}}, {"pk": 156, "model": "embargo.country", "fields": {"country": "NL"}}, {"pk": 165, "model": "embargo.country", "fields": {"country": "NO"}}, {"pk": 155, "model": "embargo.country", "fields": {"country": "NP"}}, {"pk": 154, "model": "embargo.country", "fields": {"country": "NR"}}, {"pk": 162, "model": "embargo.country", "fields": {"country": "NU"}}, {"pk": 158, "model": "embargo.country", "fields": {"country": "NZ"}}, {"pk": 166, "model": "embargo.country", "fields": {"country": "OM"}}, {"pk": 170, "model": "embargo.country", "fields": {"country": "PA"}}, {"pk": 173, "model": "embargo.country", "fields": {"country": "PE"}}, {"pk": 77, "model": "embargo.country", "fields": {"country": "PF"}}, {"pk": 171, "model": "embargo.country", "fields": {"country": "PG"}}, {"pk": 174, "model": "embargo.country", "fields": {"country": "PH"}}, {"pk": 167, "model": "embargo.country", "fields": {"country": "PK"}}, {"pk": 176, "model": "embargo.country", "fields": {"country": "PL"}}, {"pk": 189, "model": "embargo.country", "fields": {"country": "PM"}}, {"pk": 175, "model": "embargo.country", "fields": {"country": "PN"}}, {"pk": 178, "model": "embargo.country", "fields": {"country": "PR"}}, {"pk": 169, "model": "embargo.country", "fields": {"country": "PS"}}, {"pk": 177, "model": "embargo.country", "fields": {"country": "PT"}}, {"pk": 168, "model": "embargo.country", "fields": {"country": "PW"}}, {"pk": 172, "model": "embargo.country", "fields": {"country": "PY"}}, {"pk": 179, "model": "embargo.country", "fields": {"country": "QA"}}, {"pk": 183, "model": "embargo.country", "fields": {"country": "RE"}}, {"pk": 180, "model": "embargo.country", "fields": {"country": "RO"}}, {"pk": 196, "model": "embargo.country", "fields": {"country": "RS"}}, {"pk": 181, "model": "embargo.country", "fields": {"country": "RU"}}, {"pk": 182, "model": "embargo.country", "fields": {"country": "RW"}}, {"pk": 194, "model": "embargo.country", "fields": {"country": "SA"}}, {"pk": 203, "model": "embargo.country", "fields": {"country": "SB"}}, {"pk": 197, "model": "embargo.country", "fields": {"country": "SC"}}, {"pk": 210, "model": "embargo.country", "fields": {"country": "SD"}}, {"pk": 214, "model": "embargo.country", "fields": {"country": "SE"}}, {"pk": 199, "model": "embargo.country", "fields": {"country": "SG"}}, {"pk": 185, "model": "embargo.country", "fields": {"country": "SH"}}, {"pk": 202, "model": "embargo.country", "fields": {"country": "SI"}}, {"pk": 212, "model": "embargo.country", "fields": {"country": "SJ"}}, {"pk": 201, "model": "embargo.country", "fields": {"country": "SK"}}, {"pk": 198, "model": "embargo.country", "fields": {"country": "SL"}}, {"pk": 192, "model": "embargo.country", "fields": {"country": "SM"}}, {"pk": 195, "model": "embargo.country", "fields": {"country": "SN"}}, {"pk": 204, "model": "embargo.country", "fields": {"country": "SO"}}, {"pk": 211, "model": "embargo.country", "fields": {"country": "SR"}}, {"pk": 207, "model": "embargo.country", "fields": {"country": "SS"}}, {"pk": 193, "model": "embargo.country", "fields": {"country": "ST"}}, {"pk": 66, "model": "embargo.country", "fields": {"country": "SV"}}, {"pk": 200, "model": "embargo.country", "fields": {"country": "SX"}}, {"pk": 216, "model": "embargo.country", "fields": {"country": "SY"}}, {"pk": 213, "model": "embargo.country", "fields": {"country": "SZ"}}, {"pk": 229, "model": "embargo.country", "fields": {"country": "TC"}}, {"pk": 43, "model": "embargo.country", "fields": {"country": "TD"}}, {"pk": 78, "model": "embargo.country", "fields": {"country": "TF"}}, {"pk": 222, "model": "embargo.country", "fields": {"country": "TG"}}, {"pk": 220, "model": "embargo.country", "fields": {"country": "TH"}}, {"pk": 218, "model": "embargo.country", "fields": {"country": "TJ"}}, {"pk": 223, "model": "embargo.country", "fields": {"country": "TK"}}, {"pk": 221, "model": "embargo.country", "fields": {"country": "TL"}}, {"pk": 228, "model": "embargo.country", "fields": {"country": "TM"}}, {"pk": 226, "model": "embargo.country", "fields": {"country": "TN"}}, {"pk": 224, "model": "embargo.country", "fields": {"country": "TO"}}, {"pk": 227, "model": "embargo.country", "fields": {"country": "TR"}}, {"pk": 225, "model": "embargo.country", "fields": {"country": "TT"}}, {"pk": 230, "model": "embargo.country", "fields": {"country": "TV"}}, {"pk": 217, "model": "embargo.country", "fields": {"country": "TW"}}, {"pk": 219, "model": "embargo.country", "fields": {"country": "TZ"}}, {"pk": 232, "model": "embargo.country", "fields": {"country": "UA"}}, {"pk": 231, "model": "embargo.country", "fields": {"country": "UG"}}, {"pk": 236, "model": "embargo.country", "fields": {"country": "UM"}}, {"pk": 235, "model": "embargo.country", "fields": {"country": "US"}}, {"pk": 237, "model": "embargo.country", "fields": {"country": "UY"}}, {"pk": 238, "model": "embargo.country", "fields": {"country": "UZ"}}, {"pk": 97, "model": "embargo.country", "fields": {"country": "VA"}}, {"pk": 190, "model": "embargo.country", "fields": {"country": "VC"}}, {"pk": 240, "model": "embargo.country", "fields": {"country": "VE"}}, {"pk": 242, "model": "embargo.country", "fields": {"country": "VG"}}, {"pk": 243, "model": "embargo.country", "fields": {"country": "VI"}}, {"pk": 241, "model": "embargo.country", "fields": {"country": "VN"}}, {"pk": 239, "model": "embargo.country", "fields": {"country": "VU"}}, {"pk": 244, "model": "embargo.country", "fields": {"country": "WF"}}, {"pk": 191, "model": "embargo.country", "fields": {"country": "WS"}}, {"pk": 246, "model": "embargo.country", "fields": {"country": "YE"}}, {"pk": 142, "model": "embargo.country", "fields": {"country": "YT"}}, {"pk": 205, "model": "embargo.country", "fields": {"country": "ZA"}}, {"pk": 247, "model": "embargo.country", "fields": {"country": "ZM"}}, {"pk": 248, "model": "embargo.country", "fields": {"country": "ZW"}}, {"pk": 1, "model": "edxval.profile", "fields": {"profile_name": "desktop_mp4"}}, {"pk": 2, "model": "edxval.profile", "fields": {"profile_name": "desktop_webm"}}, {"pk": 3, "model": "edxval.profile", "fields": {"profile_name": "mobile_high"}}, {"pk": 4, "model": "edxval.profile", "fields": {"profile_name": "mobile_low"}}, {"pk": 5, "model": "edxval.profile", "fields": {"profile_name": "youtube"}}, {"pk": 1, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"fulfills\"", "modified": "2015-03-31T06:26:10Z", "name": "fulfills", "created": "2015-03-31T06:26:10Z"}}, {"pk": 2, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"requires\"", "modified": "2015-03-31T06:26:10Z", "name": "requires", "created": "2015-03-31T06:26:10Z"}}, {"pk": 61, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 21}}, {"pk": 62, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 21}}, {"pk": 63, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 21}}, {"pk": 454, "model": "auth.permission", "fields": {"codename": "add_aiclassifier", "name": "Can add ai classifier", "content_type": 151}}, {"pk": 455, "model": "auth.permission", "fields": {"codename": "change_aiclassifier", "name": "Can change ai classifier", "content_type": 151}}, {"pk": 456, "model": "auth.permission", "fields": {"codename": "delete_aiclassifier", "name": "Can delete ai classifier", "content_type": 151}}, {"pk": 451, "model": "auth.permission", "fields": {"codename": "add_aiclassifierset", "name": "Can add ai classifier set", "content_type": 150}}, {"pk": 452, "model": "auth.permission", "fields": {"codename": "change_aiclassifierset", "name": "Can change ai classifier set", "content_type": 150}}, {"pk": 453, "model": "auth.permission", "fields": {"codename": "delete_aiclassifierset", "name": "Can delete ai classifier set", "content_type": 150}}, {"pk": 460, "model": "auth.permission", "fields": {"codename": "add_aigradingworkflow", "name": "Can add ai grading workflow", "content_type": 153}}, {"pk": 461, "model": "auth.permission", "fields": {"codename": "change_aigradingworkflow", "name": "Can change ai grading workflow", "content_type": 153}}, {"pk": 462, "model": "auth.permission", "fields": {"codename": "delete_aigradingworkflow", "name": "Can delete ai grading workflow", "content_type": 153}}, {"pk": 457, "model": "auth.permission", "fields": {"codename": "add_aitrainingworkflow", "name": "Can add ai training workflow", "content_type": 152}}, {"pk": 458, "model": "auth.permission", "fields": {"codename": "change_aitrainingworkflow", "name": "Can change ai training workflow", "content_type": 152}}, {"pk": 459, "model": "auth.permission", "fields": {"codename": "delete_aitrainingworkflow", "name": "Can delete ai training workflow", "content_type": 152}}, {"pk": 424, "model": "auth.permission", "fields": {"codename": "add_assessment", "name": "Can add assessment", "content_type": 141}}, {"pk": 425, "model": "auth.permission", "fields": {"codename": "change_assessment", "name": "Can change assessment", "content_type": 141}}, {"pk": 426, "model": "auth.permission", "fields": {"codename": "delete_assessment", "name": "Can delete assessment", "content_type": 141}}, {"pk": 433, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedback", "name": "Can add assessment feedback", "content_type": 144}}, {"pk": 434, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedback", "name": "Can change assessment feedback", "content_type": 144}}, {"pk": 435, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedback", "name": "Can delete assessment feedback", "content_type": 144}}, {"pk": 430, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedbackoption", "name": "Can add assessment feedback option", "content_type": 143}}, {"pk": 431, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedbackoption", "name": "Can change assessment feedback option", "content_type": 143}}, {"pk": 432, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedbackoption", "name": "Can delete assessment feedback option", "content_type": 143}}, {"pk": 427, "model": "auth.permission", "fields": {"codename": "add_assessmentpart", "name": "Can add assessment part", "content_type": 142}}, {"pk": 428, "model": "auth.permission", "fields": {"codename": "change_assessmentpart", "name": "Can change assessment part", "content_type": 142}}, {"pk": 429, "model": "auth.permission", "fields": {"codename": "delete_assessmentpart", "name": "Can delete assessment part", "content_type": 142}}, {"pk": 418, "model": "auth.permission", "fields": {"codename": "add_criterion", "name": "Can add criterion", "content_type": 139}}, {"pk": 419, "model": "auth.permission", "fields": {"codename": "change_criterion", "name": "Can change criterion", "content_type": 139}}, {"pk": 420, "model": "auth.permission", "fields": {"codename": "delete_criterion", "name": "Can delete criterion", "content_type": 139}}, {"pk": 421, "model": "auth.permission", "fields": {"codename": "add_criterionoption", "name": "Can add criterion option", "content_type": 140}}, {"pk": 422, "model": "auth.permission", "fields": {"codename": "change_criterionoption", "name": "Can change criterion option", "content_type": 140}}, {"pk": 423, "model": "auth.permission", "fields": {"codename": "delete_criterionoption", "name": "Can delete criterion option", "content_type": 140}}, {"pk": 436, "model": "auth.permission", "fields": {"codename": "add_peerworkflow", "name": "Can add peer workflow", "content_type": 145}}, {"pk": 437, "model": "auth.permission", "fields": {"codename": "change_peerworkflow", "name": "Can change peer workflow", "content_type": 145}}, {"pk": 438, "model": "auth.permission", "fields": {"codename": "delete_peerworkflow", "name": "Can delete peer workflow", "content_type": 145}}, {"pk": 439, "model": "auth.permission", "fields": {"codename": "add_peerworkflowitem", "name": "Can add peer workflow item", "content_type": 146}}, {"pk": 440, "model": "auth.permission", "fields": {"codename": "change_peerworkflowitem", "name": "Can change peer workflow item", "content_type": 146}}, {"pk": 441, "model": "auth.permission", "fields": {"codename": "delete_peerworkflowitem", "name": "Can delete peer workflow item", "content_type": 146}}, {"pk": 415, "model": "auth.permission", "fields": {"codename": "add_rubric", "name": "Can add rubric", "content_type": 138}}, {"pk": 416, "model": "auth.permission", "fields": {"codename": "change_rubric", "name": "Can change rubric", "content_type": 138}}, {"pk": 417, "model": "auth.permission", "fields": {"codename": "delete_rubric", "name": "Can delete rubric", "content_type": 138}}, {"pk": 445, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflow", "name": "Can add student training workflow", "content_type": 148}}, {"pk": 446, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflow", "name": "Can change student training workflow", "content_type": 148}}, {"pk": 447, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflow", "name": "Can delete student training workflow", "content_type": 148}}, {"pk": 448, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflowitem", "name": "Can add student training workflow item", "content_type": 149}}, {"pk": 449, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflowitem", "name": "Can change student training workflow item", "content_type": 149}}, {"pk": 450, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflowitem", "name": "Can delete student training workflow item", "content_type": 149}}, {"pk": 442, "model": "auth.permission", "fields": {"codename": "add_trainingexample", "name": "Can add training example", "content_type": 147}}, {"pk": 443, "model": "auth.permission", "fields": {"codename": "change_trainingexample", "name": "Can change training example", "content_type": 147}}, {"pk": 444, "model": "auth.permission", "fields": {"codename": "delete_trainingexample", "name": "Can delete training example", "content_type": 147}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 208, "model": "auth.permission", "fields": {"codename": "add_brandinginfoconfig", "name": "Can add branding info config", "content_type": 70}}, {"pk": 209, "model": "auth.permission", "fields": {"codename": "change_brandinginfoconfig", "name": "Can change branding info config", "content_type": 70}}, {"pk": 210, "model": "auth.permission", "fields": {"codename": "delete_brandinginfoconfig", "name": "Can delete branding info config", "content_type": 70}}, {"pk": 205, "model": "auth.permission", "fields": {"codename": "add_courseauthorization", "name": "Can add course authorization", "content_type": 69}}, {"pk": 206, "model": "auth.permission", "fields": {"codename": "change_courseauthorization", "name": "Can change course authorization", "content_type": 69}}, {"pk": 207, "model": "auth.permission", "fields": {"codename": "delete_courseauthorization", "name": "Can delete course authorization", "content_type": 69}}, {"pk": 196, "model": "auth.permission", "fields": {"codename": "add_courseemail", "name": "Can add course email", "content_type": 66}}, {"pk": 197, "model": "auth.permission", "fields": {"codename": "change_courseemail", "name": "Can change course email", "content_type": 66}}, {"pk": 198, "model": "auth.permission", "fields": {"codename": "delete_courseemail", "name": "Can delete course email", "content_type": 66}}, {"pk": 202, "model": "auth.permission", "fields": {"codename": "add_courseemailtemplate", "name": "Can add course email template", "content_type": 68}}, {"pk": 203, "model": "auth.permission", "fields": {"codename": "change_courseemailtemplate", "name": "Can change course email template", "content_type": 68}}, {"pk": 204, "model": "auth.permission", "fields": {"codename": "delete_courseemailtemplate", "name": "Can delete course email template", "content_type": 68}}, {"pk": 199, "model": "auth.permission", "fields": {"codename": "add_optout", "name": "Can add optout", "content_type": 67}}, {"pk": 200, "model": "auth.permission", "fields": {"codename": "change_optout", "name": "Can change optout", "content_type": 67}}, {"pk": 201, "model": "auth.permission", "fields": {"codename": "delete_optout", "name": "Can delete optout", "content_type": 67}}, {"pk": 169, "model": "auth.permission", "fields": {"codename": "add_certificategenerationconfiguration", "name": "Can add certificate generation configuration", "content_type": 57}}, {"pk": 170, "model": "auth.permission", "fields": {"codename": "change_certificategenerationconfiguration", "name": "Can change certificate generation configuration", "content_type": 57}}, {"pk": 171, "model": "auth.permission", "fields": {"codename": "delete_certificategenerationconfiguration", "name": "Can delete certificate generation configuration", "content_type": 57}}, {"pk": 166, "model": "auth.permission", "fields": {"codename": "add_certificategenerationcoursesetting", "name": "Can add certificate generation course setting", "content_type": 56}}, {"pk": 167, "model": "auth.permission", "fields": {"codename": "change_certificategenerationcoursesetting", "name": "Can change certificate generation course setting", "content_type": 56}}, {"pk": 168, "model": "auth.permission", "fields": {"codename": "delete_certificategenerationcoursesetting", "name": "Can delete certificate generation course setting", "content_type": 56}}, {"pk": 172, "model": "auth.permission", "fields": {"codename": "add_certificatehtmlviewconfiguration", "name": "Can add certificate html view configuration", "content_type": 58}}, {"pk": 173, "model": "auth.permission", "fields": {"codename": "change_certificatehtmlviewconfiguration", "name": "Can change certificate html view configuration", "content_type": 58}}, {"pk": 174, "model": "auth.permission", "fields": {"codename": "delete_certificatehtmlviewconfiguration", "name": "Can delete certificate html view configuration", "content_type": 58}}, {"pk": 154, "model": "auth.permission", "fields": {"codename": "add_certificatewhitelist", "name": "Can add certificate whitelist", "content_type": 52}}, {"pk": 155, "model": "auth.permission", "fields": {"codename": "change_certificatewhitelist", "name": "Can change certificate whitelist", "content_type": 52}}, {"pk": 156, "model": "auth.permission", "fields": {"codename": "delete_certificatewhitelist", "name": "Can delete certificate whitelist", "content_type": 52}}, {"pk": 163, "model": "auth.permission", "fields": {"codename": "add_examplecertificate", "name": "Can add example certificate", "content_type": 55}}, {"pk": 164, "model": "auth.permission", "fields": {"codename": "change_examplecertificate", "name": "Can change example certificate", "content_type": 55}}, {"pk": 165, "model": "auth.permission", "fields": {"codename": "delete_examplecertificate", "name": "Can delete example certificate", "content_type": 55}}, {"pk": 160, "model": "auth.permission", "fields": {"codename": "add_examplecertificateset", "name": "Can add example certificate set", "content_type": 54}}, {"pk": 161, "model": "auth.permission", "fields": {"codename": "change_examplecertificateset", "name": "Can change example certificate set", "content_type": 54}}, {"pk": 162, "model": "auth.permission", "fields": {"codename": "delete_examplecertificateset", "name": "Can delete example certificate set", "content_type": 54}}, {"pk": 157, "model": "auth.permission", "fields": {"codename": "add_generatedcertificate", "name": "Can add generated certificate", "content_type": 53}}, {"pk": 158, "model": "auth.permission", "fields": {"codename": "change_generatedcertificate", "name": "Can change generated certificate", "content_type": 53}}, {"pk": 159, "model": "auth.permission", "fields": {"codename": "delete_generatedcertificate", "name": "Can delete generated certificate", "content_type": 53}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_servercircuit", "name": "Can add server circuit", "content_type": 16}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_servercircuit", "name": "Can change server circuit", "content_type": 16}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_servercircuit", "name": "Can delete server circuit", "content_type": 16}}, {"pk": 502, "model": "auth.permission", "fields": {"codename": "add_videouploadconfig", "name": "Can add video upload config", "content_type": 167}}, {"pk": 503, "model": "auth.permission", "fields": {"codename": "change_videouploadconfig", "name": "Can change video upload config", "content_type": 167}}, {"pk": 504, "model": "auth.permission", "fields": {"codename": "delete_videouploadconfig", "name": "Can delete video upload config", "content_type": 167}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 64, "model": "auth.permission", "fields": {"codename": "add_corsmodel", "name": "Can add cors model", "content_type": 22}}, {"pk": 65, "model": "auth.permission", "fields": {"codename": "change_corsmodel", "name": "Can change cors model", "content_type": 22}}, {"pk": 66, "model": "auth.permission", "fields": {"codename": "delete_corsmodel", "name": "Can delete cors model", "content_type": 22}}, {"pk": 94, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgrade", "name": "Can add offline computed grade", "content_type": 32}}, {"pk": 95, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgrade", "name": "Can change offline computed grade", "content_type": 32}}, {"pk": 96, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgrade", "name": "Can delete offline computed grade", "content_type": 32}}, {"pk": 97, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgradelog", "name": "Can add offline computed grade log", "content_type": 33}}, {"pk": 98, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgradelog", "name": "Can change offline computed grade log", "content_type": 33}}, {"pk": 99, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgradelog", "name": "Can delete offline computed grade log", "content_type": 33}}, {"pk": 79, "model": "auth.permission", "fields": {"codename": "add_studentmodule", "name": "Can add student module", "content_type": 27}}, {"pk": 80, "model": "auth.permission", "fields": {"codename": "change_studentmodule", "name": "Can change student module", "content_type": 27}}, {"pk": 81, "model": "auth.permission", "fields": {"codename": "delete_studentmodule", "name": "Can delete student module", "content_type": 27}}, {"pk": 82, "model": "auth.permission", "fields": {"codename": "add_studentmodulehistory", "name": "Can add student module history", "content_type": 28}}, {"pk": 83, "model": "auth.permission", "fields": {"codename": "change_studentmodulehistory", "name": "Can change student module history", "content_type": 28}}, {"pk": 84, "model": "auth.permission", "fields": {"codename": "delete_studentmodulehistory", "name": "Can delete student module history", "content_type": 28}}, {"pk": 91, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentinfofield", "name": "Can add x module student info field", "content_type": 31}}, {"pk": 92, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentinfofield", "name": "Can change x module student info field", "content_type": 31}}, {"pk": 93, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentinfofield", "name": "Can delete x module student info field", "content_type": 31}}, {"pk": 88, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentprefsfield", "name": "Can add x module student prefs field", "content_type": 30}}, {"pk": 89, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentprefsfield", "name": "Can change x module student prefs field", "content_type": 30}}, {"pk": 90, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentprefsfield", "name": "Can delete x module student prefs field", "content_type": 30}}, {"pk": 85, "model": "auth.permission", "fields": {"codename": "add_xmoduleuserstatesummaryfield", "name": "Can add x module user state summary field", "content_type": 29}}, {"pk": 86, "model": "auth.permission", "fields": {"codename": "change_xmoduleuserstatesummaryfield", "name": "Can change x module user state summary field", "content_type": 29}}, {"pk": 87, "model": "auth.permission", "fields": {"codename": "delete_xmoduleuserstatesummaryfield", "name": "Can delete x module user state summary field", "content_type": 29}}, {"pk": 385, "model": "auth.permission", "fields": {"codename": "add_coursererunstate", "name": "Can add course rerun state", "content_type": 128}}, {"pk": 386, "model": "auth.permission", "fields": {"codename": "change_coursererunstate", "name": "Can change course rerun state", "content_type": 128}}, {"pk": 387, "model": "auth.permission", "fields": {"codename": "delete_coursererunstate", "name": "Can delete course rerun state", "content_type": 128}}, {"pk": 505, "model": "auth.permission", "fields": {"codename": "add_coursecreator", "name": "Can add course creator", "content_type": 168}}, {"pk": 506, "model": "auth.permission", "fields": {"codename": "change_coursecreator", "name": "Can change course creator", "content_type": 168}}, {"pk": 507, "model": "auth.permission", "fields": {"codename": "delete_coursecreator", "name": "Can delete course creator", "content_type": 168}}, {"pk": 193, "model": "auth.permission", "fields": {"codename": "add_coursecohort", "name": "Can add course cohort", "content_type": 65}}, {"pk": 194, "model": "auth.permission", "fields": {"codename": "change_coursecohort", "name": "Can change course cohort", "content_type": 65}}, {"pk": 195, "model": "auth.permission", "fields": {"codename": "delete_coursecohort", "name": "Can delete course cohort", "content_type": 65}}, {"pk": 190, "model": "auth.permission", "fields": {"codename": "add_coursecohortssettings", "name": "Can add course cohorts settings", "content_type": 64}}, {"pk": 191, "model": "auth.permission", "fields": {"codename": "change_coursecohortssettings", "name": "Can change course cohorts settings", "content_type": 64}}, {"pk": 192, "model": "auth.permission", "fields": {"codename": "delete_coursecohortssettings", "name": "Can delete course cohorts settings", "content_type": 64}}, {"pk": 184, "model": "auth.permission", "fields": {"codename": "add_courseusergroup", "name": "Can add course user group", "content_type": 62}}, {"pk": 185, "model": "auth.permission", "fields": {"codename": "change_courseusergroup", "name": "Can change course user group", "content_type": 62}}, {"pk": 186, "model": "auth.permission", "fields": {"codename": "delete_courseusergroup", "name": "Can delete course user group", "content_type": 62}}, {"pk": 187, "model": "auth.permission", "fields": {"codename": "add_courseusergrouppartitiongroup", "name": "Can add course user group partition group", "content_type": 63}}, {"pk": 188, "model": "auth.permission", "fields": {"codename": "change_courseusergrouppartitiongroup", "name": "Can change course user group partition group", "content_type": 63}}, {"pk": 189, "model": "auth.permission", "fields": {"codename": "delete_courseusergrouppartitiongroup", "name": "Can delete course user group partition group", "content_type": 63}}, {"pk": 349, "model": "auth.permission", "fields": {"codename": "add_coursemode", "name": "Can add course mode", "content_type": 116}}, {"pk": 350, "model": "auth.permission", "fields": {"codename": "change_coursemode", "name": "Can change course mode", "content_type": 116}}, {"pk": 351, "model": "auth.permission", "fields": {"codename": "delete_coursemode", "name": "Can delete course mode", "content_type": 116}}, {"pk": 352, "model": "auth.permission", "fields": {"codename": "add_coursemodesarchive", "name": "Can add course modes archive", "content_type": 117}}, {"pk": 353, "model": "auth.permission", "fields": {"codename": "change_coursemodesarchive", "name": "Can change course modes archive", "content_type": 117}}, {"pk": 354, "model": "auth.permission", "fields": {"codename": "delete_coursemodesarchive", "name": "Can delete course modes archive", "content_type": 117}}, {"pk": 400, "model": "auth.permission", "fields": {"codename": "add_coursestructure", "name": "Can add course structure", "content_type": 133}}, {"pk": 401, "model": "auth.permission", "fields": {"codename": "change_coursestructure", "name": "Can change course structure", "content_type": 133}}, {"pk": 402, "model": "auth.permission", "fields": {"codename": "delete_coursestructure", "name": "Can delete course structure", "content_type": 133}}, {"pk": 358, "model": "auth.permission", "fields": {"codename": "add_darklangconfig", "name": "Can add dark lang config", "content_type": 119}}, {"pk": 359, "model": "auth.permission", "fields": {"codename": "change_darklangconfig", "name": "Can change dark lang config", "content_type": 119}}, {"pk": 360, "model": "auth.permission", "fields": {"codename": "delete_darklangconfig", "name": "Can delete dark lang config", "content_type": 119}}, {"pk": 73, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 25}}, {"pk": 74, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 25}}, {"pk": 75, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 25}}, {"pk": 76, "model": "auth.permission", "fields": {"codename": "add_code", "name": "Can add code", "content_type": 26}}, {"pk": 77, "model": "auth.permission", "fields": {"codename": "change_code", "name": "Can change code", "content_type": 26}}, {"pk": 78, "model": "auth.permission", "fields": {"codename": "delete_code", "name": "Can delete code", "content_type": 26}}, {"pk": 70, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 24}}, {"pk": 71, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 24}}, {"pk": 72, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 24}}, {"pk": 67, "model": "auth.permission", "fields": {"codename": "add_usersocialauth", "name": "Can add user social auth", "content_type": 23}}, {"pk": 68, "model": "auth.permission", "fields": {"codename": "change_usersocialauth", "name": "Can change user social auth", "content_type": 23}}, {"pk": 69, "model": "auth.permission", "fields": {"codename": "delete_usersocialauth", "name": "Can delete user social auth", "content_type": 23}}, {"pk": 271, "model": "auth.permission", "fields": {"codename": "add_notification", "name": "Can add notification", "content_type": 90}}, {"pk": 272, "model": "auth.permission", "fields": {"codename": "change_notification", "name": "Can change notification", "content_type": 90}}, {"pk": 273, "model": "auth.permission", "fields": {"codename": "delete_notification", "name": "Can delete notification", "content_type": 90}}, {"pk": 262, "model": "auth.permission", "fields": {"codename": "add_notificationtype", "name": "Can add type", "content_type": 87}}, {"pk": 263, "model": "auth.permission", "fields": {"codename": "change_notificationtype", "name": "Can change type", "content_type": 87}}, {"pk": 264, "model": "auth.permission", "fields": {"codename": "delete_notificationtype", "name": "Can delete type", "content_type": 87}}, {"pk": 265, "model": "auth.permission", "fields": {"codename": "add_settings", "name": "Can add settings", "content_type": 88}}, {"pk": 266, "model": "auth.permission", "fields": {"codename": "change_settings", "name": "Can change settings", "content_type": 88}}, {"pk": 267, "model": "auth.permission", "fields": {"codename": "delete_settings", "name": "Can delete settings", "content_type": 88}}, {"pk": 268, "model": "auth.permission", "fields": {"codename": "add_subscription", "name": "Can add subscription", "content_type": 89}}, {"pk": 269, "model": "auth.permission", "fields": {"codename": "change_subscription", "name": "Can change subscription", "content_type": 89}}, {"pk": 270, "model": "auth.permission", "fields": {"codename": "delete_subscription", "name": "Can delete subscription", "content_type": 89}}, {"pk": 55, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 19}}, {"pk": 56, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 19}}, {"pk": 57, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 19}}, {"pk": 52, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 18}}, {"pk": 53, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 18}}, {"pk": 54, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 18}}, {"pk": 58, "model": "auth.permission", "fields": {"codename": "add_useropenid", "name": "Can add user open id", "content_type": 20}}, {"pk": 59, "model": "auth.permission", "fields": {"codename": "change_useropenid", "name": "Can change user open id", "content_type": 20}}, {"pk": 60, "model": "auth.permission", "fields": {"codename": "delete_useropenid", "name": "Can delete user open id", "content_type": 20}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_crontabschedule", "name": "Can add crontab", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_crontabschedule", "name": "Can change crontab", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_crontabschedule", "name": "Can delete crontab", "content_type": 10}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_intervalschedule", "name": "Can add interval", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_intervalschedule", "name": "Can change interval", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_intervalschedule", "name": "Can delete interval", "content_type": 9}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_periodictask", "name": "Can add periodic task", "content_type": 12}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_periodictask", "name": "Can change periodic task", "content_type": 12}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_periodictask", "name": "Can delete periodic task", "content_type": 12}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_periodictasks", "name": "Can add periodic tasks", "content_type": 11}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_periodictasks", "name": "Can change periodic tasks", "content_type": 11}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_periodictasks", "name": "Can delete periodic tasks", "content_type": 11}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_taskmeta", "name": "Can add task state", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_taskmeta", "name": "Can change task state", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_taskmeta", "name": "Can delete task state", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_tasksetmeta", "name": "Can add saved group result", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_tasksetmeta", "name": "Can change saved group result", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_tasksetmeta", "name": "Can delete saved group result", "content_type": 8}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_taskstate", "name": "Can add task", "content_type": 14}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_taskstate", "name": "Can change task", "content_type": 14}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_taskstate", "name": "Can delete task", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_workerstate", "name": "Can add worker", "content_type": 13}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_workerstate", "name": "Can change worker", "content_type": 13}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_workerstate", "name": "Can delete worker", "content_type": 13}}, {"pk": 478, "model": "auth.permission", "fields": {"codename": "add_coursevideo", "name": "Can add course video", "content_type": 159}}, {"pk": 479, "model": "auth.permission", "fields": {"codename": "change_coursevideo", "name": "Can change course video", "content_type": 159}}, {"pk": 480, "model": "auth.permission", "fields": {"codename": "delete_coursevideo", "name": "Can delete course video", "content_type": 159}}, {"pk": 481, "model": "auth.permission", "fields": {"codename": "add_encodedvideo", "name": "Can add encoded video", "content_type": 160}}, {"pk": 482, "model": "auth.permission", "fields": {"codename": "change_encodedvideo", "name": "Can change encoded video", "content_type": 160}}, {"pk": 483, "model": "auth.permission", "fields": {"codename": "delete_encodedvideo", "name": "Can delete encoded video", "content_type": 160}}, {"pk": 472, "model": "auth.permission", "fields": {"codename": "add_profile", "name": "Can add profile", "content_type": 157}}, {"pk": 473, "model": "auth.permission", "fields": {"codename": "change_profile", "name": "Can change profile", "content_type": 157}}, {"pk": 474, "model": "auth.permission", "fields": {"codename": "delete_profile", "name": "Can delete profile", "content_type": 157}}, {"pk": 484, "model": "auth.permission", "fields": {"codename": "add_subtitle", "name": "Can add subtitle", "content_type": 161}}, {"pk": 485, "model": "auth.permission", "fields": {"codename": "change_subtitle", "name": "Can change subtitle", "content_type": 161}}, {"pk": 486, "model": "auth.permission", "fields": {"codename": "delete_subtitle", "name": "Can delete subtitle", "content_type": 161}}, {"pk": 475, "model": "auth.permission", "fields": {"codename": "add_video", "name": "Can add video", "content_type": 158}}, {"pk": 476, "model": "auth.permission", "fields": {"codename": "change_video", "name": "Can change video", "content_type": 158}}, {"pk": 477, "model": "auth.permission", "fields": {"codename": "delete_video", "name": "Can delete video", "content_type": 158}}, {"pk": 373, "model": "auth.permission", "fields": {"codename": "add_country", "name": "Can add country", "content_type": 124}}, {"pk": 374, "model": "auth.permission", "fields": {"codename": "change_country", "name": "Can change country", "content_type": 124}}, {"pk": 375, "model": "auth.permission", "fields": {"codename": "delete_country", "name": "Can delete country", "content_type": 124}}, {"pk": 376, "model": "auth.permission", "fields": {"codename": "add_countryaccessrule", "name": "Can add country access rule", "content_type": 125}}, {"pk": 377, "model": "auth.permission", "fields": {"codename": "change_countryaccessrule", "name": "Can change country access rule", "content_type": 125}}, {"pk": 378, "model": "auth.permission", "fields": {"codename": "delete_countryaccessrule", "name": "Can delete country access rule", "content_type": 125}}, {"pk": 379, "model": "auth.permission", "fields": {"codename": "add_courseaccessrulehistory", "name": "Can add course access rule history", "content_type": 126}}, {"pk": 380, "model": "auth.permission", "fields": {"codename": "change_courseaccessrulehistory", "name": "Can change course access rule history", "content_type": 126}}, {"pk": 381, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrulehistory", "name": "Can delete course access rule history", "content_type": 126}}, {"pk": 364, "model": "auth.permission", "fields": {"codename": "add_embargoedcourse", "name": "Can add embargoed course", "content_type": 121}}, {"pk": 365, "model": "auth.permission", "fields": {"codename": "change_embargoedcourse", "name": "Can change embargoed course", "content_type": 121}}, {"pk": 366, "model": "auth.permission", "fields": {"codename": "delete_embargoedcourse", "name": "Can delete embargoed course", "content_type": 121}}, {"pk": 367, "model": "auth.permission", "fields": {"codename": "add_embargoedstate", "name": "Can add embargoed state", "content_type": 122}}, {"pk": 368, "model": "auth.permission", "fields": {"codename": "change_embargoedstate", "name": "Can change embargoed state", "content_type": 122}}, {"pk": 369, "model": "auth.permission", "fields": {"codename": "delete_embargoedstate", "name": "Can delete embargoed state", "content_type": 122}}, {"pk": 382, "model": "auth.permission", "fields": {"codename": "add_ipfilter", "name": "Can add ip filter", "content_type": 127}}, {"pk": 383, "model": "auth.permission", "fields": {"codename": "change_ipfilter", "name": "Can change ip filter", "content_type": 127}}, {"pk": 384, "model": "auth.permission", "fields": {"codename": "delete_ipfilter", "name": "Can delete ip filter", "content_type": 127}}, {"pk": 370, "model": "auth.permission", "fields": {"codename": "add_restrictedcourse", "name": "Can add restricted course", "content_type": 123}}, {"pk": 371, "model": "auth.permission", "fields": {"codename": "change_restrictedcourse", "name": "Can change restricted course", "content_type": 123}}, {"pk": 372, "model": "auth.permission", "fields": {"codename": "delete_restrictedcourse", "name": "Can delete restricted course", "content_type": 123}}, {"pk": 211, "model": "auth.permission", "fields": {"codename": "add_externalauthmap", "name": "Can add external auth map", "content_type": 71}}, {"pk": 212, "model": "auth.permission", "fields": {"codename": "change_externalauthmap", "name": "Can change external auth map", "content_type": 71}}, {"pk": 213, "model": "auth.permission", "fields": {"codename": "delete_externalauthmap", "name": "Can delete external auth map", "content_type": 71}}, {"pk": 277, "model": "auth.permission", "fields": {"codename": "add_puzzlecomplete", "name": "Can add puzzle complete", "content_type": 92}}, {"pk": 278, "model": "auth.permission", "fields": {"codename": "change_puzzlecomplete", "name": "Can change puzzle complete", "content_type": 92}}, {"pk": 279, "model": "auth.permission", "fields": {"codename": "delete_puzzlecomplete", "name": "Can delete puzzle complete", "content_type": 92}}, {"pk": 274, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 91}}, {"pk": 275, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 91}}, {"pk": 276, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 91}}, {"pk": 175, "model": "auth.permission", "fields": {"codename": "add_instructortask", "name": "Can add instructor task", "content_type": 59}}, {"pk": 176, "model": "auth.permission", "fields": {"codename": "change_instructortask", "name": "Can change instructor task", "content_type": 59}}, {"pk": 177, "model": "auth.permission", "fields": {"codename": "delete_instructortask", "name": "Can delete instructor task", "content_type": 59}}, {"pk": 178, "model": "auth.permission", "fields": {"codename": "add_coursesoftware", "name": "Can add course software", "content_type": 60}}, {"pk": 179, "model": "auth.permission", "fields": {"codename": "change_coursesoftware", "name": "Can change course software", "content_type": 60}}, {"pk": 180, "model": "auth.permission", "fields": {"codename": "delete_coursesoftware", "name": "Can delete course software", "content_type": 60}}, {"pk": 181, "model": "auth.permission", "fields": {"codename": "add_userlicense", "name": "Can add user license", "content_type": 61}}, {"pk": 182, "model": "auth.permission", "fields": {"codename": "change_userlicense", "name": "Can change user license", "content_type": 61}}, {"pk": 183, "model": "auth.permission", "fields": {"codename": "delete_userlicense", "name": "Can delete user license", "content_type": 61}}, {"pk": 397, "model": "auth.permission", "fields": {"codename": "add_xblockasidesconfig", "name": "Can add x block asides config", "content_type": 132}}, {"pk": 398, "model": "auth.permission", "fields": {"codename": "change_xblockasidesconfig", "name": "Can change x block asides config", "content_type": 132}}, {"pk": 399, "model": "auth.permission", "fields": {"codename": "delete_xblockasidesconfig", "name": "Can delete x block asides config", "content_type": 132}}, {"pk": 496, "model": "auth.permission", "fields": {"codename": "add_coursecontentmilestone", "name": "Can add course content milestone", "content_type": 165}}, {"pk": 497, "model": "auth.permission", "fields": {"codename": "change_coursecontentmilestone", "name": "Can change course content milestone", "content_type": 165}}, {"pk": 498, "model": "auth.permission", "fields": {"codename": "delete_coursecontentmilestone", "name": "Can delete course content milestone", "content_type": 165}}, {"pk": 493, "model": "auth.permission", "fields": {"codename": "add_coursemilestone", "name": "Can add course milestone", "content_type": 164}}, {"pk": 494, "model": "auth.permission", "fields": {"codename": "change_coursemilestone", "name": "Can change course milestone", "content_type": 164}}, {"pk": 495, "model": "auth.permission", "fields": {"codename": "delete_coursemilestone", "name": "Can delete course milestone", "content_type": 164}}, {"pk": 487, "model": "auth.permission", "fields": {"codename": "add_milestone", "name": "Can add milestone", "content_type": 162}}, {"pk": 488, "model": "auth.permission", "fields": {"codename": "change_milestone", "name": "Can change milestone", "content_type": 162}}, {"pk": 489, "model": "auth.permission", "fields": {"codename": "delete_milestone", "name": "Can delete milestone", "content_type": 162}}, {"pk": 490, "model": "auth.permission", "fields": {"codename": "add_milestonerelationshiptype", "name": "Can add milestone relationship type", "content_type": 163}}, {"pk": 491, "model": "auth.permission", "fields": {"codename": "change_milestonerelationshiptype", "name": "Can change milestone relationship type", "content_type": 163}}, {"pk": 492, "model": "auth.permission", "fields": {"codename": "delete_milestonerelationshiptype", "name": "Can delete milestone relationship type", "content_type": 163}}, {"pk": 499, "model": "auth.permission", "fields": {"codename": "add_usermilestone", "name": "Can add user milestone", "content_type": 166}}, {"pk": 500, "model": "auth.permission", "fields": {"codename": "change_usermilestone", "name": "Can change user milestone", "content_type": 166}}, {"pk": 501, "model": "auth.permission", "fields": {"codename": "delete_usermilestone", "name": "Can delete user milestone", "content_type": 166}}, {"pk": 388, "model": "auth.permission", "fields": {"codename": "add_mobileapiconfig", "name": "Can add mobile api config", "content_type": 129}}, {"pk": 389, "model": "auth.permission", "fields": {"codename": "change_mobileapiconfig", "name": "Can change mobile api config", "content_type": 129}}, {"pk": 390, "model": "auth.permission", "fields": {"codename": "delete_mobileapiconfig", "name": "Can delete mobile api config", "content_type": 129}}, {"pk": 280, "model": "auth.permission", "fields": {"codename": "add_note", "name": "Can add note", "content_type": 93}}, {"pk": 281, "model": "auth.permission", "fields": {"codename": "change_note", "name": "Can change note", "content_type": 93}}, {"pk": 282, "model": "auth.permission", "fields": {"codename": "delete_note", "name": "Can delete note", "content_type": 93}}, {"pk": 220, "model": "auth.permission", "fields": {"codename": "add_accesstoken", "name": "Can add access token", "content_type": 74}}, {"pk": 221, "model": "auth.permission", "fields": {"codename": "change_accesstoken", "name": "Can change access token", "content_type": 74}}, {"pk": 222, "model": "auth.permission", "fields": {"codename": "delete_accesstoken", "name": "Can delete access token", "content_type": 74}}, {"pk": 214, "model": "auth.permission", "fields": {"codename": "add_client", "name": "Can add client", "content_type": 72}}, {"pk": 215, "model": "auth.permission", "fields": {"codename": "change_client", "name": "Can change client", "content_type": 72}}, {"pk": 216, "model": "auth.permission", "fields": {"codename": "delete_client", "name": "Can delete client", "content_type": 72}}, {"pk": 217, "model": "auth.permission", "fields": {"codename": "add_grant", "name": "Can add grant", "content_type": 73}}, {"pk": 218, "model": "auth.permission", "fields": {"codename": "change_grant", "name": "Can change grant", "content_type": 73}}, {"pk": 219, "model": "auth.permission", "fields": {"codename": "delete_grant", "name": "Can delete grant", "content_type": 73}}, {"pk": 223, "model": "auth.permission", "fields": {"codename": "add_refreshtoken", "name": "Can add refresh token", "content_type": 75}}, {"pk": 224, "model": "auth.permission", "fields": {"codename": "change_refreshtoken", "name": "Can change refresh token", "content_type": 75}}, {"pk": 225, "model": "auth.permission", "fields": {"codename": "delete_refreshtoken", "name": "Can delete refresh token", "content_type": 75}}, {"pk": 226, "model": "auth.permission", "fields": {"codename": "add_trustedclient", "name": "Can add trusted client", "content_type": 76}}, {"pk": 227, "model": "auth.permission", "fields": {"codename": "change_trustedclient", "name": "Can change trusted client", "content_type": 76}}, {"pk": 228, "model": "auth.permission", "fields": {"codename": "delete_trustedclient", "name": "Can delete trusted client", "content_type": 76}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_psychometricdata", "name": "Can add psychometric data", "content_type": 17}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_psychometricdata", "name": "Can change psychometric data", "content_type": 17}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_psychometricdata", "name": "Can delete psychometric data", "content_type": 17}}, {"pk": 361, "model": "auth.permission", "fields": {"codename": "add_midcoursereverificationwindow", "name": "Can add midcourse reverification window", "content_type": 120}}, {"pk": 362, "model": "auth.permission", "fields": {"codename": "change_midcoursereverificationwindow", "name": "Can change midcourse reverification window", "content_type": 120}}, {"pk": 363, "model": "auth.permission", "fields": {"codename": "delete_midcoursereverificationwindow", "name": "Can delete midcourse reverification window", "content_type": 120}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 340, "model": "auth.permission", "fields": {"codename": "add_certificateitem", "name": "Can add certificate item", "content_type": 113}}, {"pk": 341, "model": "auth.permission", "fields": {"codename": "change_certificateitem", "name": "Can change certificate item", "content_type": 113}}, {"pk": 342, "model": "auth.permission", "fields": {"codename": "delete_certificateitem", "name": "Can delete certificate item", "content_type": 113}}, {"pk": 322, "model": "auth.permission", "fields": {"codename": "add_coupon", "name": "Can add coupon", "content_type": 107}}, {"pk": 323, "model": "auth.permission", "fields": {"codename": "change_coupon", "name": "Can change coupon", "content_type": 107}}, {"pk": 324, "model": "auth.permission", "fields": {"codename": "delete_coupon", "name": "Can delete coupon", "content_type": 107}}, {"pk": 325, "model": "auth.permission", "fields": {"codename": "add_couponredemption", "name": "Can add coupon redemption", "content_type": 108}}, {"pk": 326, "model": "auth.permission", "fields": {"codename": "change_couponredemption", "name": "Can change coupon redemption", "content_type": 108}}, {"pk": 327, "model": "auth.permission", "fields": {"codename": "delete_couponredemption", "name": "Can delete coupon redemption", "content_type": 108}}, {"pk": 331, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitem", "name": "Can add course reg code item", "content_type": 110}}, {"pk": 332, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitem", "name": "Can change course reg code item", "content_type": 110}}, {"pk": 333, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitem", "name": "Can delete course reg code item", "content_type": 110}}, {"pk": 334, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitemannotation", "name": "Can add course reg code item annotation", "content_type": 111}}, {"pk": 335, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitemannotation", "name": "Can change course reg code item annotation", "content_type": 111}}, {"pk": 336, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitemannotation", "name": "Can delete course reg code item annotation", "content_type": 111}}, {"pk": 316, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcode", "name": "Can add course registration code", "content_type": 105}}, {"pk": 317, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcode", "name": "Can change course registration code", "content_type": 105}}, {"pk": 318, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcode", "name": "Can delete course registration code", "content_type": 105}}, {"pk": 310, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcodeinvoiceitem", "name": "Can add course registration code invoice item", "content_type": 103}}, {"pk": 311, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcodeinvoiceitem", "name": "Can change course registration code invoice item", "content_type": 103}}, {"pk": 312, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcodeinvoiceitem", "name": "Can delete course registration code invoice item", "content_type": 103}}, {"pk": 346, "model": "auth.permission", "fields": {"codename": "add_donation", "name": "Can add donation", "content_type": 115}}, {"pk": 347, "model": "auth.permission", "fields": {"codename": "change_donation", "name": "Can change donation", "content_type": 115}}, {"pk": 348, "model": "auth.permission", "fields": {"codename": "delete_donation", "name": "Can delete donation", "content_type": 115}}, {"pk": 343, "model": "auth.permission", "fields": {"codename": "add_donationconfiguration", "name": "Can add donation configuration", "content_type": 114}}, {"pk": 344, "model": "auth.permission", "fields": {"codename": "change_donationconfiguration", "name": "Can change donation configuration", "content_type": 114}}, {"pk": 345, "model": "auth.permission", "fields": {"codename": "delete_donationconfiguration", "name": "Can delete donation configuration", "content_type": 114}}, {"pk": 301, "model": "auth.permission", "fields": {"codename": "add_invoice", "name": "Can add invoice", "content_type": 100}}, {"pk": 302, "model": "auth.permission", "fields": {"codename": "change_invoice", "name": "Can change invoice", "content_type": 100}}, {"pk": 303, "model": "auth.permission", "fields": {"codename": "delete_invoice", "name": "Can delete invoice", "content_type": 100}}, {"pk": 313, "model": "auth.permission", "fields": {"codename": "add_invoicehistory", "name": "Can add invoice history", "content_type": 104}}, {"pk": 314, "model": "auth.permission", "fields": {"codename": "change_invoicehistory", "name": "Can change invoice history", "content_type": 104}}, {"pk": 315, "model": "auth.permission", "fields": {"codename": "delete_invoicehistory", "name": "Can delete invoice history", "content_type": 104}}, {"pk": 307, "model": "auth.permission", "fields": {"codename": "add_invoiceitem", "name": "Can add invoice item", "content_type": 102}}, {"pk": 308, "model": "auth.permission", "fields": {"codename": "change_invoiceitem", "name": "Can change invoice item", "content_type": 102}}, {"pk": 309, "model": "auth.permission", "fields": {"codename": "delete_invoiceitem", "name": "Can delete invoice item", "content_type": 102}}, {"pk": 304, "model": "auth.permission", "fields": {"codename": "add_invoicetransaction", "name": "Can add invoice transaction", "content_type": 101}}, {"pk": 305, "model": "auth.permission", "fields": {"codename": "change_invoicetransaction", "name": "Can change invoice transaction", "content_type": 101}}, {"pk": 306, "model": "auth.permission", "fields": {"codename": "delete_invoicetransaction", "name": "Can delete invoice transaction", "content_type": 101}}, {"pk": 295, "model": "auth.permission", "fields": {"codename": "add_order", "name": "Can add order", "content_type": 98}}, {"pk": 296, "model": "auth.permission", "fields": {"codename": "change_order", "name": "Can change order", "content_type": 98}}, {"pk": 297, "model": "auth.permission", "fields": {"codename": "delete_order", "name": "Can delete order", "content_type": 98}}, {"pk": 298, "model": "auth.permission", "fields": {"codename": "add_orderitem", "name": "Can add order item", "content_type": 99}}, {"pk": 299, "model": "auth.permission", "fields": {"codename": "change_orderitem", "name": "Can change order item", "content_type": 99}}, {"pk": 300, "model": "auth.permission", "fields": {"codename": "delete_orderitem", "name": "Can delete order item", "content_type": 99}}, {"pk": 328, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistration", "name": "Can add paid course registration", "content_type": 109}}, {"pk": 329, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistration", "name": "Can change paid course registration", "content_type": 109}}, {"pk": 330, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistration", "name": "Can delete paid course registration", "content_type": 109}}, {"pk": 337, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistrationannotation", "name": "Can add paid course registration annotation", "content_type": 112}}, {"pk": 338, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistrationannotation", "name": "Can change paid course registration annotation", "content_type": 112}}, {"pk": 339, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistrationannotation", "name": "Can delete paid course registration annotation", "content_type": 112}}, {"pk": 319, "model": "auth.permission", "fields": {"codename": "add_registrationcoderedemption", "name": "Can add registration code redemption", "content_type": 106}}, {"pk": 320, "model": "auth.permission", "fields": {"codename": "change_registrationcoderedemption", "name": "Can change registration code redemption", "content_type": 106}}, {"pk": 321, "model": "auth.permission", "fields": {"codename": "delete_registrationcoderedemption", "name": "Can delete registration code redemption", "content_type": 106}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 6}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 15}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 15}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 15}}, {"pk": 283, "model": "auth.permission", "fields": {"codename": "add_splashconfig", "name": "Can add splash config", "content_type": 94}}, {"pk": 284, "model": "auth.permission", "fields": {"codename": "change_splashconfig", "name": "Can change splash config", "content_type": 94}}, {"pk": 285, "model": "auth.permission", "fields": {"codename": "delete_splashconfig", "name": "Can delete splash config", "content_type": 94}}, {"pk": 100, "model": "auth.permission", "fields": {"codename": "add_anonymoususerid", "name": "Can add anonymous user id", "content_type": 34}}, {"pk": 101, "model": "auth.permission", "fields": {"codename": "change_anonymoususerid", "name": "Can change anonymous user id", "content_type": 34}}, {"pk": 102, "model": "auth.permission", "fields": {"codename": "delete_anonymoususerid", "name": "Can delete anonymous user id", "content_type": 34}}, {"pk": 136, "model": "auth.permission", "fields": {"codename": "add_courseaccessrole", "name": "Can add course access role", "content_type": 46}}, {"pk": 137, "model": "auth.permission", "fields": {"codename": "change_courseaccessrole", "name": "Can change course access role", "content_type": 46}}, {"pk": 138, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrole", "name": "Can delete course access role", "content_type": 46}}, {"pk": 130, "model": "auth.permission", "fields": {"codename": "add_courseenrollment", "name": "Can add course enrollment", "content_type": 44}}, {"pk": 131, "model": "auth.permission", "fields": {"codename": "change_courseenrollment", "name": "Can change course enrollment", "content_type": 44}}, {"pk": 132, "model": "auth.permission", "fields": {"codename": "delete_courseenrollment", "name": "Can delete course enrollment", "content_type": 44}}, {"pk": 133, "model": "auth.permission", "fields": {"codename": "add_courseenrollmentallowed", "name": "Can add course enrollment allowed", "content_type": 45}}, {"pk": 134, "model": "auth.permission", "fields": {"codename": "change_courseenrollmentallowed", "name": "Can change course enrollment allowed", "content_type": 45}}, {"pk": 135, "model": "auth.permission", "fields": {"codename": "delete_courseenrollmentallowed", "name": "Can delete course enrollment allowed", "content_type": 45}}, {"pk": 139, "model": "auth.permission", "fields": {"codename": "add_dashboardconfiguration", "name": "Can add dashboard configuration", "content_type": 47}}, {"pk": 140, "model": "auth.permission", "fields": {"codename": "change_dashboardconfiguration", "name": "Can change dashboard configuration", "content_type": 47}}, {"pk": 141, "model": "auth.permission", "fields": {"codename": "delete_dashboardconfiguration", "name": "Can delete dashboard configuration", "content_type": 47}}, {"pk": 145, "model": "auth.permission", "fields": {"codename": "add_entranceexamconfiguration", "name": "Can add entrance exam configuration", "content_type": 49}}, {"pk": 146, "model": "auth.permission", "fields": {"codename": "change_entranceexamconfiguration", "name": "Can change entrance exam configuration", "content_type": 49}}, {"pk": 147, "model": "auth.permission", "fields": {"codename": "delete_entranceexamconfiguration", "name": "Can delete entrance exam configuration", "content_type": 49}}, {"pk": 142, "model": "auth.permission", "fields": {"codename": "add_linkedinaddtoprofileconfiguration", "name": "Can add linked in add to profile configuration", "content_type": 48}}, {"pk": 143, "model": "auth.permission", "fields": {"codename": "change_linkedinaddtoprofileconfiguration", "name": "Can change linked in add to profile configuration", "content_type": 48}}, {"pk": 144, "model": "auth.permission", "fields": {"codename": "delete_linkedinaddtoprofileconfiguration", "name": "Can delete linked in add to profile configuration", "content_type": 48}}, {"pk": 127, "model": "auth.permission", "fields": {"codename": "add_loginfailures", "name": "Can add login failures", "content_type": 43}}, {"pk": 128, "model": "auth.permission", "fields": {"codename": "change_loginfailures", "name": "Can change login failures", "content_type": 43}}, {"pk": 129, "model": "auth.permission", "fields": {"codename": "delete_loginfailures", "name": "Can delete login failures", "content_type": 43}}, {"pk": 124, "model": "auth.permission", "fields": {"codename": "add_passwordhistory", "name": "Can add password history", "content_type": 42}}, {"pk": 125, "model": "auth.permission", "fields": {"codename": "change_passwordhistory", "name": "Can change password history", "content_type": 42}}, {"pk": 126, "model": "auth.permission", "fields": {"codename": "delete_passwordhistory", "name": "Can delete password history", "content_type": 42}}, {"pk": 121, "model": "auth.permission", "fields": {"codename": "add_pendingemailchange", "name": "Can add pending email change", "content_type": 41}}, {"pk": 122, "model": "auth.permission", "fields": {"codename": "change_pendingemailchange", "name": "Can change pending email change", "content_type": 41}}, {"pk": 123, "model": "auth.permission", "fields": {"codename": "delete_pendingemailchange", "name": "Can delete pending email change", "content_type": 41}}, {"pk": 118, "model": "auth.permission", "fields": {"codename": "add_pendingnamechange", "name": "Can add pending name change", "content_type": 40}}, {"pk": 119, "model": "auth.permission", "fields": {"codename": "change_pendingnamechange", "name": "Can change pending name change", "content_type": 40}}, {"pk": 120, "model": "auth.permission", "fields": {"codename": "delete_pendingnamechange", "name": "Can delete pending name change", "content_type": 40}}, {"pk": 115, "model": "auth.permission", "fields": {"codename": "add_registration", "name": "Can add registration", "content_type": 39}}, {"pk": 116, "model": "auth.permission", "fields": {"codename": "change_registration", "name": "Can change registration", "content_type": 39}}, {"pk": 117, "model": "auth.permission", "fields": {"codename": "delete_registration", "name": "Can delete registration", "content_type": 39}}, {"pk": 106, "model": "auth.permission", "fields": {"codename": "add_userprofile", "name": "Can add user profile", "content_type": 36}}, {"pk": 107, "model": "auth.permission", "fields": {"codename": "change_userprofile", "name": "Can change user profile", "content_type": 36}}, {"pk": 108, "model": "auth.permission", "fields": {"codename": "delete_userprofile", "name": "Can delete user profile", "content_type": 36}}, {"pk": 109, "model": "auth.permission", "fields": {"codename": "add_usersignupsource", "name": "Can add user signup source", "content_type": 37}}, {"pk": 110, "model": "auth.permission", "fields": {"codename": "change_usersignupsource", "name": "Can change user signup source", "content_type": 37}}, {"pk": 111, "model": "auth.permission", "fields": {"codename": "delete_usersignupsource", "name": "Can delete user signup source", "content_type": 37}}, {"pk": 103, "model": "auth.permission", "fields": {"codename": "add_userstanding", "name": "Can add user standing", "content_type": 35}}, {"pk": 104, "model": "auth.permission", "fields": {"codename": "change_userstanding", "name": "Can change user standing", "content_type": 35}}, {"pk": 105, "model": "auth.permission", "fields": {"codename": "delete_userstanding", "name": "Can delete user standing", "content_type": 35}}, {"pk": 112, "model": "auth.permission", "fields": {"codename": "add_usertestgroup", "name": "Can add user test group", "content_type": 38}}, {"pk": 113, "model": "auth.permission", "fields": {"codename": "change_usertestgroup", "name": "Can change user test group", "content_type": 38}}, {"pk": 114, "model": "auth.permission", "fields": {"codename": "delete_usertestgroup", "name": "Can delete user test group", "content_type": 38}}, {"pk": 409, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 136}}, {"pk": 410, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 136}}, {"pk": 411, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 136}}, {"pk": 412, "model": "auth.permission", "fields": {"codename": "add_scoresummary", "name": "Can add score summary", "content_type": 137}}, {"pk": 413, "model": "auth.permission", "fields": {"codename": "change_scoresummary", "name": "Can change score summary", "content_type": 137}}, {"pk": 414, "model": "auth.permission", "fields": {"codename": "delete_scoresummary", "name": "Can delete score summary", "content_type": 137}}, {"pk": 403, "model": "auth.permission", "fields": {"codename": "add_studentitem", "name": "Can add student item", "content_type": 134}}, {"pk": 404, "model": "auth.permission", "fields": {"codename": "change_studentitem", "name": "Can change student item", "content_type": 134}}, {"pk": 405, "model": "auth.permission", "fields": {"codename": "delete_studentitem", "name": "Can delete student item", "content_type": 134}}, {"pk": 406, "model": "auth.permission", "fields": {"codename": "add_submission", "name": "Can add submission", "content_type": 135}}, {"pk": 407, "model": "auth.permission", "fields": {"codename": "change_submission", "name": "Can change submission", "content_type": 135}}, {"pk": 408, "model": "auth.permission", "fields": {"codename": "delete_submission", "name": "Can delete submission", "content_type": 135}}, {"pk": 394, "model": "auth.permission", "fields": {"codename": "add_surveyanswer", "name": "Can add survey answer", "content_type": 131}}, {"pk": 395, "model": "auth.permission", "fields": {"codename": "change_surveyanswer", "name": "Can change survey answer", "content_type": 131}}, {"pk": 396, "model": "auth.permission", "fields": {"codename": "delete_surveyanswer", "name": "Can delete survey answer", "content_type": 131}}, {"pk": 391, "model": "auth.permission", "fields": {"codename": "add_surveyform", "name": "Can add survey form", "content_type": 130}}, {"pk": 392, "model": "auth.permission", "fields": {"codename": "change_surveyform", "name": "Can change survey form", "content_type": 130}}, {"pk": 393, "model": "auth.permission", "fields": {"codename": "delete_surveyform", "name": "Can delete survey form", "content_type": 130}}, {"pk": 148, "model": "auth.permission", "fields": {"codename": "add_trackinglog", "name": "Can add tracking log", "content_type": 50}}, {"pk": 149, "model": "auth.permission", "fields": {"codename": "change_trackinglog", "name": "Can change tracking log", "content_type": 50}}, {"pk": 150, "model": "auth.permission", "fields": {"codename": "delete_trackinglog", "name": "Can delete tracking log", "content_type": 50}}, {"pk": 289, "model": "auth.permission", "fields": {"codename": "add_usercoursetag", "name": "Can add user course tag", "content_type": 96}}, {"pk": 290, "model": "auth.permission", "fields": {"codename": "change_usercoursetag", "name": "Can change user course tag", "content_type": 96}}, {"pk": 291, "model": "auth.permission", "fields": {"codename": "delete_usercoursetag", "name": "Can delete user course tag", "content_type": 96}}, {"pk": 292, "model": "auth.permission", "fields": {"codename": "add_userorgtag", "name": "Can add user org tag", "content_type": 97}}, {"pk": 293, "model": "auth.permission", "fields": {"codename": "change_userorgtag", "name": "Can change user org tag", "content_type": 97}}, {"pk": 294, "model": "auth.permission", "fields": {"codename": "delete_userorgtag", "name": "Can delete user org tag", "content_type": 97}}, {"pk": 286, "model": "auth.permission", "fields": {"codename": "add_userpreference", "name": "Can add user preference", "content_type": 95}}, {"pk": 287, "model": "auth.permission", "fields": {"codename": "change_userpreference", "name": "Can change user preference", "content_type": 95}}, {"pk": 288, "model": "auth.permission", "fields": {"codename": "delete_userpreference", "name": "Can delete user preference", "content_type": 95}}, {"pk": 151, "model": "auth.permission", "fields": {"codename": "add_ratelimitconfiguration", "name": "Can add rate limit configuration", "content_type": 51}}, {"pk": 152, "model": "auth.permission", "fields": {"codename": "change_ratelimitconfiguration", "name": "Can change rate limit configuration", "content_type": 51}}, {"pk": 153, "model": "auth.permission", "fields": {"codename": "delete_ratelimitconfiguration", "name": "Can delete rate limit configuration", "content_type": 51}}, {"pk": 355, "model": "auth.permission", "fields": {"codename": "add_softwaresecurephotoverification", "name": "Can add software secure photo verification", "content_type": 118}}, {"pk": 356, "model": "auth.permission", "fields": {"codename": "change_softwaresecurephotoverification", "name": "Can change software secure photo verification", "content_type": 118}}, {"pk": 357, "model": "auth.permission", "fields": {"codename": "delete_softwaresecurephotoverification", "name": "Can delete software secure photo verification", "content_type": 118}}, {"pk": 229, "model": "auth.permission", "fields": {"codename": "add_article", "name": "Can add article", "content_type": 77}}, {"pk": 233, "model": "auth.permission", "fields": {"codename": "assign", "name": "Can change ownership of any article", "content_type": 77}}, {"pk": 230, "model": "auth.permission", "fields": {"codename": "change_article", "name": "Can change article", "content_type": 77}}, {"pk": 231, "model": "auth.permission", "fields": {"codename": "delete_article", "name": "Can delete article", "content_type": 77}}, {"pk": 234, "model": "auth.permission", "fields": {"codename": "grant", "name": "Can assign permissions to other users", "content_type": 77}}, {"pk": 232, "model": "auth.permission", "fields": {"codename": "moderate", "name": "Can edit all articles and lock/unlock/restore", "content_type": 77}}, {"pk": 235, "model": "auth.permission", "fields": {"codename": "add_articleforobject", "name": "Can add Article for object", "content_type": 78}}, {"pk": 236, "model": "auth.permission", "fields": {"codename": "change_articleforobject", "name": "Can change Article for object", "content_type": 78}}, {"pk": 237, "model": "auth.permission", "fields": {"codename": "delete_articleforobject", "name": "Can delete Article for object", "content_type": 78}}, {"pk": 244, "model": "auth.permission", "fields": {"codename": "add_articleplugin", "name": "Can add article plugin", "content_type": 81}}, {"pk": 245, "model": "auth.permission", "fields": {"codename": "change_articleplugin", "name": "Can change article plugin", "content_type": 81}}, {"pk": 246, "model": "auth.permission", "fields": {"codename": "delete_articleplugin", "name": "Can delete article plugin", "content_type": 81}}, {"pk": 238, "model": "auth.permission", "fields": {"codename": "add_articlerevision", "name": "Can add article revision", "content_type": 79}}, {"pk": 239, "model": "auth.permission", "fields": {"codename": "change_articlerevision", "name": "Can change article revision", "content_type": 79}}, {"pk": 240, "model": "auth.permission", "fields": {"codename": "delete_articlerevision", "name": "Can delete article revision", "content_type": 79}}, {"pk": 259, "model": "auth.permission", "fields": {"codename": "add_articlesubscription", "name": "Can add article subscription", "content_type": 86}}, {"pk": 260, "model": "auth.permission", "fields": {"codename": "change_articlesubscription", "name": "Can change article subscription", "content_type": 86}}, {"pk": 261, "model": "auth.permission", "fields": {"codename": "delete_articlesubscription", "name": "Can delete article subscription", "content_type": 86}}, {"pk": 247, "model": "auth.permission", "fields": {"codename": "add_reusableplugin", "name": "Can add reusable plugin", "content_type": 82}}, {"pk": 248, "model": "auth.permission", "fields": {"codename": "change_reusableplugin", "name": "Can change reusable plugin", "content_type": 82}}, {"pk": 249, "model": "auth.permission", "fields": {"codename": "delete_reusableplugin", "name": "Can delete reusable plugin", "content_type": 82}}, {"pk": 253, "model": "auth.permission", "fields": {"codename": "add_revisionplugin", "name": "Can add revision plugin", "content_type": 84}}, {"pk": 254, "model": "auth.permission", "fields": {"codename": "change_revisionplugin", "name": "Can change revision plugin", "content_type": 84}}, {"pk": 255, "model": "auth.permission", "fields": {"codename": "delete_revisionplugin", "name": "Can delete revision plugin", "content_type": 84}}, {"pk": 256, "model": "auth.permission", "fields": {"codename": "add_revisionpluginrevision", "name": "Can add revision plugin revision", "content_type": 85}}, {"pk": 257, "model": "auth.permission", "fields": {"codename": "change_revisionpluginrevision", "name": "Can change revision plugin revision", "content_type": 85}}, {"pk": 258, "model": "auth.permission", "fields": {"codename": "delete_revisionpluginrevision", "name": "Can delete revision plugin revision", "content_type": 85}}, {"pk": 250, "model": "auth.permission", "fields": {"codename": "add_simpleplugin", "name": "Can add simple plugin", "content_type": 83}}, {"pk": 251, "model": "auth.permission", "fields": {"codename": "change_simpleplugin", "name": "Can change simple plugin", "content_type": 83}}, {"pk": 252, "model": "auth.permission", "fields": {"codename": "delete_simpleplugin", "name": "Can delete simple plugin", "content_type": 83}}, {"pk": 241, "model": "auth.permission", "fields": {"codename": "add_urlpath", "name": "Can add URL path", "content_type": 80}}, {"pk": 242, "model": "auth.permission", "fields": {"codename": "change_urlpath", "name": "Can change URL path", "content_type": 80}}, {"pk": 243, "model": "auth.permission", "fields": {"codename": "delete_urlpath", "name": "Can delete URL path", "content_type": 80}}, {"pk": 463, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflow", "name": "Can add assessment workflow", "content_type": 154}}, {"pk": 464, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflow", "name": "Can change assessment workflow", "content_type": 154}}, {"pk": 465, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflow", "name": "Can delete assessment workflow", "content_type": 154}}, {"pk": 469, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowcancellation", "name": "Can add assessment workflow cancellation", "content_type": 156}}, {"pk": 470, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowcancellation", "name": "Can change assessment workflow cancellation", "content_type": 156}}, {"pk": 471, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowcancellation", "name": "Can delete assessment workflow cancellation", "content_type": 156}}, {"pk": 466, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowstep", "name": "Can add assessment workflow step", "content_type": 155}}, {"pk": 467, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowstep", "name": "Can change assessment workflow step", "content_type": 155}}, {"pk": 468, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowstep", "name": "Can delete assessment workflow step", "content_type": 155}}, {"pk": 508, "model": "auth.permission", "fields": {"codename": "add_studioconfig", "name": "Can add studio config", "content_type": 169}}, {"pk": 509, "model": "auth.permission", "fields": {"codename": "change_studioconfig", "name": "Can change studio config", "content_type": 169}}, {"pk": 510, "model": "auth.permission", "fields": {"codename": "delete_studioconfig", "name": "Can delete studio config", "content_type": 169}}, {"pk": 1, "model": "util.ratelimitconfiguration", "fields": {"change_date": "2015-03-31T06:25:45Z", "changed_by": null, "enabled": true}}, {"pk": 1, "model": "certificates.certificatehtmlviewconfiguration", "fields": {"change_date": "2015-03-31T06:25:47Z", "changed_by": null, "configuration": "{\n            {\n    \"default\": {\n        \"accomplishment_class_append\": \"accomplishment-certificate\",\n        \"platform_name\": \"edX\",\n        \"company_privacy_url\": \"http://www.edx.org/edx-privacy-policy\",\n        \"company_tos_url\": \"http://www.edx.org/edx-terms-service\",\n        \"company_verified_certificate_url\": \"http://www.edx.org/verified-certificate\",\n        \"document_stylesheet_url_application\": \"/static/certificates/sass/main-ltr.css\",\n        \"logo_src\": \"/static/certificates/images/logo-edx.svg\",\n        \"logo_url\": \"http://www.edx.org\"\n    },\n    \"honor\": {\n        \"certificate_type\": \"Honor Code\",\n        \"document_body_class_append\": \"is-honorcode\"\n    },\n    \"verified\": {\n        \"certificate_type\": \"Verified\",\n        \"document_body_class_append\": \"is-idverified\"\n    },\n    \"xseries\": {\n        \"certificate_type\": \"XSeries\",\n        \"document_body_class_append\": \"is-xseries\"\n    }\n}\n        }", "enabled": false}}, {"pk": 1, "model": "dark_lang.darklangconfig", "fields": {"change_date": "2015-03-31T06:26:01Z", "changed_by": null, "enabled": true, "released_languages": ""}}, {"pk": 1, "model": "mobile_api.mobileapiconfig", "fields": {"change_date": "2015-03-31T06:26:03Z", "video_profiles": "mobile_low,mobile_high,youtube", "changed_by": null, "enabled": false}},{"pk": 1, "model": "edxval.profile", "fields": {"profile_name": "desktop_mp4"}}, {"pk": 1, "model": "edxval.video", "fields": {"duration": 10.0, "status": "status", "edx_video_id": "edx_video_id", "client_video_id": "", "created": "2015-04-25T18:04:41Z"}}, {"pk": 1, "model": "edxval.encodedvideo", "fields": {"profile": 1, "created": "2015-04-25T18:04:41Z", "url": "http://www.w3schools.com/html/mov_bbb.webm", "modified": "2015-04-25T18:04:41Z", "video": 1, "file_size": 1000, "bitrate": 1000}}]
diff --git a/lms/djangoapps/courseware/tests/test_video_handlers.py b/lms/djangoapps/courseware/tests/test_video_handlers.py
index d785136597b3133f213f2ca5731b24a408a4eaeb..86be625395df533697b536e3ed7e7c65dcbb88f5 100644
--- a/lms/djangoapps/courseware/tests/test_video_handlers.py
+++ b/lms/djangoapps/courseware/tests/test_video_handlers.py
@@ -1,15 +1,17 @@
 # -*- coding: utf-8 -*-
 """Video xmodule tests in mongo."""
 
-from mock import patch
-from nose.plugins.attrib import attr
 import os
+import freezegun
 import tempfile
 import textwrap
 import json
-from datetime import timedelta
+import ddt
+
+from nose.plugins.attrib import attr
+from datetime import timedelta, datetime
 from webob import Request
-from mock import MagicMock, Mock
+from mock import MagicMock, Mock, patch
 
 from xmodule.contentstore.content import StaticContent
 from xmodule.contentstore.django import contentstore
@@ -26,6 +28,9 @@ from xmodule.video_module.transcripts_utils import (
     TranscriptsGenerationException,
 )
 
+
+TRANSCRIPT = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
+BUMPER_TRANSCRIPT = {"start": [1], "end": [10], "text": ["A bumper"]}
 SRT_content = textwrap.dedent("""
         0
         00:00:00,12 --> 00:00:00,100
@@ -104,6 +109,20 @@ def _upload_file(subs_file, location, filename):
     del_cached_content(content.location)
 
 
+def attach_sub(item, filename):
+    """
+    Attach `en` transcript.
+    """
+    item.sub = filename
+
+
+def attach_bumper_transcript(item, filename, lang="en"):
+    """
+    Attach bumper transcript.
+    """
+    item.video_bumper["transcripts"][lang] = filename
+
+
 @attr('shard_1')
 class TestVideo(BaseTestXmodule):
     """Integration tests: web client + mongo."""
@@ -129,6 +148,8 @@ class TestVideo(BaseTestXmodule):
             {'speed': 2.0},
             {'saved_video_position': "00:00:10"},
             {'transcript_language': 'uk'},
+            {'bumper_do_not_show_again': True},
+            {'bumper_last_view_date': True},
             {'demoo�': 'sample'}
         ]
         for sample in data:
@@ -151,6 +172,15 @@ class TestVideo(BaseTestXmodule):
         self.item_descriptor.handle_ajax('save_user_state', {'transcript_language': "uk"})
         self.assertEqual(self.item_descriptor.transcript_language, 'uk')
 
+        self.assertEqual(self.item_descriptor.bumper_do_not_show_again, False)
+        self.item_descriptor.handle_ajax('save_user_state', {'bumper_do_not_show_again': True})
+        self.assertEqual(self.item_descriptor.bumper_do_not_show_again, True)
+
+        with freezegun.freeze_time(datetime.now()):
+            self.assertEqual(self.item_descriptor.bumper_last_view_date, None)
+            self.item_descriptor.handle_ajax('save_user_state', {'bumper_last_view_date': True})
+            self.assertEqual(self.item_descriptor.bumper_last_view_date, datetime.utcnow())
+
         response = self.item_descriptor.handle_ajax('save_user_state', {u'demoo�': "sample"})
         self.assertEqual(json.loads(response)['success'], True)
 
@@ -166,7 +196,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
 
     Tests for `available_translations` dispatch.
     """
-    non_en_file = _create_srt_file()
+    srt_file = _create_srt_file()
     DATA = """
         <video show_captions="true"
         display_name="A Name"
@@ -175,7 +205,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
             <source src="example.webm"/>
             <transcript language="uk" src="{}"/>
         </video>
-    """.format(os.path.split(non_en_file.name)[1])
+    """.format(os.path.split(srt_file.name)[1])
 
     MODEL_DATA = {
         'data': DATA
@@ -197,7 +227,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
         self.assertEqual(json.loads(response.body), ['en'])
 
     def test_available_translation_non_en(self):
-        _upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
+        _upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
 
         request = Request.blank('/available_translations')
         response = self.item.transcript(request=request, dispatch='available_translations')
@@ -210,7 +240,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
         _upload_sjson_file(good_sjson, self.item_descriptor.location)
 
         # Upload non-english transcript.
-        _upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
+        _upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
 
         self.item.sub = _get_subs_id(good_sjson.name)
 
@@ -220,6 +250,63 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
 
 
 @attr('shard_1')
+@ddt.ddt
+class TestTranscriptAvailableTranslationsBumperDispatch(TestVideo):
+    """
+    Test video handler that provide available translations info.
+
+    Tests for `available_translations_bumper` dispatch.
+    """
+    srt_file = _create_srt_file()
+    DATA = """
+        <video show_captions="true"
+        display_name="A Name"
+        >
+            <source src="example.mp4"/>
+            <source src="example.webm"/>
+            <transcript language="uk" src="{}"/>
+        </video>
+    """.format(os.path.split(srt_file.name)[1])
+
+    MODEL_DATA = {
+        'data': DATA
+    }
+
+    def setUp(self):
+        super(TestTranscriptAvailableTranslationsBumperDispatch, self).setUp()
+        self.item_descriptor.render(STUDENT_VIEW)
+        self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+        self.dispatch = "available_translations/?is_bumper=1"
+        self.item.video_bumper = {"transcripts": {"en": ""}}
+
+    @ddt.data("en", "uk")
+    def test_available_translation_en_and_non_en(self, lang):
+        filename = os.path.split(self.srt_file.name)[1]
+        _upload_file(self.srt_file, self.item_descriptor.location, filename)
+        self.item.video_bumper["transcripts"][lang] = filename
+
+        request = Request.blank('/' + self.dispatch)
+        response = self.item.transcript(request=request, dispatch=self.dispatch)
+        self.assertEqual(json.loads(response.body), [lang])
+
+    def test_multiple_available_translations(self):
+        en_translation = _create_srt_file()
+        en_translation_filename = os.path.split(en_translation.name)[1]
+        uk_translation_filename = os.path.split(self.srt_file.name)[1]
+        # Upload english transcript.
+        _upload_file(en_translation, self.item_descriptor.location, en_translation_filename)
+
+        # Upload non-english transcript.
+        _upload_file(self.srt_file, self.item_descriptor.location, uk_translation_filename)
+
+        self.item.video_bumper["transcripts"]["en"] = en_translation_filename
+        self.item.video_bumper["transcripts"]["uk"] = uk_translation_filename
+
+        request = Request.blank('/' + self.dispatch)
+        response = self.item.transcript(request=request, dispatch=self.dispatch)
+        self.assertEqual(json.loads(response.body), ['en', 'uk'])
+
+
 class TestTranscriptDownloadDispatch(TestVideo):
     """
     Test video handler that provide translation transcripts.
@@ -272,8 +359,9 @@ class TestTranscriptDownloadDispatch(TestVideo):
         request = Request.blank('/download')
         response = self.item.transcript(request=request, dispatch='download')
         self.assertEqual(response.status, '404 Not Found')
+        transcripts = self.item.get_transcripts_info()
         with self.assertRaises(NotFoundError):
-            self.item.get_transcript()
+            self.item.get_transcript(transcripts)
 
     @patch('xmodule.video_module.VideoModule.get_transcript', return_value=('Subs!', u"å¡ž.srt", 'application/x-subrip; charset=utf-8'))
     def test_download_non_en_non_ascii_filename(self, __):
@@ -285,14 +373,15 @@ class TestTranscriptDownloadDispatch(TestVideo):
 
 
 @attr('shard_1')
+@ddt.ddt
 class TestTranscriptTranslationGetDispatch(TestVideo):
     """
     Test video handler that provide translation transcripts.
 
-    Tests for `translation` dispatch.
+    Tests for `translation` and `translation_bumper` dispatches.
     """
 
-    non_en_file = _create_srt_file()
+    srt_file = _create_srt_file()
     DATA = """
         <video show_captions="true"
         display_name="A Name"
@@ -301,7 +390,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
             <source src="example.webm"/>
             <transcript language="uk" src="{}"/>
         </video>
-    """.format(os.path.split(non_en_file.name)[1])
+    """.format(os.path.split(srt_file.name)[1])
 
     MODEL_DATA = {
         'data': DATA
@@ -311,37 +400,41 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
         super(TestTranscriptTranslationGetDispatch, self).setUp()
         self.item_descriptor.render(STUDENT_VIEW)
         self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+        self.item.video_bumper = {"transcripts": {"en": ""}}
 
-    def test_translation_fails(self):
+    @ddt.data(
         # No language
-        request = Request.blank('/translation')
-        response = self.item.transcript(request=request, dispatch='translation')
-        self.assertEqual(response.status, '400 Bad Request')
-
+        ('/translation', 'translation', '400 Bad Request'),
         # No videoId - HTML5 video with language that is not in available languages
-        request = Request.blank('/translation/ru')
-        response = self.item.transcript(request=request, dispatch='translation/ru')
-        self.assertEqual(response.status, '404 Not Found')
-
+        ('/translation/ru', 'translation/ru', '404 Not Found'),
         # Language is not in available languages
-        request = Request.blank('/translation/ru?videoId=12345')
-        response = self.item.transcript(request=request, dispatch='translation/ru')
-        self.assertEqual(response.status, '404 Not Found')
-
+        ('/translation/ru?videoId=12345', 'translation/ru', '404 Not Found'),
         # Youtube_id is invalid or does not exist
-        request = Request.blank('/translation/uk?videoId=9855256955511225')
-        response = self.item.transcript(request=request, dispatch='translation/uk')
-        self.assertEqual(response.status, '404 Not Found')
-
-    def test_translaton_en_youtube_success(self):
+        ('/translation/uk?videoId=9855256955511225', 'translation/uk', '404 Not Found'),
+        ('/translation?is_bumper=1', 'translation', '400 Bad Request'),
+        ('/translation/ru?is_bumper=1', 'translation/ru', '404 Not Found'),
+        ('/translation/ru?videoId=12345&is_bumper=1', 'translation/ru', '404 Not Found'),
+        ('/translation/uk?videoId=9855256955511225&is_bumper=1', 'translation/uk', '404 Not Found'),
+    )
+    @ddt.unpack
+    def test_translation_fails(self, url, dispatch, status_code):
+        request = Request.blank(url)
+        response = self.item.transcript(request=request, dispatch=dispatch)
+        self.assertEqual(response.status, status_code)
+
+    @ddt.data(
+        ('translation/en?videoId={}', 'translation/en', attach_sub),
+        ('translation/en?videoId={}&is_bumper=1', 'translation/en', attach_bumper_transcript))
+    @ddt.unpack
+    def test_translaton_en_youtube_success(self, url, dispatch, attach):
         subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
         good_sjson = _create_file(json.dumps(subs))
         _upload_sjson_file(good_sjson, self.item_descriptor.location)
         subs_id = _get_subs_id(good_sjson.name)
 
-        self.item.sub = subs_id
-        request = Request.blank('/translation/en?videoId={}'.format(subs_id))
-        response = self.item.transcript(request=request, dispatch='translation/en')
+        attach(self.item, subs_id)
+        request = Request.blank(url.format(subs_id))
+        response = self.item.transcript(request=request, dispatch=dispatch)
         self.assertDictEqual(json.loads(response.body), subs)
 
     def test_translation_non_en_youtube_success(self):
@@ -352,9 +445,9 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
                 u'\u041f\u0440\u0438\u0432\u0456\u0442, edX \u0432\u0456\u0442\u0430\u0454 \u0432\u0430\u0441.'
             ]
         }
-        self.non_en_file.seek(0)
-        _upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
-        subs_id = _get_subs_id(self.non_en_file.name)
+        self.srt_file.seek(0)
+        _upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
+        subs_id = _get_subs_id(self.srt_file.name)
 
         # youtube 1_0 request, will generate for all speeds for existing ids
         self.item.youtube_id_1_0 = subs_id
@@ -387,16 +480,19 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
         }
         self.assertDictEqual(json.loads(response.body), calculated_1_5)
 
-    def test_translaton_en_html5_success(self):
-        subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
-        good_sjson = _create_file(json.dumps(subs))
+    @ddt.data(
+        ('translation/en', 'translation/en', attach_sub),
+        ('translation/en?is_bumper=1', 'translation/en', attach_bumper_transcript))
+    @ddt.unpack
+    def test_translaton_en_html5_success(self, url, dispatch, attach):
+        good_sjson = _create_file(json.dumps(TRANSCRIPT))
         _upload_sjson_file(good_sjson, self.item_descriptor.location)
         subs_id = _get_subs_id(good_sjson.name)
 
-        self.item.sub = subs_id
-        request = Request.blank('/translation/en')
-        response = self.item.transcript(request=request, dispatch='translation/en')
-        self.assertDictEqual(json.loads(response.body), subs)
+        attach(self.item, subs_id)
+        request = Request.blank(url)
+        response = self.item.transcript(request=request, dispatch=dispatch)
+        self.assertDictEqual(json.loads(response.body), TRANSCRIPT)
 
     def test_translaton_non_en_html5_success(self):
         subs = {
@@ -406,8 +502,8 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
                 u'\u041f\u0440\u0438\u0432\u0456\u0442, edX \u0432\u0456\u0442\u0430\u0454 \u0432\u0430\u0441.'
             ]
         }
-        self.non_en_file.seek(0)
-        _upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
+        self.srt_file.seek(0)
+        _upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
 
         # manually clean youtube_id_1_0, as it has default value
         self.item.youtube_id_1_0 = ""
@@ -453,7 +549,22 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
         response = self.item.transcript(request=request, dispatch='translation/uk')
         self.assertEqual(response.status, '404 Not Found')
 
-    def test_translation_static_transcript(self):
+    @ddt.data(
+        # Test youtube style en
+        ('/translation/en?videoId=12345', 'translation/en', '307 Temporary Redirect', '12345'),
+        # Test html5 style en
+        ('/translation/en', 'translation/en', '307 Temporary Redirect', 'OEoXaMPEzfM', attach_sub),
+        # Test different language to ensure we are just ignoring it since we can't
+        # translate with static fallback
+        ('/translation/uk', 'translation/uk', '404 Not Found'),
+        (
+            '/translation/en?is_bumper=1', 'translation/en', '307 Temporary Redirect', 'OEoXaMPEzfM',
+            attach_bumper_transcript
+        ),
+        ('/translation/uk?is_bumper=1', 'translation/uk', '404 Not Found'),
+    )
+    @ddt.unpack
+    def test_translation_static_transcript(self, url, dispatch, status_code, sub=None, attach=None):
         """
         Set course static_asset_path and ensure we get redirected to that path
         if it isn't found in the contentstore
@@ -464,30 +575,16 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
         with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
             store.update_item(self.course, self.user.id)
 
-        # Test youtube style en
-        request = Request.blank('/translation/en?videoId=12345')
-        response = self.item.transcript(request=request, dispatch='translation/en')
-        self.assertEqual(response.status, '307 Temporary Redirect')
-        self.assertIn(
-            ('Location', '/static/dummy/static/subs_12345.srt.sjson'),
-            response.headerlist
-        )
-
-        # Test HTML5 video style
-        self.item.sub = 'OEoXaMPEzfM'
-        request = Request.blank('/translation/en')
-        response = self.item.transcript(request=request, dispatch='translation/en')
-        self.assertEqual(response.status, '307 Temporary Redirect')
-        self.assertIn(
-            ('Location', '/static/dummy/static/subs_OEoXaMPEzfM.srt.sjson'),
-            response.headerlist
-        )
-
-        # Test different language to ensure we are just ignoring it since we can't
-        # translate with static fallback
-        request = Request.blank('/translation/uk')
-        response = self.item.transcript(request=request, dispatch='translation/uk')
-        self.assertEqual(response.status, '404 Not Found')
+        if attach:
+            attach(self.item, sub)
+        request = Request.blank(url)
+        response = self.item.transcript(request=request, dispatch=dispatch)
+        self.assertEqual(response.status, status_code)
+        if sub:
+            self.assertIn(
+                ('Location', '/static/dummy/static/subs_{}.srt.sjson'.format(sub)),
+                response.headerlist
+            )
 
 
 @attr('shard_1')
@@ -497,7 +594,7 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo):
 
     Tests for `translation` dispatch GET HTTP method.
     """
-    non_en_file = _create_srt_file()
+    srt_file = _create_srt_file()
     DATA = """
         <video show_captions="true"
         display_name="A Name"
@@ -507,7 +604,7 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo):
             <transcript language="uk" src="{}"/>
             <transcript language="zh" src="{}"/>
         </video>
-    """.format(os.path.split(non_en_file.name)[1], u"å¡ž.srt".encode('utf8'))
+    """.format(os.path.split(srt_file.name)[1], u"å¡ž.srt".encode('utf8'))
 
     MODEL_DATA = {'data': DATA}
 
@@ -523,12 +620,12 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo):
         self.assertEqual(response.status, '400 Bad Request')
 
         # Correct case:
-        filename = os.path.split(self.non_en_file.name)[1]
-        _upload_file(self.non_en_file, self.item_descriptor.location, filename)
-        self.non_en_file.seek(0)
+        filename = os.path.split(self.srt_file.name)[1]
+        _upload_file(self.srt_file, self.item_descriptor.location, filename)
+        self.srt_file.seek(0)
         request = Request.blank(u'translation/uk?filename={}'.format(filename))
         response = self.item_descriptor.studio_transcript(request=request, dispatch='translation/uk')
-        self.assertEqual(response.body, self.non_en_file.read())
+        self.assertEqual(response.body, self.srt_file.read())
         self.assertEqual(response.headers['Content-Type'], 'application/x-subrip; charset=utf-8')
         self.assertEqual(
             response.headers['Content-Disposition'],
@@ -537,12 +634,12 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo):
         self.assertEqual(response.headers['Content-Language'], 'uk')
 
         # Non ascii file name download:
-        self.non_en_file.seek(0)
-        _upload_file(self.non_en_file, self.item_descriptor.location, u'å¡ž.srt')
-        self.non_en_file.seek(0)
+        self.srt_file.seek(0)
+        _upload_file(self.srt_file, self.item_descriptor.location, u'å¡ž.srt')
+        self.srt_file.seek(0)
         request = Request.blank('translation/zh?filename={}'.format(u'å¡ž.srt'.encode('utf8')))
         response = self.item_descriptor.studio_transcript(request=request, dispatch='translation/zh')
-        self.assertEqual(response.body, self.non_en_file.read())
+        self.assertEqual(response.body, self.srt_file.read())
         self.assertEqual(response.headers['Content-Type'], 'application/x-subrip; charset=utf-8')
         self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename="å¡ž.srt"')
         self.assertEqual(response.headers['Content-Language'], 'zh')
@@ -614,7 +711,7 @@ class TestGetTranscript(TestVideo):
     """
     Make sure that `get_transcript` method works correctly
     """
-    non_en_file = _create_srt_file()
+    srt_file = _create_srt_file()
     DATA = """
         <video show_captions="true"
         display_name="A Name"
@@ -624,7 +721,7 @@ class TestGetTranscript(TestVideo):
             <transcript language="uk" src="{}"/>
             <transcript language="zh" src="{}"/>
         </video>
-    """.format(os.path.split(non_en_file.name)[1], u"å¡ž.srt".encode('utf8'))
+    """.format(os.path.split(srt_file.name)[1], u"å¡ž.srt".encode('utf8'))
 
     MODEL_DATA = {
         'data': DATA
@@ -660,7 +757,8 @@ class TestGetTranscript(TestVideo):
         _upload_sjson_file(good_sjson, self.item.location)
         self.item.sub = _get_subs_id(good_sjson.name)
 
-        text, filename, mime_type = self.item.get_transcript()
+        transcripts = self.item.get_transcripts_info()
+        text, filename, mime_type = self.item.get_transcript(transcripts)
 
         expected_text = textwrap.dedent("""\
             0
@@ -697,7 +795,8 @@ class TestGetTranscript(TestVideo):
 
         _upload_sjson_file(good_sjson, self.item.location)
         self.item.sub = _get_subs_id(good_sjson.name)
-        text, filename, mime_type = self.item.get_transcript("txt")
+        transcripts = self.item.get_transcripts_info()
+        text, filename, mime_type = self.item.get_transcript(transcripts, transcript_format="txt")
         expected_text = textwrap.dedent("""\
             Hi, welcome to Edx.
             Let's start with what is on your screen right now.""")
@@ -708,14 +807,15 @@ class TestGetTranscript(TestVideo):
 
     def test_en_with_empty_sub(self):
 
+        transcripts = {"transcripts": {}, "sub": ""}
         # no self.sub, self.youttube_1_0 exist, but no file in assets
         with self.assertRaises(NotFoundError):
-            self.item.get_transcript()
+            self.item.get_transcript(transcripts)
 
-        # no self.sub and no self.youtube_1_0
+        # no self.sub and no self.youtube_1_0, no non-en transcritps
         self.item.youtube_id_1_0 = None
         with self.assertRaises(ValueError):
-            self.item.get_transcript()
+            self.item.get_transcript(transcripts)
 
         # no self.sub but youtube_1_0 exists with file in assets
         good_sjson = _create_file(content=textwrap.dedent("""\
@@ -737,7 +837,7 @@ class TestGetTranscript(TestVideo):
         _upload_sjson_file(good_sjson, self.item.location)
         self.item.youtube_id_1_0 = _get_subs_id(good_sjson.name)
 
-        text, filename, mime_type = self.item.get_transcript()
+        text, filename, mime_type = self.item.get_transcript(transcripts)
         expected_text = textwrap.dedent("""\
             0
             00:00:00,270 --> 00:00:02,720
@@ -755,10 +855,11 @@ class TestGetTranscript(TestVideo):
 
     def test_non_en_with_non_ascii_filename(self):
         self.item.transcript_language = 'zh'
-        self.non_en_file.seek(0)
-        _upload_file(self.non_en_file, self.item_descriptor.location, u"å¡ž.srt")
+        self.srt_file.seek(0)
+        _upload_file(self.srt_file, self.item_descriptor.location, u"å¡ž.srt")
 
-        text, filename, mime_type = self.item.get_transcript()
+        transcripts = self.item.get_transcripts_info()
+        text, filename, mime_type = self.item.get_transcript(transcripts)
         expected_text = textwrap.dedent("""
         0
         00:00:00,12 --> 00:00:00,100
@@ -774,8 +875,9 @@ class TestGetTranscript(TestVideo):
         _upload_sjson_file(good_sjson, self.item.location)
         self.item.sub = _get_subs_id(good_sjson.name)
 
+        transcripts = self.item.get_transcripts_info()
         with self.assertRaises(ValueError):
-            self.item.get_transcript()
+            self.item.get_transcript(transcripts)
 
     def test_key_error(self):
         good_sjson = _create_file(content="""
@@ -794,5 +896,6 @@ class TestGetTranscript(TestVideo):
         _upload_sjson_file(good_sjson, self.item.location)
         self.item.sub = _get_subs_id(good_sjson.name)
 
+        transcripts = self.item.get_transcripts_info()
         with self.assertRaises(KeyError):
-            self.item.get_transcript()
+            self.item.get_transcript(transcripts)
diff --git a/lms/djangoapps/courseware/tests/test_video_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py
index c9b02696f383e26545f15c7d49da3324e3a32c9c..36c1eacb2ee0e1af6710c1b8ba7bf0edb1b72133 100644
--- a/lms/djangoapps/courseware/tests/test_video_mongo.py
+++ b/lms/djangoapps/courseware/tests/test_video_mongo.py
@@ -9,8 +9,9 @@ from nose.plugins.attrib import attr
 
 from django.conf import settings
 from django.test import TestCase
+from django.test.utils import override_settings
 
-from xmodule.video_module import create_youtube_string, VideoDescriptor
+from xmodule.video_module import VideoDescriptor, bumper_utils, video_utils
 from xmodule.x_module import STUDENT_VIEW
 from xmodule.tests.test_video import VideoDescriptorTestBase
 from xmodule.tests.test_import import DummySystem
@@ -31,43 +32,51 @@ class TestVideoYouTube(TestVideo):
     def test_video_constructor(self):
         """Make sure that all parameters extracted correctly from xml"""
         context = self.item_descriptor.render(STUDENT_VIEW).content
-        sources = json.dumps([u'example.mp4', u'example.webm'])
+        sources = [u'example.mp4', u'example.webm']
 
         expected_context = {
-            'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', False),
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
             'display_name': u'A Name',
-            'end': 3610.0,
-            'id': self.item_descriptor.location.html_id(),
-            'show_captions': 'true',
-            'handout': None,
             'download_video_link': u'example.mp4',
-            'sources': sources,
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
+            'metadata': json.dumps(OrderedDict({
+                "saveStateUrl": self.item_descriptor.xmodule_runtime.ajax_url + "/save_user_state",
+                "autoplay": False,
+                "streams": "0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg",
+                "sub": "a_sub_file.srt.sjson",
+                "sources": sources,
+                "captionDataDir": None,
+                "showCaptions": "true",
+                "generalSpeed": 1.0,
+                "speed": None,
+                "savedVideoPosition": 0.0,
+                "start": 3603.0,
+                "end": 3610.0,
+                "transcriptLanguage": "en",
+                "transcriptLanguages": OrderedDict({"en": "English", "uk": u"Українська"}),
+                "ytTestTimeout": 1500,
+                "ytApiUrl": "www.youtube.com/iframe_api",
+                "ytTestUrl": "gdata.youtube.com/feeds/api/videos/",
+                "transcriptTranslationUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
+                ).rstrip('/?'),
+                "transcriptAvailableTranslationsUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'available_translations'
+                ).rstrip('/?'),
+                "autohideHtml5": False,
+            })),
             'track': None,
-            'youtube_streams': create_youtube_string(self.item_descriptor),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': json.dumps(OrderedDict({"en": "English", "uk": u"Українська"})),
-            'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'translation'
-            ).rstrip('/?'),
-            'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'available_translations'
-            ).rstrip('/?'),
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
         }
 
         self.assertEqual(
@@ -100,43 +109,51 @@ class TestVideoNonYouTube(TestVideo):
             the template generates an empty string for the YouTube streams.
         """
         context = self.item_descriptor.render(STUDENT_VIEW).content
-        sources = json.dumps([u'example.mp4', u'example.webm'])
+        sources = [u'example.mp4', u'example.webm']
 
         expected_context = {
-            'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
             'download_video_link': u'example.mp4',
-            'end': 3610.0,
+            'handout': None,
             'id': self.item_descriptor.location.html_id(),
-            'sources': sources,
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'metadata': json.dumps(OrderedDict({
+                "saveStateUrl": self.item_descriptor.xmodule_runtime.ajax_url + "/save_user_state",
+                "autoplay": False,
+                "streams": "1.00:3_yD_cEKoCk",
+                "sub": "a_sub_file.srt.sjson",
+                "sources": sources,
+                "captionDataDir": None,
+                "showCaptions": "true",
+                "generalSpeed": 1.0,
+                "speed": None,
+                "savedVideoPosition": 0.0,
+                "start": 3603.0,
+                "end": 3610.0,
+                "transcriptLanguage": "en",
+                "transcriptLanguages": OrderedDict({"en": "English"}),
+                "ytTestTimeout": 1500,
+                "ytApiUrl": "www.youtube.com/iframe_api",
+                "ytTestUrl": "gdata.youtube.com/feeds/api/videos/",
+                "transcriptTranslationUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
+                ).rstrip('/?'),
+                "transcriptAvailableTranslationsUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'available_translations'
+                ).rstrip('/?'),
+                "autohideHtml5": False,
+            })),
             'track': None,
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': '{"en": "English"}',
-            'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'translation'
-            ).rstrip('/?'),
-            'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'available_translations'
-            ).rstrip('/?')
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
         }
 
         self.assertEqual(
@@ -157,6 +174,32 @@ class TestGetHtmlMethod(BaseTestXmodule):
     def setUp(self):
         super(TestGetHtmlMethod, self).setUp()
         self.setup_course()
+        self.default_metadata_dict = OrderedDict({
+            "saveStateUrl": "",
+            "autoplay": settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
+            "streams": "1.00:3_yD_cEKoCk",
+            "sub": "a_sub_file.srt.sjson",
+            "sources": '[]',
+            "captionDataDir": None,
+            "showCaptions": "true",
+            "generalSpeed": 1.0,
+            "speed": None,
+            "savedVideoPosition": 0.0,
+            "start": 3603.0,
+            "end": 3610.0,
+            "transcriptLanguage": "en",
+            "transcriptLanguages": OrderedDict({"en": "English"}),
+            "ytTestTimeout": 1500,
+            "ytApiUrl": "www.youtube.com/iframe_api",
+            "ytTestUrl": "gdata.youtube.com/feeds/api/videos/",
+            "transcriptTranslationUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                self.item_descriptor, 'transcript', 'translation/__lang__'
+            ).rstrip('/?'),
+            "transcriptAvailableTranslationsUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                self.item_descriptor, 'transcript', 'available_translations'
+            ).rstrip('/?'),
+            "autohideHtml5": False,
+        })
 
     def test_get_html_track(self):
         SOURCE_XML = """
@@ -209,36 +252,31 @@ class TestGetHtmlMethod(BaseTestXmodule):
                 'transcripts': '<transcript language="uk" src="ukrainian.srt" />',
             },
         ]
-        sources = json.dumps([u'example.mp4', u'example.webm'])
+        sources = [u'example.mp4', u'example.webm']
 
         expected_context = {
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
             'download_video_link': u'example.mp4',
-            'end': 3610.0,
-            'id': None,
-            'sources': sources,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
-            'speed': 'null',
-            'general_speed': 1.0,
-            'track': u'http://www.example.com/track',
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
+            'metadata': '',
+            'track': None,
+            'transcript_download_format': 'srt',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
         }
 
         for data in cases:
+            metadata = self.default_metadata_dict
+            metadata['sources'] = sources
             DATA = SOURCE_XML.format(
                 download_track=data['download_track'],
                 track=data['track'],
@@ -252,22 +290,29 @@ class TestGetHtmlMethod(BaseTestXmodule):
             ).rstrip('/?')
 
             context = self.item_descriptor.render(STUDENT_VIEW).content
-
-            expected_context.update({
-                'transcript_download_format': None if self.item_descriptor.track and self.item_descriptor.download_track else 'srt',
-                'transcript_languages': '{"en": "English"}' if not data['transcripts'] else json.dumps({"uk": u'Українська'}),
-                'transcript_language': u'en' if not data['transcripts'] or data.get('sub') else u'uk',
-                'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                    self.item_descriptor, 'transcript', 'translation'
+            metadata.update({
+                'transcriptLanguages': {"en": "English"} if not data['transcripts'] else {"uk": u'Українська'},
+                'transcriptLanguage': u'en' if not data['transcripts'] or data.get('sub') else u'uk',
+                'transcriptTranslationUrl': self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
                 ).rstrip('/?'),
-                'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
+                'transcriptAvailableTranslationsUrl': self.item_descriptor.xmodule_runtime.handler_url(
                     self.item_descriptor, 'transcript', 'available_translations'
                 ).rstrip('/?'),
-                'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
-                'track': track_url if data['expected_track_url'] == u'a_sub_file.srt.sjson' else data['expected_track_url'],
+                'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
                 'sub': data['sub'],
+            })
+            expected_context.update({
+                'transcript_download_format': (
+                    None if self.item_descriptor.track and self.item_descriptor.download_track else 'srt'
+                ),
+                'track': (
+                    track_url if data['expected_track_url'] == u'a_sub_file.srt.sjson' else data['expected_track_url']
+                ),
                 'id': self.item_descriptor.location.html_id(),
+                'metadata': json.dumps(metadata)
             })
+
             self.assertEqual(
                 context,
                 self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context),
@@ -295,7 +340,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
                 """,
                 'result': {
                     'download_video_link': u'example_source.mp4',
-                    'sources': json.dumps([u'example.mp4', u'example.webm']),
+                    'sources': [u'example.mp4', u'example.webm'],
                 },
             },
             {
@@ -307,7 +352,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
                 """,
                 'result': {
                     'download_video_link': u'example.mp4',
-                    'sources': json.dumps([u'example.mp4', u'example.webm']),
+                    'sources': [u'example.mp4', u'example.webm'],
                 },
             },
             {
@@ -326,7 +371,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
                     <source src="example.webm"/>
                 """,
                 'result': {
-                    'sources': json.dumps([u'example.mp4', u'example.webm']),
+                    'sources': [u'example.mp4', u'example.webm'],
                 },
             },
         ]
@@ -334,31 +379,21 @@ class TestGetHtmlMethod(BaseTestXmodule):
         initial_context = {
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
-            'download_video_link': None,
-            'end': 3610.0,
-            'id': None,
-            'sources': '[]',
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'download_video_link': u'example.mp4',
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
+            'metadata': self.default_metadata_dict,
             'track': None,
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': '{"en": "English"}',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
         }
 
         for data in cases:
@@ -371,17 +406,21 @@ class TestGetHtmlMethod(BaseTestXmodule):
             context = self.item_descriptor.render(STUDENT_VIEW).content
 
             expected_context = dict(initial_context)
-            expected_context.update({
-                'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                    self.item_descriptor, 'transcript', 'translation'
+            expected_context['metadata'].update({
+                'transcriptTranslationUrl': self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
                 ).rstrip('/?'),
-                'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
+                'transcriptAvailableTranslationsUrl': self.item_descriptor.xmodule_runtime.handler_url(
                     self.item_descriptor, 'transcript', 'available_translations'
                 ).rstrip('/?'),
-                'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+                'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+                'sources': data['result'].get('sources', []),
+            })
+            expected_context.update({
                 'id': self.item_descriptor.location.html_id(),
+                'download_video_link': data['result'].get('download_video_link'),
+                'metadata': json.dumps(expected_context['metadata'])
             })
-            expected_context.update(data['result'])
 
             self.assertEqual(
                 context,
@@ -413,7 +452,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
             'edx_video_id': "meow",
             'result': {
                 'download_video_link': u'example_source.mp4',
-                'sources': json.dumps([u'example.mp4', u'example.webm']),
+                'sources': [u'example.mp4', u'example.webm'],
             }
         }
         DATA = SOURCE_XML.format(
@@ -469,39 +508,32 @@ class TestGetHtmlMethod(BaseTestXmodule):
             'result': {
                 'download_video_link': None,
                 # make sure the desktop_mp4 url is included as part of the alternative sources.
-                'sources': json.dumps([u'example.mp4', u'example.webm', u'http://www.meowmix.com']),
+                'sources': [u'example.mp4', u'example.webm', u'http://www.meowmix.com'],
             }
         }
 
         # Video found for edx_video_id
+        metadata = self.default_metadata_dict
+        metadata['autoplay'] = False
+        metadata['sources'] = ""
         initial_context = {
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
-            'download_video_link': None,
-            'end': 3610.0,
-            'id': None,
-            'sources': '[]',
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'download_video_link': u'example.mp4',
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
             'track': None,
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': '{"en": "English"}',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
+            'metadata': metadata
         }
 
         DATA = SOURCE_XML.format(
@@ -514,17 +546,21 @@ class TestGetHtmlMethod(BaseTestXmodule):
         context = self.item_descriptor.render(STUDENT_VIEW).content
 
         expected_context = dict(initial_context)
-        expected_context.update({
-            'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'translation'
+        expected_context['metadata'].update({
+            'transcriptTranslationUrl': self.item_descriptor.xmodule_runtime.handler_url(
+                self.item_descriptor, 'transcript', 'translation/__lang__'
             ).rstrip('/?'),
-            'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
+            'transcriptAvailableTranslationsUrl': self.item_descriptor.xmodule_runtime.handler_url(
                 self.item_descriptor, 'transcript', 'available_translations'
             ).rstrip('/?'),
-            'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+            'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+            'sources': data['result']['sources'],
+        })
+        expected_context.update({
             'id': self.item_descriptor.location.html_id(),
+            'download_video_link': data['result']['download_video_link'],
+            'metadata': json.dumps(expected_context['metadata'])
         })
-        expected_context.update(data['result'])
 
         self.assertEqual(
             context,
@@ -579,42 +615,32 @@ class TestGetHtmlMethod(BaseTestXmodule):
             'result': {
                 'download_video_link': u'http://fake-video.edx.org/thundercats.mp4',
                 # make sure the urls for the various encodings are included as part of the alternative sources.
-                'sources': json.dumps(
-                    [u'example.mp4', u'example.webm'] +
-                    [video['url'] for video in encoded_videos]
-                ),
+                'sources': [u'example.mp4', u'example.webm'] +
+                           [video['url'] for video in encoded_videos],
             }
         }
 
         # Video found for edx_video_id
+        metadata = self.default_metadata_dict
+        metadata['sources'] = ""
         initial_context = {
             'branding_info': None,
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
-            'download_video_link': None,
-            'end': 3610.0,
-            'id': None,
-            'sources': '[]',
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'download_video_link': u'example.mp4',
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
             'track': None,
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': '{"en": "English"}',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
+            'metadata': metadata,
         }
 
         DATA = SOURCE_XML.format(
@@ -627,17 +653,21 @@ class TestGetHtmlMethod(BaseTestXmodule):
         context = self.item_descriptor.render(STUDENT_VIEW).content
 
         expected_context = dict(initial_context)
-        expected_context.update({
-            'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                self.item_descriptor, 'transcript', 'translation'
+        expected_context['metadata'].update({
+            'transcriptTranslationUrl': self.item_descriptor.xmodule_runtime.handler_url(
+                self.item_descriptor, 'transcript', 'translation/__lang__'
             ).rstrip('/?'),
-            'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
+            'transcriptAvailableTranslationsUrl': self.item_descriptor.xmodule_runtime.handler_url(
                 self.item_descriptor, 'transcript', 'available_translations'
             ).rstrip('/?'),
-            'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+            'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+            'sources': data['result']['sources'],
+        })
+        expected_context.update({
             'id': self.item_descriptor.location.html_id(),
+            'download_video_link': data['result']['download_video_link'],
+            'metadata': json.dumps(expected_context['metadata'])
         })
-        expected_context.update(data['result'])
 
         self.assertEqual(
             context,
@@ -690,12 +720,10 @@ class TestGetHtmlMethod(BaseTestXmodule):
             """,
             'result': {
                 'download_video_link': u'example_source.mp4',
-                'sources': json.dumps(
-                    [
-                        u'http://cdn_example.com/example.mp4',
-                        u'http://cdn_example.com/example.webm'
-                    ]
-                ),
+                'sources': [
+                    u'http://cdn_example.com/example.mp4',
+                    u'http://cdn_example.com/example.webm'
+                ],
             },
         }
 
@@ -712,31 +740,21 @@ class TestGetHtmlMethod(BaseTestXmodule):
                 'url': 'http://www.xuetangx.com'
             },
             'license': None,
+            'bumper_metadata': 'null',
             'cdn_eval': False,
             'cdn_exp_group': None,
-            'data_dir': getattr(self, 'data_dir', None),
-            'show_captions': 'true',
-            'handout': None,
             'display_name': u'A Name',
             'download_video_link': None,
-            'end': 3610.0,
+            'handout': None,
             'id': None,
-            'sources': '[]',
-            'speed': 'null',
-            'general_speed': 1.0,
-            'start': 3603.0,
-            'saved_video_position': 0.0,
-            'sub': u'a_sub_file.srt.sjson',
+            'metadata': self.default_metadata_dict,
             'track': None,
-            'youtube_streams': '1.00:3_yD_cEKoCk',
-            'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True),
-            'yt_test_timeout': 1500,
-            'yt_api_url': 'www.youtube.com/iframe_api',
-            'yt_test_url': 'gdata.youtube.com/feeds/api/videos/',
             'transcript_download_format': 'srt',
-            'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}],
-            'transcript_language': u'en',
-            'transcript_languages': '{"en": "English"}',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': 'null',
         }
 
         for data in cases:
@@ -748,21 +766,23 @@ class TestGetHtmlMethod(BaseTestXmodule):
             )
             self.initialize_module(data=DATA)
             self.item_descriptor.xmodule_runtime.user_location = 'CN'
-
             context = self.item_descriptor.render('student_view').content
-
             expected_context = dict(initial_context)
-            expected_context.update({
-                'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url(
-                    self.item_descriptor, 'transcript', 'translation'
+            expected_context['metadata'].update({
+                'transcriptTranslationUrl': self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
                 ).rstrip('/?'),
-                'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url(
+                'transcriptAvailableTranslationsUrl': self.item_descriptor.xmodule_runtime.handler_url(
                     self.item_descriptor, 'transcript', 'available_translations'
                 ).rstrip('/?'),
-                'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+                'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+                'sources': data['result'].get('sources', []),
+            })
+            expected_context.update({
                 'id': self.item_descriptor.location.html_id(),
+                'download_video_link': data['result'].get('download_video_link'),
+                'metadata': json.dumps(expected_context['metadata'])
             })
-            expected_context.update(data['result'])
 
             self.assertEqual(
                 context,
@@ -948,3 +968,125 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
             VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
         with self.assertRaises(ValVideoNotFoundError):
             get_video_info("test_edx_video_id")
+
+
+class TestVideoWithBumper(TestVideo):
+    """
+    Tests rendered content in presence of video bumper.
+    """
+    CATEGORY = "video"
+    METADATA = {}
+    FEATURES = settings.FEATURES
+
+    @patch('xmodule.video_module.bumper_utils.get_bumper_settings')
+    def test_is_bumper_enabled(self, get_bumper_settings):
+        """
+        Check that bumper is (not)shown if ENABLE_VIDEO_BUMPER is (False)True
+
+        Assume that bumper settings are correct.
+        """
+        self.FEATURES.update({
+            "SHOW_BUMPER_PERIODICITY": 1,
+            "ENABLE_VIDEO_BUMPER": True,
+        })
+
+        get_bumper_settings.return_value = {
+            "video_id": "edx_video_id",
+            "transcripts": {},
+        }
+        with override_settings(FEATURES=self.FEATURES):
+            self.assertTrue(bumper_utils.is_bumper_enabled(self.item_descriptor))
+
+        self.FEATURES.update({"ENABLE_VIDEO_BUMPER": False})
+
+        with override_settings(FEATURES=self.FEATURES):
+            self.assertFalse(bumper_utils.is_bumper_enabled(self.item_descriptor))
+
+    @patch('xmodule.video_module.bumper_utils.is_bumper_enabled')
+    @patch('xmodule.video_module.bumper_utils.get_bumper_settings')
+    @patch('edxval.api.get_urls_for_profiles')
+    def test_bumper_metadata(self, get_url_for_profiles, get_bumper_settings, is_bumper_enabled):
+        """
+        Test content with rendered bumper metadata.
+        """
+        get_url_for_profiles.return_value = {
+            "desktop_mp4": "http://test_bumper.mp4",
+            "desktop_webm": "",
+        }
+
+        get_bumper_settings.return_value = {
+            "video_id": "edx_video_id",
+            "transcripts": {},
+        }
+
+        is_bumper_enabled.return_value = True
+
+        content = self.item_descriptor.render(STUDENT_VIEW).content
+        sources = [u'example.mp4', u'example.webm']
+        expected_context = {
+            'branding_info': None,
+            'license': None,
+            'bumper_metadata': json.dumps(OrderedDict({
+                'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+                "showCaptions": "true",
+                "sources": ["http://test_bumper.mp4"],
+                'streams': '',
+                "transcriptLanguage": "en",
+                "transcriptLanguages": {"en": "English"},
+                "transcriptTranslationUrl": video_utils.set_query_parameter(
+                    self.item_descriptor.xmodule_runtime.handler_url(
+                        self.item_descriptor, 'transcript', 'translation/__lang__'
+                    ).rstrip('/?'), 'is_bumper', 1
+                ),
+                "transcriptAvailableTranslationsUrl": video_utils.set_query_parameter(
+                    self.item_descriptor.xmodule_runtime.handler_url(
+                        self.item_descriptor, 'transcript', 'available_translations'
+                    ).rstrip('/?'), 'is_bumper', 1
+                ),
+            })),
+            'cdn_eval': False,
+            'cdn_exp_group': None,
+            'display_name': u'A Name',
+            'download_video_link': u'example.mp4',
+            'handout': None,
+            'id': self.item_descriptor.location.html_id(),
+            'metadata': json.dumps(OrderedDict({
+                "saveStateUrl": self.item_descriptor.xmodule_runtime.ajax_url + "/save_user_state",
+                "autoplay": False,
+                "streams": "0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg",
+                "sub": "a_sub_file.srt.sjson",
+                "sources": sources,
+                "captionDataDir": None,
+                "showCaptions": "true",
+                "generalSpeed": 1.0,
+                "speed": None,
+                "savedVideoPosition": 0.0,
+                "start": 3603.0,
+                "end": 3610.0,
+                "transcriptLanguage": "en",
+                "transcriptLanguages": OrderedDict({"en": "English", "uk": u"Українська"}),
+                "ytTestTimeout": 1500,
+                "ytApiUrl": "www.youtube.com/iframe_api",
+                "ytTestUrl": "gdata.youtube.com/feeds/api/videos/",
+                "transcriptTranslationUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'translation/__lang__'
+                ).rstrip('/?'),
+                "transcriptAvailableTranslationsUrl": self.item_descriptor.xmodule_runtime.handler_url(
+                    self.item_descriptor, 'transcript', 'available_translations'
+                ).rstrip('/?'),
+                "autohideHtml5": False,
+            })),
+            'track': None,
+            'transcript_download_format': 'srt',
+            'transcript_download_formats_list': [
+                {'display_name': 'SubRip (.srt) file', 'value': 'srt'},
+                {'display_name': 'Text (.txt) file', 'value': 'txt'}
+            ],
+            'poster': json.dumps(OrderedDict({
+                "url": "http://img.youtube.com/vi/ZwkTiUPN0mg/0.jpg",
+                "type": "youtube"
+            }))
+        }
+
+        expected_content = self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context)
+        self.assertEqual(content, expected_content)
diff --git a/lms/djangoapps/mobile_api/video_outlines/serializers.py b/lms/djangoapps/mobile_api/video_outlines/serializers.py
index 73f7089df695b7ea37a2bb4554dd03cfa1141b42..167abf3e23dca2becf0d6da5119ee050a101674f 100644
--- a/lms/djangoapps/mobile_api/video_outlines/serializers.py
+++ b/lms/djangoapps/mobile_api/video_outlines/serializers.py
@@ -206,7 +206,8 @@ def video_summary(video_profiles, course_id, video_descriptor, request, local_ca
     size = default_encoded_video.get('file_size', 0)
 
     # Transcripts...
-    transcript_langs = video_descriptor.available_translations(verify_assets=False)
+    transcripts_info = video_descriptor.get_transcripts_info()
+    transcript_langs = video_descriptor.available_translations(transcripts_info, verify_assets=False)
 
     transcripts = {
         lang: reverse(
@@ -227,7 +228,7 @@ def video_summary(video_profiles, course_id, video_descriptor, request, local_ca
         "duration": duration,
         "size": size,
         "transcripts": transcripts,
-        "language": video_descriptor.get_default_transcript_language(),
+        "language": video_descriptor.get_default_transcript_language(transcripts_info),
         "encoded_videos": video_data.get('profiles')
     }
     ret.update(always_available_data)
diff --git a/lms/djangoapps/mobile_api/video_outlines/views.py b/lms/djangoapps/mobile_api/video_outlines/views.py
index ae1d7361c6a363e973c5e39848fb60624b990cb9..f0a25a77af84095a385147ccf974e0b226eb1281 100644
--- a/lms/djangoapps/mobile_api/video_outlines/views.py
+++ b/lms/djangoapps/mobile_api/video_outlines/views.py
@@ -119,7 +119,8 @@ class VideoTranscripts(generics.RetrieveAPIView):
         )
         try:
             video_descriptor = modulestore().get_item(usage_key)
-            content, filename, mimetype = video_descriptor.get_transcript(lang=lang)
+            transcripts = video_descriptor.get_transcripts_info()
+            content, filename, mimetype = video_descriptor.get_transcript(transcripts, lang=lang)
         except (NotFoundError, ValueError, KeyError):
             raise Http404(u"Transcript not found for {}, lang: {}".format(block_id, lang))
 
diff --git a/lms/envs/bok_choy.py b/lms/envs/bok_choy.py
index 3a1c1a450ede47c905f4074704433a736e63ecd6..ce93aac8da5f9dcaa91def1de145a550df1bb9f2 100644
--- a/lms/envs/bok_choy.py
+++ b/lms/envs/bok_choy.py
@@ -123,6 +123,11 @@ FEATURES['ENABLE_MAX_FAILED_LOGIN_ATTEMPTS'] = False
 FEATURES['SQUELCH_PII_IN_LOGS'] = False
 FEATURES['PREVENT_CONCURRENT_LOGINS'] = False
 FEATURES['ADVANCED_SECURITY'] = False
+
+FEATURES['ENABLE_MOBILE_REST_API'] = True  # Show video bumper in LMS
+FEATURES['ENABLE_VIDEO_BUMPER'] = True  # Show video bumper in LMS
+FEATURES['SHOW_BUMPER_PERIODICITY'] = 1
+
 PASSWORD_MIN_LENGTH = None
 PASSWORD_COMPLEXITY = {}
 
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 3e0d69b7d0c8a7db9da4f46fc7faf348a6f2b25f..74dac034260ef0f585b18945406e86b0a965871f 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -392,6 +392,13 @@ FEATURES = {
 
     # Teams feature
     'ENABLE_TEAMS': False,
+
+    # Show video bumper in LMS
+    'ENABLE_VIDEO_BUMPER': False,
+
+    # How many seconds to show the bumper again, default is 7 days:
+    'SHOW_BUMPER_PERIODICITY': 7 * 24 * 3600,
+
 }
 
 # Ignore static asset files on import which match this pattern
@@ -1665,6 +1672,8 @@ YOUTUBE = {
             'v': 'set_youtube_id_of_11_symbols_here',
         },
     },
+
+    'IMAGE_API': 'http://img.youtube.com/vi/{youtube_id}/0.jpg',  # /maxresdefault.jpg for 1920*1080
 }
 
 ################################### APPS ######################################
diff --git a/lms/templates/video.html b/lms/templates/video.html
index 9936b97b7d4be0a418f28399ee81ca3fe13872f4..48c069a8739a4a099de8b259b0a4597271ce4f35 100644
--- a/lms/templates/video.html
+++ b/lms/templates/video.html
@@ -7,47 +7,9 @@
 <div
     id="video_${id}"
     class="video closed"
-
-    data-streams="${youtube_streams}"
-
-    % if sub:
-      data-sub="${sub}"
-    % endif
-    % if autoplay:
-      data-autoplay="${autoplay}"
-    % endif
-
-    data-sources='${sources}'
-    data-save-state-url="${ajax_url}"
-    data-caption-data-dir="${data_dir}"
-    data-show-captions="${show_captions}"
-    data-general-speed="${general_speed}"
-    data-speed="${speed}"
-    data-saved-video-position="${saved_video_position}"
-    data-start="${start}"
-    data-end="${end}"
-    data-transcript-language="${transcript_language}"
-    data-transcript-languages='${transcript_languages}'
-    data-autoplay="${autoplay}"
-    data-yt-test-timeout="${yt_test_timeout}"
-    data-yt-api-url="${yt_api_url}"
-    data-yt-test-url="${yt_test_url}"
-    data-transcript-translation-url="${transcript_translation_url}"
-    data-transcript-available-translations-url="${transcript_available_translations_url}"
-
-    ## For now, the option "data-autohide-html5" is hard coded. This option
-    ## either enables or disables autohiding of controls and captions on mouse
-    ## inactivity. If set to true, controls and captions will autohide for
-    ## HTML5 sources (non-YouTube) after a period of mouse inactivity over the
-    ## whole video. When the mouse moves (or a key is pressed while any part of
-    ## the video player is focused), the captions and controls will be shown
-    ## once again.
-    ##
-    ## There is no option in the "Advanced Editor" to set this option. However,
-    ## this option will have an effect if changed to "True". The code on
-    ## front-end exists.
-    data-autohide-html5="False"
-
+    data-metadata='${metadata}'
+    data-bumper-metadata='${bumper_metadata}'
+    data-poster='${poster}'
     tabindex="-1"
 >
     <div class="focus_grabber first"></div>
@@ -65,41 +27,13 @@
           </section>
           <div class="video-player-post"></div>
           <section class="video-controls is-hidden">
-              <div class="slider" title="${_('Video position')}"></div>
               <div>
-                  <ul class="vcr">
-                      <li><a class="video_control" href="#" title="${_('Play')}" role="button" aria-disabled="false"></a></li>
-                      <li><div class="vidtime">0:00 / 0:00</div></li>
-                  </ul>
-                  <div class="secondary-controls">
-                      <div class="speeds menu-container">
-                          <a class="speed-button" href="#" title="${_('Speeds')}" role="button" aria-disabled="false">
-                              <span class="label">${_('Speed')}</span>
-                              <span class="value"></span>
-                          </a>
-                          <ol class="video-speeds menu" role="menu"></ol>
-                      </div>
-                      <div class="volume">
-                          <a href="#" role="button" aria-disabled="false" title="${_('Volume')}" aria-label="${_('Click on this button to mute or unmute this video or press UP or DOWN buttons to increase or decrease volume level.')}"></a>
-                          <div role="presentation" class="volume-slider-container">
-                              <div class="volume-slider"></div>
-                          </div>
-                      </div>
-                      <a href="#" class="add-fullscreen" title="${_('Fill browser')}" role="button" aria-disabled="false">${_('Fill browser')}</a>
-                      <a href="#" class="quality-control is-hidden" title="${_('HD off')}" role="button" aria-disabled="false">${_('HD off')}</a>
-
-                      <div class="lang menu-container">
-                        <a href="#" class="hide-subtitles" title="${_('Turn off captions')}" role="button" aria-disabled="false">${_('Turn off captions')}</a>
-                      </div>
-                  </div>
+                  <div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
+                  <div class="secondary-controls"></div>
               </div>
           </section>
           <a class="nav-skip sr" id="before-transcript_${id}" href="#after-transcript_${id}">${_('Skip to end of transcript.')}</a>
       </article>
-
-      <ol id="transcript-captions" class="subtitles" tabindex="0" role="group" aria-label="${_('Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.')}">
-        <li></li>
-      </ol>
     </div>
 
     <a class="nav-skip sr" id="after-transcript_${id}" href="#before-transcript_${id}">${_('Go back to start of transcript.')}</a>
@@ -116,8 +50,8 @@
           % if transcript_download_format:
             <a href="${track}">${_('Download transcript')}</a>
             <div class="a11y-menu-container">
-                <a class="a11y-menu-button" href="#" title="${'.' + transcript_download_format}">${'.' + transcript_download_format}</a>
-                <ol class="a11y-menu-list">
+                <a class="a11y-menu-button" href="#" title="${'.' + transcript_download_format}" role="button" aria-disabled="false">${'.' + transcript_download_format}</a>
+                <ol class="a11y-menu-list" role="menu">
                 % for item in transcript_download_formats_list:
                   % if item['value'] == transcript_download_format:
                   <li class="a11y-menu-item active">
@@ -126,7 +60,7 @@
                   % endif
                   ## This is necessary so we don't scrape 'display_name' as a string.
                   <% dname = item['display_name'] %>
-                      <a class="a11y-menu-item-link" href="#${item['value']}" title="${_(dname)}" data-value="${item['value']}">
+                      <a class="a11y-menu-item-link" href="#${item['value']}" title="${_(dname)}" data-value="${item['value']}" role="menuitem" aria-disabled="false">
                         ${_(dname)}
                       </a>
                   </li>