diff --git a/CHANGELOG.md b/CHANGELOG.md index 7841542046..71b3a06e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ LifterLMS Changelog =================== +v3.19.4 - 2018-06-?? +-------------------- + ++ Add subscription event on builder to allow integrations to run custom code on heartbeat ticks + + v3.19.3 - 2018-06-14 -------------------- diff --git a/assets/js/builder/Controllers/Sync.js b/assets/js/builder/Controllers/Sync.js index eb43582195..16db93f1c6 100644 --- a/assets/js/builder/Controllers/Sync.js +++ b/assets/js/builder/Controllers/Sync.js @@ -1,7 +1,7 @@ /** * Sync builder data to the server * @since 3.16.0 - * @version 3.17.1 + * @version [version] */ define( [], function() { @@ -312,10 +312,12 @@ define( [], function() { * @param obj data data set that was processed by the server * @return void * @since 3.16.11 - * @version 3.16.6 + * @version [version] */ function maybe_restart_tracking( model, data ) { + Backbone.pubSub.trigger( model.get( 'type' ) + '-maybe-restart-tracking', model, data ); + var omit = [ 'id', 'orig_id' ]; if ( model.get_relationships ) { diff --git a/assets/js/llms-builder.js b/assets/js/llms-builder.js index 935765d6cd..8a28378e89 100644 --- a/assets/js/llms-builder.js +++ b/assets/js/llms-builder.js @@ -6159,6 +6159,8 @@ define( 'Controllers/Sync',[], function() { */ function maybe_restart_tracking( model, data ) { + Backbone.pubSub.trigger( model.get( 'type' ) + '-maybe-restart-tracking', model, data ); + var omit = [ 'id', 'orig_id' ]; if ( model.get_relationships ) { diff --git a/assets/js/llms-builder.js.map b/assets/js/llms-builder.js.map index b46747d0cf..ec8e0076a5 100644 --- a/assets/js/llms-builder.js.map +++ b/assets/js/llms-builder.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../config-wrap-start-default.js","vendor/almond.js","underscore.js","backbone.js","jquery.js","vendor/backbone.collectionView.js","vendor/backbone.trackit.js","Models/Image.js","Models/_Relationships.js","Models/QuestionChoice.js","Collections/QuestionChoices.js","Models/QuestionType.js","Models/Question.js","Collections/Questions.js","Models/_Utilities.js","Schemas/Quiz.js","Models/Quiz.js","Schemas/Lesson.js","Models/Lesson.js","Collections/Lessons.js","Collections/QuestionTypes.js","Models/Section.js","Collections/Sections.js","Collections/loader.js","Models/Abstract.js","Models/Course.js","Models/loader.js","Views/_Detachable.js","Views/_Editable.js","Views/_Receivable.js","Views/_Shiftable.js","Views/_Subview.js","Views/_Trashable.js","Views/_loader.js","Controllers/Construct.js","Controllers/Debug.js","Controllers/Schemas.js","Controllers/Sync.js","Views/Lesson.js","Views/LessonList.js","Views/Section.js","Views/SectionList.js","Views/Course.js","Views/SettingsFields.js","Views/LessonEditor.js","Views/Popover.js","Views/PostSearch.js","Views/QuestionType.js","Views/QuestionBank.js","Views/QuestionChoice.js","Views/QuestionChoiceList.js","Views/Question.js","Views/QuestionList.js","Views/Quiz.js","Views/Assignment.js","Views/Editor.js","Views/Elements.js","Views/Utilities.js","Views/Sidebar.js","main.js","../../../config-wrap-end-default.js"],"names":[],"mappings":"AAAA;AACA,ACDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACrbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC72CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACvMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACtJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1WA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACtOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9QA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACvKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3nBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC5LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACnDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1tBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC1FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACzIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACzGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACxZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/TA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC3KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACjFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AChUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClKA;AACA","file":"llms-builder.js","sourcesContent":["(function($){\n","/**\n * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.\n * Released under MIT license, http://github.com/requirejs/almond/LICENSE\n */\n//Going sloppy to avoid 'use strict' string cost, but strict practices should\n//be followed.\n/*global setTimeout: false */\n\nvar requirejs, require, define;\n(function (undef) {\n\tvar main, req, makeMap, handlers,\n\t\tdefined = {},\n\t\twaiting = {},\n\t\tconfig = {},\n\t\tdefining = {},\n\t\thasOwn = Object.prototype.hasOwnProperty,\n\t\taps = [].slice,\n\t\tjsSuffixRegExp = /\\.js$/;\n\n\tfunction hasProp(obj, prop) {\n\t\treturn hasOwn.call(obj, prop);\n\t}\n\n\t/**\n\t * Given a relative module name, like ./something, normalize it to\n\t * a real name that can be mapped to a path.\n\t * @param {String} name the relative name\n\t * @param {String} baseName a real name that the name arg is relative\n\t * to.\n\t * @returns {String} normalized name\n\t */\n\tfunction normalize(name, baseName) {\n\t\tvar nameParts, nameSegment, mapValue, foundMap, lastIndex,\n\t\t\tfoundI, foundStarMap, starI, i, j, part, normalizedBaseParts,\n\t\t\tbaseParts = baseName && baseName.split(\"/\"),\n\t\t\tmap = config.map,\n\t\t\tstarMap = (map && map['*']) || {};\n\n\t\t//Adjust any relative paths.\n\t\tif (name) {\n\t\t\tname = name.split('/');\n\t\t\tlastIndex = name.length - 1;\n\n\t\t\t// If wanting node ID compatibility, strip .js from end\n\t\t\t// of IDs. Have to do this here, and not in nameToUrl\n\t\t\t// because node allows either .js or non .js to map\n\t\t\t// to same file.\n\t\t\tif (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {\n\t\t\t\tname[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');\n\t\t\t}\n\n\t\t\t// Starts with a '.' so need the baseName\n\t\t\tif (name[0].charAt(0) === '.' && baseParts) {\n\t\t\t\t//Convert baseName to array, and lop off the last part,\n\t\t\t\t//so that . matches that 'directory' and not name of the baseName's\n\t\t\t\t//module. For instance, baseName of 'one/two/three', maps to\n\t\t\t\t//'one/two/three.js', but we want the directory, 'one/two' for\n\t\t\t\t//this normalization.\n\t\t\t\tnormalizedBaseParts = baseParts.slice(0, baseParts.length - 1);\n\t\t\t\tname = normalizedBaseParts.concat(name);\n\t\t\t}\n\n\t\t\t//start trimDots\n\t\t\tfor (i = 0; i < name.length; i++) {\n\t\t\t\tpart = name[i];\n\t\t\t\tif (part === '.') {\n\t\t\t\t\tname.splice(i, 1);\n\t\t\t\t\ti -= 1;\n\t\t\t\t} else if (part === '..') {\n\t\t\t\t\t// If at the start, or previous value is still ..,\n\t\t\t\t\t// keep them so that when converted to a path it may\n\t\t\t\t\t// still work when converted to a path, even though\n\t\t\t\t\t// as an ID it is less than ideal. In larger point\n\t\t\t\t\t// releases, may be better to just kick out an error.\n\t\t\t\t\tif (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else if (i > 0) {\n\t\t\t\t\t\tname.splice(i - 1, 2);\n\t\t\t\t\t\ti -= 2;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t//end trimDots\n\n\t\t\tname = name.join('/');\n\t\t}\n\n\t\t//Apply map config if available.\n\t\tif ((baseParts || starMap) && map) {\n\t\t\tnameParts = name.split('/');\n\n\t\t\tfor (i = nameParts.length; i > 0; i -= 1) {\n\t\t\t\tnameSegment = nameParts.slice(0, i).join(\"/\");\n\n\t\t\t\tif (baseParts) {\n\t\t\t\t\t//Find the longest baseName segment match in the config.\n\t\t\t\t\t//So, do joins on the biggest to smallest lengths of baseParts.\n\t\t\t\t\tfor (j = baseParts.length; j > 0; j -= 1) {\n\t\t\t\t\t\tmapValue = map[baseParts.slice(0, j).join('/')];\n\n\t\t\t\t\t\t//baseName segment has config, find if it has one for\n\t\t\t\t\t\t//this name.\n\t\t\t\t\t\tif (mapValue) {\n\t\t\t\t\t\t\tmapValue = mapValue[nameSegment];\n\t\t\t\t\t\t\tif (mapValue) {\n\t\t\t\t\t\t\t\t//Match, update name to the new value.\n\t\t\t\t\t\t\t\tfoundMap = mapValue;\n\t\t\t\t\t\t\t\tfoundI = i;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (foundMap) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t//Check for a star map match, but just hold on to it,\n\t\t\t\t//if there is a shorter segment match later in a matching\n\t\t\t\t//config, then favor over this star map.\n\t\t\t\tif (!foundStarMap && starMap && starMap[nameSegment]) {\n\t\t\t\t\tfoundStarMap = starMap[nameSegment];\n\t\t\t\t\tstarI = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!foundMap && foundStarMap) {\n\t\t\t\tfoundMap = foundStarMap;\n\t\t\t\tfoundI = starI;\n\t\t\t}\n\n\t\t\tif (foundMap) {\n\t\t\t\tnameParts.splice(0, foundI, foundMap);\n\t\t\t\tname = nameParts.join('/');\n\t\t\t}\n\t\t}\n\n\t\treturn name;\n\t}\n\n\tfunction makeRequire(relName, forceSync) {\n\t\treturn function () {\n\t\t\t//A version of a require function that passes a moduleName\n\t\t\t//value for items that may need to\n\t\t\t//look up paths relative to the moduleName\n\t\t\tvar args = aps.call(arguments, 0);\n\n\t\t\t//If first arg is not require('string'), and there is only\n\t\t\t//one arg, it is the array form without a callback. Insert\n\t\t\t//a null so that the following concat is correct.\n\t\t\tif (typeof args[0] !== 'string' && args.length === 1) {\n\t\t\t\targs.push(null);\n\t\t\t}\n\t\t\treturn req.apply(undef, args.concat([relName, forceSync]));\n\t\t};\n\t}\n\n\tfunction makeNormalize(relName) {\n\t\treturn function (name) {\n\t\t\treturn normalize(name, relName);\n\t\t};\n\t}\n\n\tfunction makeLoad(depName) {\n\t\treturn function (value) {\n\t\t\tdefined[depName] = value;\n\t\t};\n\t}\n\n\tfunction callDep(name) {\n\t\tif (hasProp(waiting, name)) {\n\t\t\tvar args = waiting[name];\n\t\t\tdelete waiting[name];\n\t\t\tdefining[name] = true;\n\t\t\tmain.apply(undef, args);\n\t\t}\n\n\t\tif (!hasProp(defined, name) && !hasProp(defining, name)) {\n\t\t\tthrow new Error('No ' + name);\n\t\t}\n\t\treturn defined[name];\n\t}\n\n\t//Turns a plugin!resource to [plugin, resource]\n\t//with the plugin being undefined if the name\n\t//did not have a plugin prefix.\n\tfunction splitPrefix(name) {\n\t\tvar prefix,\n\t\t\tindex = name ? name.indexOf('!') : -1;\n\t\tif (index > -1) {\n\t\t\tprefix = name.substring(0, index);\n\t\t\tname = name.substring(index + 1, name.length);\n\t\t}\n\t\treturn [prefix, name];\n\t}\n\n\t//Creates a parts array for a relName where first part is plugin ID,\n\t//second part is resource ID. Assumes relName has already been normalized.\n\tfunction makeRelParts(relName) {\n\t\treturn relName ? splitPrefix(relName) : [];\n\t}\n\n\t/**\n\t * Makes a name map, normalizing the name, and using a plugin\n\t * for normalization if necessary. Grabs a ref to plugin\n\t * too, as an optimization.\n\t */\n\tmakeMap = function (name, relParts) {\n\t\tvar plugin,\n\t\t\tparts = splitPrefix(name),\n\t\t\tprefix = parts[0],\n\t\t\trelResourceName = relParts[1];\n\n\t\tname = parts[1];\n\n\t\tif (prefix) {\n\t\t\tprefix = normalize(prefix, relResourceName);\n\t\t\tplugin = callDep(prefix);\n\t\t}\n\n\t\t//Normalize according\n\t\tif (prefix) {\n\t\t\tif (plugin && plugin.normalize) {\n\t\t\t\tname = plugin.normalize(name, makeNormalize(relResourceName));\n\t\t\t} else {\n\t\t\t\tname = normalize(name, relResourceName);\n\t\t\t}\n\t\t} else {\n\t\t\tname = normalize(name, relResourceName);\n\t\t\tparts = splitPrefix(name);\n\t\t\tprefix = parts[0];\n\t\t\tname = parts[1];\n\t\t\tif (prefix) {\n\t\t\t\tplugin = callDep(prefix);\n\t\t\t}\n\t\t}\n\n\t\t//Using ridiculous property names for space reasons\n\t\treturn {\n\t\t\tf: prefix ? prefix + '!' + name : name, //fullName\n\t\t\tn: name,\n\t\t\tpr: prefix,\n\t\t\tp: plugin\n\t\t};\n\t};\n\n\tfunction makeConfig(name) {\n\t\treturn function () {\n\t\t\treturn (config && config.config && config.config[name]) || {};\n\t\t};\n\t}\n\n\thandlers = {\n\t\trequire: function (name) {\n\t\t\treturn makeRequire(name);\n\t\t},\n\t\texports: function (name) {\n\t\t\tvar e = defined[name];\n\t\t\tif (typeof e !== 'undefined') {\n\t\t\t\treturn e;\n\t\t\t} else {\n\t\t\t\treturn (defined[name] = {});\n\t\t\t}\n\t\t},\n\t\tmodule: function (name) {\n\t\t\treturn {\n\t\t\t\tid: name,\n\t\t\t\turi: '',\n\t\t\t\texports: defined[name],\n\t\t\t\tconfig: makeConfig(name)\n\t\t\t};\n\t\t}\n\t};\n\n\tmain = function (name, deps, callback, relName) {\n\t\tvar cjsModule, depName, ret, map, i, relParts,\n\t\t\targs = [],\n\t\t\tcallbackType = typeof callback,\n\t\t\tusingExports;\n\n\t\t//Use name if no relName\n\t\trelName = relName || name;\n\t\trelParts = makeRelParts(relName);\n\n\t\t//Call the callback to define the module, if necessary.\n\t\tif (callbackType === 'undefined' || callbackType === 'function') {\n\t\t\t//Pull out the defined dependencies and pass the ordered\n\t\t\t//values to the callback.\n\t\t\t//Default to [require, exports, module] if no deps\n\t\t\tdeps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;\n\t\t\tfor (i = 0; i < deps.length; i += 1) {\n\t\t\t\tmap = makeMap(deps[i], relParts);\n\t\t\t\tdepName = map.f;\n\n\t\t\t\t//Fast path CommonJS standard dependencies.\n\t\t\t\tif (depName === \"require\") {\n\t\t\t\t\targs[i] = handlers.require(name);\n\t\t\t\t} else if (depName === \"exports\") {\n\t\t\t\t\t//CommonJS module spec 1.1\n\t\t\t\t\targs[i] = handlers.exports(name);\n\t\t\t\t\tusingExports = true;\n\t\t\t\t} else if (depName === \"module\") {\n\t\t\t\t\t//CommonJS module spec 1.1\n\t\t\t\t\tcjsModule = args[i] = handlers.module(name);\n\t\t\t\t} else if (hasProp(defined, depName) ||\n\t\t\t\t\t\t hasProp(waiting, depName) ||\n\t\t\t\t\t\t hasProp(defining, depName)) {\n\t\t\t\t\targs[i] = callDep(depName);\n\t\t\t\t} else if (map.p) {\n\t\t\t\t\tmap.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});\n\t\t\t\t\targs[i] = defined[depName];\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(name + ' missing ' + depName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tret = callback ? callback.apply(defined[name], args) : undefined;\n\n\t\t\tif (name) {\n\t\t\t\t//If setting exports via \"module\" is in play,\n\t\t\t\t//favor that over return value and exports. After that,\n\t\t\t\t//favor a non-undefined return value over exports use.\n\t\t\t\tif (cjsModule && cjsModule.exports !== undef &&\n\t\t\t\t\t\tcjsModule.exports !== defined[name]) {\n\t\t\t\t\tdefined[name] = cjsModule.exports;\n\t\t\t\t} else if (ret !== undef || !usingExports) {\n\t\t\t\t\t//Use the return value from the function.\n\t\t\t\t\tdefined[name] = ret;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (name) {\n\t\t\t//May just be an object definition for the module. Only\n\t\t\t//worry about defining if have a module name.\n\t\t\tdefined[name] = callback;\n\t\t}\n\t};\n\n\trequirejs = require = req = function (deps, callback, relName, forceSync, alt) {\n\t\tif (typeof deps === \"string\") {\n\t\t\tif (handlers[deps]) {\n\t\t\t\t//callback in this case is really relName\n\t\t\t\treturn handlers[deps](callback);\n\t\t\t}\n\t\t\t//Just return the module wanted. In this scenario, the\n\t\t\t//deps arg is the module name, and second arg (if passed)\n\t\t\t//is just the relName.\n\t\t\t//Normalize module name, if it contains . or ..\n\t\t\treturn callDep(makeMap(deps, makeRelParts(callback)).f);\n\t\t} else if (!deps.splice) {\n\t\t\t//deps is a config object, not an array.\n\t\t\tconfig = deps;\n\t\t\tif (config.deps) {\n\t\t\t\treq(config.deps, config.callback);\n\t\t\t}\n\t\t\tif (!callback) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (callback.splice) {\n\t\t\t\t//callback is an array, which means it is a dependency list.\n\t\t\t\t//Adjust args if there are dependencies\n\t\t\t\tdeps = callback;\n\t\t\t\tcallback = relName;\n\t\t\t\trelName = null;\n\t\t\t} else {\n\t\t\t\tdeps = undef;\n\t\t\t}\n\t\t}\n\n\t\t//Support require(['a'])\n\t\tcallback = callback || function () {};\n\n\t\t//If relName is a function, it is an errback handler,\n\t\t//so remove it.\n\t\tif (typeof relName === 'function') {\n\t\t\trelName = forceSync;\n\t\t\tforceSync = alt;\n\t\t}\n\n\t\t//Simulate async callback;\n\t\tif (forceSync) {\n\t\t\tmain(undef, deps, callback, relName);\n\t\t} else {\n\t\t\t//Using a non-zero value because of concern for what old browsers\n\t\t\t//do, and latest browsers \"upgrade\" to 4 if lower value is used:\n\t\t\t//http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:\n\t\t\t//If want a value immediately, use require('id') instead -- something\n\t\t\t//that works in almond on the global level, but not guaranteed and\n\t\t\t//unlikely to work in other AMD implementations.\n\t\t\tsetTimeout(function () {\n\t\t\t\tmain(undef, deps, callback, relName);\n\t\t\t}, 4);\n\t\t}\n\n\t\treturn req;\n\t};\n\n\t/**\n\t * Just drops the config on the floor, but returns req in case\n\t * the config return value is used.\n\t */\n\treq.config = function (cfg) {\n\t\treturn req(cfg);\n\t};\n\n\t/**\n\t * Expose module registry for debugging and tooling\n\t */\n\trequirejs._defined = defined;\n\n\tdefine = function (name, deps, callback) {\n\t\tif (typeof name !== 'string') {\n\t\t\tthrow new Error('See almond README: incorrect module build, no module name');\n\t\t}\n\n\t\t//This module may not have dependencies\n\t\tif (!deps.splice) {\n\t\t\t//deps is not an array, so probably means\n\t\t\t//an object literal or factory function for\n\t\t\t//the value. Adjust args.\n\t\t\tcallback = deps;\n\t\t\tdeps = [];\n\t\t}\n\n\t\tif (!hasProp(defined, name) && !hasProp(waiting, name)) {\n\t\t\twaiting[name] = [name, deps, callback];\n\t\t}\n\t};\n\n\tdefine.amd = {\n\t\tjQuery: true\n\t};\n}());\n\ndefine(\"vendor/almond\", function(){});\n\n","/**\n * Returns the WordPress-loaded version of Underscore for use with things that need it and use Require.\n * @return obj\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'underscore',[],function() {\n\treturn _;\n} );\n\n","/**\n * Returns the WordPress-loaded version of Backbone for use with things that need it and use Require.\n * @return obj\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'backbone',[],function() {\n\treturn Backbone;\n} );\n\n","/**\n * Returns the WordPress-loaded version of Underscore for use with things that need it and use Require.\n * @return obj\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'jquery',[],function() {\n\treturn jQuery;\n} );\n\n","/*!\n* Backbone.CollectionView, v1.3.4\n* Copyright (c)2013 Rotunda Software, LLC.\n* Distributed under MIT license\n* http://github.com/rotundasoftware/backbone-collection-view\n*/\n\n( function( root, factory ) {\n\t// UMD wrapper\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( 'vendor/backbone.collectionView',[ 'underscore', 'backbone', 'jquery' ], factory );\n\t} else if ( typeof exports !== 'undefined' ) {\n\t\t// Node/CommonJS\n\t\tmodule.exports = factory( require('underscore' ), require( 'backbone' ), require( 'backbone' ).$ );\n\t} else {\n\t\t// Browser globals\n\t\tfactory( root._, root.Backbone, ( root.jQuery || root.Zepto || root.$ ) );\n\t}\n}( this, function( _, Backbone, $ ) {\n\tvar mDefaultModelViewConstructor = Backbone.View;\n\n\tvar kDefaultReferenceBy = \"model\";\n\n\tvar kOptionsRequiringRerendering = [ \"collection\", \"modelView\", \"modelViewOptions\", \"itemTemplate\", \"itemTemplateFunction\", \"detachedRendering\" ];\n\n\tvar kStylesForEmptyListCaption = {\n\t\t\"background\" : \"transparent\",\n\t\t\"border\" : \"none\",\n\t\t\"box-shadow\" : \"none\"\n\t};\n\n\tBackbone.CollectionView = Backbone.View.extend( {\n\n\t\ttagName : \"ul\",\n\n\t\tevents : {\n\t\t\t\"mousedown > li, tbody > tr > td\" : \"_listItem_onMousedown\",\n\t\t\t\"dblclick > li, tbody > tr > td\" : \"_listItem_onDoubleClick\",\n\t\t\t\"click\" : \"_listBackground_onClick\",\n\t\t\t\"click ul.collection-view, table.collection-view\" : \"_listBackground_onClick\",\n\t\t\t\"keydown\" : \"_onKeydown\"\n\t\t},\n\n\t\t// only used if Backbone.Courier is available\n\t\tspawnMessages : {\n\t\t\t\"focus\" : \"focus\"\n\t\t},\n\n\t\t//only used if Backbone.Courier is available\n\t\tpassMessages : { \"*\" : \".\" },\n\n\t\t// viewOption definitions with default values.\n\t\tinitializationOptions : [\n\t\t\t{ \"collection\" : null },\n\t\t\t{ \"modelView\" : null },\n\t\t\t{ \"modelViewOptions\" : {} },\n\t\t\t{ \"itemTemplate\" : null },\n\t\t\t{ \"itemTemplateFunction\" : null },\n\t\t\t{ \"selectable\" : true },\n\t\t\t{ \"clickToSelect\" : true },\n\t\t\t{ \"selectableModelsFilter\" : null },\n\t\t\t{ \"visibleModelsFilter\" : null },\n\t\t\t{ \"sortableModelsFilter\" : null },\n\t\t\t{ \"selectMultiple\" : false },\n\t\t\t{ \"clickToToggle\" : false },\n\t\t\t{ \"processKeyEvents\" : true },\n\t\t\t{ \"sortable\" : false },\n\t\t\t{ \"sortableOptions\" : null },\n\t\t\t{ \"reuseModelViews\" : true },\n\t\t\t{ \"detachedRendering\" : false },\n\t\t\t{ \"emptyListCaption\" : null }\n\t\t],\n\n\t\tinitialize : function( options ) {\n\t\t\tBackbone.ViewOptions.add( this, \"initializationOptions\" ); // setup the ViewOptions functionality.\n\t\t\tthis.setOptions( options ); // and make use of any provided options\n\n\t\t\tif( ! this.collection ) this.collection = new Backbone.Collection();\n\n\t\t\tthis._hasBeenRendered = false;\n\n\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\tBackbone.Courier.add( this );\n\t\t\t}\n\n\t\t\tthis.$el.data( \"view\", this ); // needed for connected sortable lists\n\t\t\tthis.$el.addClass( \"collection-view collection-list\" ); // collection-list is in there for legacy purposes\n\t\t\tif( this.selectable ) this.$el.addClass( \"selectable\" );\n\n\t\t\tif( this.selectable && this.processKeyEvents )\n\t\t\t\tthis.$el.attr( \"tabindex\", 0 ); // so we get keyboard events\n\n\t\t\tthis.selectedItems = [];\n\n\t\t\tthis._updateItemTemplate();\n\n\t\t\tif( this.collection )\n\t\t\t\tthis._registerCollectionEvents();\n\n\t\t\tthis.viewManager = new ChildViewContainer();\n\t\t},\n\n\t\t_onOptionsChanged : function( changedOptions, originalOptions ) {\n\t\t\tvar _this = this;\n\t\t\tvar rerender = false;\n\n\t\t\t_.each( _.keys( changedOptions ), function( changedOptionKey ) {\n\t\t\t\tvar newVal = changedOptions[ changedOptionKey ];\n\t\t\t\tvar oldVal = originalOptions[ changedOptionKey ];\n\t\t\t\tswitch( changedOptionKey ) {\n\t\t\t\t\tcase \"collection\" :\n\t\t\t\t\t\tif ( newVal !== oldVal ) {\n\t\t\t\t\t\t\t_this.stopListening( oldVal );\n\t\t\t\t\t\t\t_this._registerCollectionEvents();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"selectMultiple\" :\n\t\t\t\t\t\tif( ! newVal && _this.selectedItems.length > 1 )\n\t\t\t\t\t\t\t_this.setSelectedModel( _.first( _this.selectedItems ), { by : \"cid\" } );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"selectable\" :\n\t\t\t\t\t\tif( ! newVal && _this.selectedItems.length > 0 )\n\t\t\t\t\t\t\t_this.setSelectedModels( [] );\n\n\t\t\t\t\t\tif( newVal && this.processKeyEvents ) _this.$el.attr( \"tabindex\", 0 ); // so we get keyboard events\n\t\t\t\t\t\telse _this.$el.removeAttr( \"tabindex\", 0 );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"sortable\" :\n\t\t\t\t\t\tchangedOptions.sortable ? _this._setupSortable() : _this.$el.sortable( \"destroy\" );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"selectableModelsFilter\" :\n\t\t\t\t\t\t_this.reapplyFilter( 'selectableModels' );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"sortableOptions\" :\n\t\t\t\t\t\t_this.$el.sortable( \"destroy\" );\n\t\t\t\t\t\t_this._setupSortable();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"sortableModelsFilter\" :\n\t\t\t\t\t\t_this.reapplyFilter( 'sortableModels' );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"visibleModelsFilter\" :\n\t\t\t\t\t\t_this.reapplyFilter( 'visibleModels' );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"itemTemplate\" :\n\t\t\t\t\t\t_this._updateItemTemplate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"processKeyEvents\" :\n\t\t\t\t\t\tif( newVal && this.selectable ) _this.$el.attr( \"tabindex\", 0 ); // so we get keyboard events\n\t\t\t\t\t\telse _this.$el.removeAttr( \"tabindex\", 0 );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"modelView\" :\n\t\t\t\t\t\t//need to remove all old view instances\n\t\t\t\t\t\t_this.viewManager.each( function( view ) {\n\t\t\t\t\t\t\t_this.viewManager.remove( view );\n\t\t\t\t\t\t\t// destroy the View itself\n\t\t\t\t\t\t\tview.remove();\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif( _.contains( kOptionsRequiringRerendering, changedOptionKey ) ) rerender = true;\n\t\t\t} );\n\n\t\t\tif( this._hasBeenRendered && rerender ) {\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t},\n\n\t\tsetOption : function( optionName, optionValue ) { // now is mearly a wrapper around backbone.viewOptions' setOptions()\n\t\t\tvar optionHash = {};\n\t\t\toptionHash[ optionName ] = optionValue;\n\t\t\tthis.setOptions( optionHash );\n\t\t},\n\n\t\tgetSelectedModel : function( options ) {\n\t\t\treturn this.selectedItems.length ? _.first( this.getSelectedModels( options ) ) : null;\n\t\t},\n\n\t\tgetSelectedModels : function ( options ) {\n\t\t\tvar _this = this;\n\n\t\t\toptions = _.extend( {}, {\n\t\t\t\tby : kDefaultReferenceBy\n\t\t\t}, options );\n\n\t\t\tvar referenceBy = options.by;\n\t\t\tvar items = [];\n\n\t\t\tswitch( referenceBy ) {\n\t\t\t\tcase \"id\" :\n\t\t\t\t\t_.each( this.selectedItems, function ( item ) {\n\t\t\t\t\t\titems.push( _this.collection.get( item ).id );\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"cid\" :\n\t\t\t\t\titems = items.concat( this.selectedItems );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"offset\" :\n\t\t\t\t\tvar curLineNumber = 0;\n\n\t\t\t\t\tvar itemElements = this._getVisibleItemEls();\n\n\t\t\t\t\titemElements.each( function() {\n\t\t\t\t\t\tvar thisItemEl = $( this );\n\t\t\t\t\t\tif( thisItemEl.is( \".selected\" ) )\n\t\t\t\t\t\t\titems.push( curLineNumber );\n\t\t\t\t\t\tcurLineNumber++;\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"model\" :\n\t\t\t\t\t_.each( this.selectedItems, function ( item ) {\n\t\t\t\t\t\titems.push( _this.collection.get( item ) );\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"view\" :\n\t\t\t\t\t_.each( this.selectedItems, function ( item ) {\n\t\t\t\t\t\titems.push( _this.viewManager.findByModel( _this.collection.get( item ) ) );\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault :\n\t\t\t\t\tthrow new Error( \"Invalid referenceBy option: \" + referenceBy );\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn items;\n\n\t\t},\n\n\t\tsetSelectedModels : function( newSelectedItems, options ) {\n\t\t\tif( ! _.isArray( newSelectedItems ) ) throw \"Invalid parameter value\";\n\t\t\tif( ! this.selectable && newSelectedItems.length > 0 ) return; // used to throw error, but there are some circumstances in which a list can be selectable at times and not at others, don't want to have to worry about catching errors\n\n\t\t\toptions = _.extend( {}, {\n\t\t\t\tsilent : false,\n\t\t\t\tby : kDefaultReferenceBy\n\t\t\t}, options );\n\n\t\t\tvar referenceBy = options.by;\n\t\t\tvar newSelectedCids = [];\n\n\t\t\tswitch( referenceBy ) {\n\t\t\t\tcase \"cid\" :\n\t\t\t\t\tnewSelectedCids = newSelectedItems;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"id\" :\n\t\t\t\t\tthis.collection.each( function( thisModel ) {\n\t\t\t\t\t\tif( _.contains( newSelectedItems, thisModel.id ) ) newSelectedCids.push( thisModel.cid );\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"model\" :\n\t\t\t\t\tnewSelectedCids = _.pluck( newSelectedItems, \"cid\" );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"view\" :\n\t\t\t\t\t_.each( newSelectedItems, function( item ) {\n\t\t\t\t\t\tnewSelectedCids.push( item.model.cid );\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"offset\" :\n\t\t\t\t\tvar curLineNumber = 0;\n\t\t\t\t\tvar selectedItems = [];\n\n\t\t\t\t\tvar itemElements = this._getVisibleItemEls();\n\t\t\t\t\titemElements.each( function() {\n\t\t\t\t\t\tvar thisItemEl = $( this );\n\t\t\t\t\t\tif( _.contains( newSelectedItems, curLineNumber ) )\n\t\t\t\t\t\t\tnewSelectedCids.push( thisItemEl.attr( \"data-model-cid\" ) );\n\t\t\t\t\t\tcurLineNumber++;\n\t\t\t\t\t} );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault :\n\t\t\t\t\tthrow new Error( \"Invalid referenceBy option: \" + referenceBy );\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tvar oldSelectedModels = this.getSelectedModels();\n\t\t\tvar oldSelectedCids = _.clone( this.selectedItems );\n\n\t\t\tthis.selectedItems = this._convertStringsToInts( newSelectedCids );\n\t\t\tthis._validateSelection();\n\n\t\t\tvar newSelectedModels = this.getSelectedModels();\n\n\t\t\tif( ! this._containSameElements( oldSelectedCids, this.selectedItems ) )\n\t\t\t{\n\t\t\t\tthis._addSelectedClassToSelectedItems( oldSelectedCids );\n\n\t\t\t\tif( ! options.silent )\n\t\t\t\t{\n\t\t\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\t\t\tthis.spawn( \"selectionChanged\", {\n\t\t\t\t\t\t\tselectedModels : newSelectedModels,\n\t\t\t\t\t\t\toldSelectedModels : oldSelectedModels\n\t\t\t\t\t\t} );\n\t\t\t\t\t} else this.trigger( \"selectionChanged\", newSelectedModels, oldSelectedModels );\n\t\t\t\t}\n\n\t\t\t\tthis.updateDependentControls();\n\t\t\t}\n\t\t},\n\n\t\tsetSelectedModel : function( newSelectedItem, options ) {\n\t\t\tif( ! newSelectedItem && newSelectedItem !== 0 )\n\t\t\t\tthis.setSelectedModels( [], options );\n\t\t\telse\n\t\t\t\tthis.setSelectedModels( [ newSelectedItem ], options );\n\t\t},\n\n\t\tgetView : function( reference, options ) {\n\t\t\toptions = _.extend( {}, {\n\t\t\t\tby : kDefaultReferenceBy\n\t\t\t}, options );\n\n\t\t\tswitch( options.by ) {\n\t\t\t\tcase \"id\" :\n\t\t\t\tcase \"cid\" :\n\t\t\t\t\tvar model = this.collection.get( reference ) || null;\n\t\t\t\t\treturn model && this.viewManager.findByModel( model );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"offset\" :\n\t\t\t\t\tvar itemElements = this._getVisibleItemEls();\n\t\t\t\t\treturn $( itemElements.get( reference ) );\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"model\" :\n\t\t\t\t\treturn this.viewManager.findByModel( reference );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault :\n\t\t\t\t\tthrow new Error( \"Invalid referenceBy option: \" + referenceBy );\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\n\t\trender : function() {\n\t\t\tvar _this = this;\n\n\t\t\tthis._hasBeenRendered = true;\n\n\t\t\tif( this.selectable ) this._saveSelection();\n\n\t\t\tvar modelViewContainerEl;\n\n\t\t\t// If collection view element is a table and it has a tbody\n\t\t\t// within it, render the model views inside of the tbody\n\t\t\tmodelViewContainerEl = this._getContainerEl();\n\n\t\t\tvar oldViewManager = this.viewManager;\n\t\t\tthis.viewManager = new ChildViewContainer();\n\n\t\t\t// detach each of our subviews that we have already created to represent models\n\t\t\t// in the collection. We are going to re-use the ones that represent models that\n\t\t\t// are still here, instead of creating new ones, so that we don't loose state\n\t\t\t// information in the views.\n\t\t\toldViewManager.each( function( thisModelView ) {\n\t\t\t\t// to boost performance, only detach those views that will be sticking around.\n\t\t\t\t// we won't need the other ones later, so no need to detach them individually.\n\t\t\t\tif( this.reuseModelViews && this.collection.get( thisModelView.model.cid ) ) {\n\t\t\t\t\tthisModelView.$el.detach();\n\t\t\t\t} else thisModelView.remove();\n\t\t\t}, this );\n\n\t\t\tmodelViewContainerEl.empty();\n\t\t\tvar fragmentContainer;\n\n\t\t\tif( this.detachedRendering )\n\t\t\t\tfragmentContainer = document.createDocumentFragment();\n\n\t\t\tthis.collection.each( function( thisModel ) {\n\t\t\t\tvar thisModelView = oldViewManager.findByModelCid( thisModel.cid );\n\t\t\t\tif( ! this.reuseModelViews || _.isUndefined( thisModelView ) ) {\n\t\t\t\t\t// if the model view has not already been created on a\n\t\t\t\t\t// previous render then create and initialize it now.\n\t\t\t\t\tthisModelView = this._createNewModelView( thisModel, this._getModelViewOptions( thisModel ) );\n\t\t\t\t}\n\n\t\t\t\tthis._insertAndRenderModelView( thisModelView, fragmentContainer || modelViewContainerEl );\n\t\t\t}, this );\n\n\t\t\tif( this.detachedRendering )\n\t\t\t\tmodelViewContainerEl.append( fragmentContainer );\n\n\t\t\tif( this.sortable ) this._setupSortable();\n\n\t\t\tthis._showEmptyListCaptionIfAppropriate();\n\n\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\tthis.spawn( \"render\" );\n\t\t\telse this.trigger( \"render\" );\n\n\t\t\tif( this.selectable ) {\n\t\t\t\tthis._restoreSelection();\n\t\t\t\tthis.updateDependentControls();\n\t\t\t}\n\n\t\t\tthis.forceRerenderOnNextSortEvent = false;\n\t\t},\n\n\t\t_showEmptyListCaptionIfAppropriate : function ( ) {\n\t\t\tthis._removeEmptyListCaption();\n\n\t\t\tif( this.emptyListCaption ) {\n\t\t\t\tvar visibleEls = this._getVisibleItemEls();\n\n\t\t\t\tif( visibleEls.length === 0 ) {\n\t\t\t\t\tvar emptyListString;\n\n\t\t\t\t\tif( _.isFunction( this.emptyListCaption ) )\n\t\t\t\t\t\temptyListString = this.emptyListCaption();\n\t\t\t\t\telse\n\t\t\t\t\t\temptyListString = this.emptyListCaption;\n\n\t\t\t\t\tvar $emptyListCaptionEl;\n\t\t\t\t\tvar $varEl = $( \"\" + emptyListString + \"\" );\n\n\t\t\t\t\t// need to wrap the empty caption to make it fit the rendered list structure (either with an li or a tr td)\n\t\t\t\t\tif( this._isRenderedAsList() )\n\t\t\t\t\t\t$emptyListCaptionEl = $varEl.wrapAll( \"
  • \" ).parent().css( kStylesForEmptyListCaption );\n\t\t\t\t\telse\n\t\t\t\t\t\t$emptyListCaptionEl = $varEl.wrapAll( \"\" ).parent().parent().css( kStylesForEmptyListCaption );\n\n\t\t\t\t\tthis._getContainerEl().append( $emptyListCaptionEl );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_removeEmptyListCaption : function( ) {\n\t\t\tif( this._isRenderedAsList() )\n\t\t\t\tthis._getContainerEl().find( \"> li > var.empty-list-caption\" ).parent().remove();\n\t\t\telse\n\t\t\t\tthis._getContainerEl().find( \"> tr > td > var.empty-list-caption\" ).parent().parent().remove();\n\t\t},\n\n\t\t// Render a single model view in container object \"parentElOrDocumentFragment\", which is either\n\t\t// a documentFragment or a jquery object. optional arg atIndex is not support for document fragments.\n\t\t_insertAndRenderModelView : function( modelView, parentElOrDocumentFragment, atIndex ) {\n\t\t\tvar thisModelViewWrapped = this._wrapModelView( modelView );\n\n\t\t\tif( parentElOrDocumentFragment.nodeType === 11 ) // if we are inserting into a document fragment, we need to use the DOM appendChild method\n\t\t\t\tparentElOrDocumentFragment.appendChild( thisModelViewWrapped.get( 0 ) );\n\t\t\telse {\n\t\t\t\tvar numberOfModelViewsCurrentlyInDOM = parentElOrDocumentFragment.children().length;\n\t\t\t\tif( ! _.isUndefined( atIndex ) && atIndex >= 0 && atIndex < numberOfModelViewsCurrentlyInDOM )\n\t\t\t\t\t// note this.collection.length might be greater than parentElOrDocumentFragment.children().length here\n\t\t\t\t\tparentElOrDocumentFragment.children().eq( atIndex ).before( thisModelViewWrapped );\n\t\t\t\telse {\n\t\t\t\t\t// if we are attempting to insert a modelView in an position that is beyond what is currently in the\n\t\t\t\t\t// DOM, then make a note that we need to re-render the collection view on the next sort event. If we dont\n\t\t\t\t\t// force this re-render, we can end up with modelViews in the wrong order when the collection defines\n\t\t\t\t\t// a comparator and multiple models are added at once. See https://github.com/rotundasoftware/backbone.collectionView/issues/69\n\t\t\t\t\tif( ! _.isUndefined( atIndex ) && atIndex > numberOfModelViewsCurrentlyInDOM ) this.forceRerenderOnNextSortEvent = true;\n\n\t\t\t\t\tparentElOrDocumentFragment.append( thisModelViewWrapped );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.viewManager.add( modelView );\n\n\t\t\t// we have to render the modelView after it has been put in context, as opposed to in the\n\t\t\t// initialize function of the modelView, because some rendering might be dependent on\n\t\t\t// the modelView's context in the DOM tree. For example, if the modelView stretch()'s itself,\n\t\t\t// it must be in full context in the DOM tree or else the stretch will not behave as intended.\n\t\t\tvar renderResult = modelView.render();\n\n\t\t\t// return false from the view's render function to hide this item\n\t\t\tif( renderResult === false ) {\n\t\t\t\tthisModelViewWrapped.hide();\n\t\t\t\tthisModelViewWrapped.addClass( \"not-visible\" );\n\t\t\t}\n\n\t\t\tvar hideThisModelView = false;\n\t\t\tif( _.isFunction( this.visibleModelsFilter ) )\n\t\t\t\thideThisModelView = ! this.visibleModelsFilter( modelView.model );\n\n\t\t\tif( thisModelViewWrapped.children().length === 1 )\n\t\t\t\tthisModelViewWrapped.toggle( ! hideThisModelView );\n\t\t\telse modelView.$el.toggle( ! hideThisModelView );\n\n\t\t\tthisModelViewWrapped.toggleClass( \"not-visible\", hideThisModelView );\n\n\t\t\tif( ! hideThisModelView && this.emptyListCaption ) this._removeEmptyListCaption();\n\t\t},\n\n\t\tupdateDependentControls : function() {\n\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\tthis.spawn( \"updateDependentControls\", {\n\t\t\t\t\tselectedModels : this.getSelectedModels()\n\t\t\t\t} );\n\t\t\t} else this.trigger( \"updateDependentControls\", this.getSelectedModels() );\n\t\t},\n\n\t\t// Override `Backbone.View.remove` to also destroy all Views in `viewManager`\n\t\tremove : function() {\n\t\t\tthis.viewManager.each( function( view ) {\n\t\t\t\tview.remove();\n\t\t\t} );\n\n\t\t\tBackbone.View.prototype.remove.apply( this, arguments );\n\t\t},\n\n\t\treapplyFilter : function( whichFilter ) {\n\t\t\tvar _this = this;\n\n\t\t\tif( ! _.contains( [ \"selectableModels\", \"sortableModels\", \"visibleModels\" ], whichFilter ) ) {\n\t\t\t\tthrow new Error( \"Invalid filter identifier supplied to reapplyFilter: \" + whichFilter );\n\t\t\t}\n\n\t\t\tswitch( whichFilter ) {\n\t\t\t\tcase \"visibleModels\":\n\t\t\t\t\t_this.viewManager.each( function( thisModelView ) {\n\t\t\t\t\t\tvar notVisible = _this.visibleModelsFilter && ! _this.visibleModelsFilter.call( _this, thisModelView.model );\n\n\t\t\t\t\t\tthisModelView.$el.toggleClass( \"not-visible\", notVisible );\n\t\t\t\t\t\tif( _this._modelViewHasWrapperLI( thisModelView ) ) {\n\t\t\t\t\t\t\tthisModelView.$el.closest( \"li\" ).toggleClass( \"not-visible\", notVisible ).toggle( ! notVisible );\n\t\t\t\t\t\t} else thisModelView.$el.toggle( ! notVisible );\n\t\t\t\t\t} );\n\n\t\t\t\t\tthis._showEmptyListCaptionIfAppropriate();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"sortableModels\":\n\t\t\t\t\t_this.$el.sortable( \"destroy\" );\n\n\t\t\t\t\t_this.viewManager.each( function( thisModelView ) {\n\t\t\t\t\t\tvar notSortable = _this.sortableModelsFilter && ! _this.sortableModelsFilter.call( _this, thisModelView.model );\n\n\t\t\t\t\t\tthisModelView.$el.toggleClass( \"not-sortable\", notSortable );\n\t\t\t\t\t\tif( _this._modelViewHasWrapperLI( thisModelView ) ) {\n\t\t\t\t\t\t\tthisModelView.$el.closest( \"li\" ).toggleClass( \"not-sortable\", notSortable );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t\t_this._setupSortable();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"selectableModels\":\n\t\t\t\t\t_this.viewManager.each( function( thisModelView ) {\n\t\t\t\t\t\tvar notSelectable = _this.selectableModelsFilter && ! _this.selectableModelsFilter.call( _this, thisModelView.model );\n\n\t\t\t\t\t\tthisModelView.$el.toggleClass( \"not-selectable\", notSelectable );\n\t\t\t\t\t\tif( _this._modelViewHasWrapperLI( thisModelView ) ) {\n\t\t\t\t\t\t\tthisModelView.$el.closest( \"li\" ).toggleClass( \"not-selectable\", notSelectable );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t\t_this._validateSelection();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\n\t\t// A method to remove the view relating to model.\n\t\t_removeModelView : function( modelView ) {\n\t\t\tif( this.selectable ) this._saveSelection();\n\n\t\t\tthis.viewManager.remove( modelView ); // Remove the view from the viewManager\n\t\t\tif( this._modelViewHasWrapperLI( modelView ) ) modelView.$el.parent().remove(); // Remove the li wrapper from the DOM\n\t\t\tmodelView.remove(); // Remove the view from the DOM and stop listening to events\n\n\t\t\tif( this.selectable ) this._restoreSelection();\n\n\t\t\tthis._showEmptyListCaptionIfAppropriate();\n\t\t},\n\n\t\t_validateSelectionAndRender : function() {\n\t\t\tthis._validateSelection();\n\t\t\tthis.render();\n\t\t},\n\n\t\t_registerCollectionEvents : function() {\n\n\t\t\tthis.listenTo( this.collection, \"add\", function( model ) {\n\t\t\t\tvar modelView;\n\t\t\t\tif( this._hasBeenRendered ) {\n\t\t\t\t\tmodelView = this._createNewModelView( model, this._getModelViewOptions( model ) );\n\t\t\t\t\tthis._insertAndRenderModelView( modelView, this._getContainerEl(), this.collection.indexOf( model ) );\n\t\t\t\t}\n\n\t\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\t\tthis.spawn( \"add\", modelView );\n\t\t\t\telse this.trigger( \"add\", modelView );\n\t\t\t} );\n\n\t\t\tthis.listenTo( this.collection, \"remove\", function( model ) {\n\t\t\t\tvar modelView;\n\n\t\t\t\tif( this._hasBeenRendered ) {\n\t\t\t\t\tmodelView = this.viewManager.findByModelCid( model.cid );\n\t\t\t\t\tthis._removeModelView( modelView );\n\t\t\t\t}\n\n\t\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\t\tthis.spawn( \"remove\" );\n\t\t\t\telse this.trigger( \"remove\" );\n\t\t\t} );\n\n\t\t\tthis.listenTo( this.collection, \"reset\", function() {\n\t\t\t\tif( this._hasBeenRendered ) this.render();\n\t\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\t\tthis.spawn( \"reset\" );\n\t\t\t\telse this.trigger( \"reset\" );\n\t\t\t} );\n\n\t\t\t// we should not be listening to change events on the model as a default behavior. the models\n\t\t\t// should be responsible for re-rendering themselves if necessary, and if the collection does\n\t\t\t// also need to re-render as a result of a model change, this should be handled by overriding\n\t\t\t// this method. by default the collection view should not re-render in response to model changes\n\t\t\t// this.listenTo( this.collection, \"change\", function( model ) {\n\t\t\t// \tif( this._hasBeenRendered ) this.viewManager.findByModel( model ).render();\n\t\t\t// \tif( this._isBackboneCourierAvailable() )\n\t\t\t// \t\tthis.spawn( \"change\", { model : model } );\n\t\t\t// } );\n\n\t\t\tthis.listenTo( this.collection, \"sort\", function( collection, options ) {\n\t\t\t\tif( this._hasBeenRendered && ( options.add !== true || this.forceRerenderOnNextSortEvent ) ) this.render();\n\t\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\t\tthis.spawn( \"sort\" );\n\t\t\t\telse this.trigger( \"sort\" );\n\t\t\t} );\n\t\t},\n\n\t\t_getContainerEl : function() {\n\t\t\tif ( this._isRenderedAsTable() ) {\n\t\t\t\t// not all tables have a tbody, so we test\n\t\t\t\tvar tbody = this.$el.find( \"> tbody\" );\n\t\t\t\tif ( tbody.length > 0 )\n\t\t\t\t\treturn tbody;\n\t\t\t}\n\t\t\treturn this.$el;\n\t\t},\n\n\t\t_getClickedItemId : function( theEvent ) {\n\t\t\tvar clickedItemId = null;\n\n\t\t\t// important to use currentTarget as opposed to target, since we could be bubbling\n\t\t\t// an event that took place within another collectionList\n\t\t\tvar clickedItemEl = $( theEvent.currentTarget );\n\t\t\tif( clickedItemEl.closest( \".collection-view\" ).get(0) !== this.$el.get(0) ) return;\n\n\t\t\t// determine which list item was clicked. If we clicked in the blank area\n\t\t\t// underneath all the elements, we want to know that too, since in this\n\t\t\t// case we will want to deselect all elements. so check to see if the clicked\n\t\t\t// DOM element is the list itself to find that out.\n\t\t\tvar clickedItem = clickedItemEl.closest( \"[data-model-cid]\" );\n\t\t\tif( clickedItem.length > 0 )\n\t\t\t{\n\t\t\t\tclickedItemId = clickedItem.attr( \"data-model-cid\" );\n\t\t\t\tif( $.isNumeric( clickedItemId ) ) clickedItemId = parseInt( clickedItemId, 10 );\n\t\t\t}\n\n\t\t\treturn clickedItemId;\n\t\t},\n\n\t\t_updateItemTemplate : function() {\n\t\t\tvar itemTemplateHtml;\n\t\t\tif( this.itemTemplate )\n\t\t\t{\n\t\t\t\tif( $( this.itemTemplate ).length === 0 )\n\t\t\t\t\tthrow \"Could not find item template from selector: \" + this.itemTemplate;\n\n\t\t\t\titemTemplateHtml = $( this.itemTemplate ).html();\n\t\t\t}\n\t\t\telse\n\t\t\t\titemTemplateHtml = this.$( \".item-template\" ).html();\n\n\t\t\tif( itemTemplateHtml ) this.itemTemplateFunction = _.template( itemTemplateHtml );\n\n\t\t},\n\n\t\t_validateSelection : function() {\n\t\t\t// note can't use the collection's proxy to underscore because \"cid\" is not an attribute,\n\t\t\t// but an element of the model object itself.\n\t\t\tvar modelReferenceIds = _.pluck( this.collection.models, \"cid\" );\n\t\t\tthis.selectedItems = _.intersection( modelReferenceIds, this.selectedItems );\n\n\t\t\tif( _.isFunction( this.selectableModelsFilter ) )\n\t\t\t{\n\t\t\t\tthis.selectedItems = _.filter( this.selectedItems, function( thisItemId ) {\n\t\t\t\t\treturn this.selectableModelsFilter.call( this, this.collection.get( thisItemId ) );\n\t\t\t\t}, this );\n\t\t\t}\n\t\t},\n\n\t\t_saveSelection : function() {\n\t\t\t// save the current selection. use restoreSelection() to restore the selection to the state it was in the last time saveSelection() was called.\n\t\t\tif( ! this.selectable ) throw \"Attempt to save selection on non-selectable list\";\n\t\t\tthis.savedSelection = {\n\t\t\t\titems : _.clone( this.selectedItems ),\n\t\t\t\toffset : this.getSelectedModel( { by : \"offset\" } )\n\t\t\t};\n\t\t},\n\n\t\t_restoreSelection : function() {\n\t\t\tif( ! this.savedSelection ) throw \"Attempt to restore selection but no selection has been saved!\";\n\n\t\t\t// reset selectedItems to empty so that we \"redraw\" all \"selected\" classes\n\t\t\t// when we set our new selection. We do this because it is likely that our\n\t\t\t// contents have been refreshed, and we have thus lost all old \"selected\" classes.\n\t\t\tthis.setSelectedModels( [], { silent : true } );\n\n\t\t\tif( this.savedSelection.items.length > 0 )\n\t\t\t{\n\t\t\t\t// first try to restore the old selected items using their reference ids.\n\t\t\t\tthis.setSelectedModels( this.savedSelection.items, { by : \"cid\", silent : true } );\n\n\t\t\t\t// all the items with the saved reference ids have been removed from the list.\n\t\t\t\t// ok. try to restore the selection based on the offset that used to be selected.\n\t\t\t\t// this is the expected behavior after a item is deleted from a list (i.e. select\n\t\t\t\t// the line that immediately follows the deleted line).\n\t\t\t\tif( this.selectedItems.length === 0 )\n\t\t\t\t\tthis.setSelectedModel( this.savedSelection.offset, { by : \"offset\" } );\n\n\t\t\t\t// Trigger a selection changed if the previously selected items were not all found\n\t\t\t\tif (this.selectedItems.length !== this.savedSelection.items.length)\n\t\t\t\t{\n\t\t\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\t\t\tthis.spawn( \"selectionChanged\", {\n\t\t\t\t\t\t\tselectedModels : this.getSelectedModels(),\n\t\t\t\t\t\t\toldSelectedModels : []\n\t\t\t\t\t\t} );\n\t\t\t\t\t} else this.trigger( \"selectionChanged\", this.getSelectedModels(), [] );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_addSelectedClassToSelectedItems : function( oldItemsIdsWithSelectedClass ) {\n\t\t\tif( _.isUndefined( oldItemsIdsWithSelectedClass ) ) oldItemsIdsWithSelectedClass = [];\n\n\t\t\t// oldItemsIdsWithSelectedClass is used for optimization purposes only. If this info is supplied then we\n\t\t\t// only have to add / remove the \"selected\" class from those items that \"selected\" state has changed.\n\n\t\t\tvar itemsIdsFromWhichSelectedClassNeedsToBeRemoved = oldItemsIdsWithSelectedClass;\n\t\t\titemsIdsFromWhichSelectedClassNeedsToBeRemoved = _.without( itemsIdsFromWhichSelectedClassNeedsToBeRemoved, this.selectedItems );\n\n\t\t\t_.each( itemsIdsFromWhichSelectedClassNeedsToBeRemoved, function( thisItemId ) {\n\t\t\t\tthis._getContainerEl().find( \"[data-model-cid=\" + thisItemId + \"]\" ).removeClass( \"selected\" );\n\n\t\t\t\tif( this._isRenderedAsList() ) {\n\t\t\t\t\tthis._getContainerEl().find( \"li[data-model-cid=\" + thisItemId + \"] > *\" ).removeClass( \"selected\" );\n\t\t\t\t}\n\t\t\t}, this );\n\n\t\t\tvar itemsIdsFromWhichSelectedClassNeedsToBeAdded = this.selectedItems;\n\t\t\titemsIdsFromWhichSelectedClassNeedsToBeAdded = _.without( itemsIdsFromWhichSelectedClassNeedsToBeAdded, oldItemsIdsWithSelectedClass );\n\n\t\t\t_.each( itemsIdsFromWhichSelectedClassNeedsToBeAdded, function( thisItemId ) {\n\t\t\t\tthis._getContainerEl().find( \"[data-model-cid=\" + thisItemId + \"]\" ).addClass( \"selected\" );\n\n\t\t\t\tif( this._isRenderedAsList() ) {\n\t\t\t\t\tthis._getContainerEl().find( \"li[data-model-cid=\" + thisItemId + \"] > *\" ).addClass( \"selected\" );\n\t\t\t\t}\n\t\t\t}, this );\n\t\t},\n\n\t\t_reorderCollectionBasedOnHTML : function() {\n\n\t\t\tvar _this = this;\n\n\t\t\tthis._getContainerEl().children().each( function() {\n\t\t\t\tvar thisModelCid = $( this ).attr( \"data-model-cid\" );\n\n\t\t\t\tif( thisModelCid )\n\t\t\t\t{\n\t\t\t\t\t// remove the current model and then add it back (at the end of the collection).\n\t\t\t\t\t// When we are done looping through all models, they will be in the correct order.\n\t\t\t\t\tvar thisModel = _this.collection.get( thisModelCid );\n\t\t\t\t\tif( thisModel )\n\t\t\t\t\t{\n\t\t\t\t\t\t_this.collection.remove( thisModel, { silent : true } );\n\t\t\t\t\t\t_this.collection.add( thisModel, { silent : true, sort : ! _this.collection.comparator } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif( this._isBackboneCourierAvailable() ) this.spawn( \"reorder\" );\n\t\t\telse this.collection.trigger( \"reorder\" );\n\n\t\t\tif( this.collection.comparator ) this.collection.sort();\n\n\t\t},\n\n\t\t_getModelViewConstructor : function( thisModel ) {\n\t\t\treturn this.modelView || mDefaultModelViewConstructor;\n\t\t},\n\n\t\t_getModelViewOptions : function( thisModel ) {\n\t\t\tvar modelViewOptions = this.modelViewOptions;\n\t\t\tif( _.isFunction( modelViewOptions ) ) modelViewOptions = modelViewOptions( thisModel );\n\n\t\t\treturn _.extend( { model : thisModel }, modelViewOptions );\n\t\t},\n\n\t\t_createNewModelView : function( model, modelViewOptions ) {\n\t\t\tvar modelViewConstructor = this._getModelViewConstructor( model );\n\t\t\tif( _.isUndefined( modelViewConstructor ) ) throw \"Could not find modelView constructor for model\";\n\n\t\t\tvar newModelView = new( modelViewConstructor )( modelViewOptions );\n\t\t\tnewModelView.collectionListView = newModelView.collectionView = this; // collectionListView for legacy\n\n\t\t\treturn newModelView;\n\t\t},\n\n\t\t_wrapModelView : function( modelView ) {\n\t\t\tvar _this = this;\n\n\t\t\t// we use items client ids as opposed to real ids, since we may not have a representation\n\t\t\t// of these models on the server\n\t\t\tvar modelViewWrapperEl;\n\n\t\t\tif( this._isRenderedAsTable() ) {\n\t\t\t\t// if we are rendering the collection in a table, the template $el is a tr so we just need to set the data-model-cid\n\t\t\t\tmodelViewWrapperEl = modelView.$el;\n\t\t\t\tmodelView.$el.attr( \"data-model-cid\", modelView.model.cid );\n\t\t\t}\n\t\t\telse if( this._isRenderedAsList() ) {\n\t\t\t\t// if we are rendering the collection in a list, we need wrap each item in an
  • (if its not already an
  • )\n\t\t\t\t// and set the data-model-cid\n\t\t\t\tif( modelView.$el.is( \"li\" ) ) {\n\t\t\t\t\tmodelViewWrapperEl = modelView.$el;\n\t\t\t\t\tmodelView.$el.attr( \"data-model-cid\", modelView.model.cid );\n\t\t\t\t} else {\n\t\t\t\t\tmodelViewWrapperEl = modelView.$el.wrapAll( \"
  • \" ).parent();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif( _.isFunction( this.sortableModelsFilter ) )\n\t\t\t\tif( ! this.sortableModelsFilter.call( _this, modelView.model ) ) {\n\t\t\t\t\tmodelViewWrapperEl.addClass( \"not-sortable\" );\n\t\t\t\t\tmodelView.$el.addClass( \"not-selectable\" );\n\t\t\t\t}\n\n\t\t\tif( _.isFunction( this.selectableModelsFilter ) )\n\t\t\t\tif( ! this.selectableModelsFilter.call( _this, modelView.model ) ) {\n\t\t\t\t\tmodelViewWrapperEl.addClass( \"not-selectable\" );\n\t\t\t\t\tmodelView.$el.addClass( \"not-selectable\" );\n\t\t\t\t}\n\n\t\t\treturn modelViewWrapperEl;\n\t\t},\n\n\t\t_convertStringsToInts : function( theArray ) {\n\t\t\treturn _.map( theArray, function( thisEl ) {\n\t\t\t\tif( ! _.isString( thisEl ) ) return thisEl;\n\t\t\t\tvar thisElAsNumber = parseInt( thisEl, 10 );\n\t\t\t\treturn( thisElAsNumber == thisEl ? thisElAsNumber : thisEl );\n\t\t\t} );\n\t\t},\n\n\t\t_containSameElements : function( arrayA, arrayB ) {\n\t\t\tif( arrayA.length != arrayB.length ) return false;\n\t\t\tvar intersectionSize = _.intersection( arrayA, arrayB ).length;\n\t\t\treturn intersectionSize == arrayA.length; // and must also equal arrayB.length, since arrayA.length == arrayB.length\n\t\t},\n\n\t\t_isRenderedAsTable : function() {\n\t\t\treturn this.$el.prop( \"tagName\" ).toLowerCase() === \"table\";\n\t\t},\n\n\t\t_isRenderedAsList : function() {\n\t\t\treturn ! this._isRenderedAsTable();\n\t\t},\n\n\t\t_modelViewHasWrapperLI : function( modelView ) {\n\t\t\treturn this._isRenderedAsList() && ! modelView.$el.is( \"li\" );\n\t\t},\n\n\t\t// Returns the wrapper HTML element for each visible modelView.\n\t\t// When rendering in a table context, the returned elements are the $el of each modelView.\n\t\t// When rendering in a list context,\n\t\t// If the $el of the modelView is an
  • , the returned elements are the $el of each modelView.\n\t\t// Otherwise, the returned elements are the
  • 's the collectionView wrapped around each modelView $el.\n\t\t_getVisibleItemEls : function() {\n\t\t\tvar itemElements = [];\n\t\t\titemElements = this._getContainerEl().find( \"> [data-model-cid]:not(.not-visible)\" );\n\n\t\t\treturn itemElements;\n\t\t},\n\n\t\t_charCodes : {\n\t\t\tupArrow : 38,\n\t\t\tdownArrow : 40\n\t\t},\n\n\t\t_isBackboneCourierAvailable : function() {\n\t\t\treturn !_.isUndefined( Backbone.Courier );\n\t\t},\n\n\t\t_setupSortable : function() {\n\t\t\tvar sortableOptions = _.extend( {\n\t\t\t\taxis : \"y\",\n\t\t\t\tdistance : 10,\n\t\t\t\tforcePlaceholderSize : true,\n\t\t\t\titems : this._isRenderedAsTable() ? \"> tbody > tr:not(.not-sortable)\" : \"> li:not(.not-sortable)\",\n\t\t\t\tstart : _.bind( this._sortStart, this ),\n\t\t\t\tchange : _.bind( this._sortChange, this ),\n\t\t\t\tstop : _.bind( this._sortStop, this ),\n\t\t\t\treceive : _.bind( this._receive, this ),\n\t\t\t\tover : _.bind( this._over, this )\n\t\t\t}, _.result( this, \"sortableOptions\" ) );\n\n\t\t\tthis.$el = this.$el.sortable( sortableOptions );\n\t\t\t//this.$el.sortable( \"enable\" ); // in case it was disabled previously\n\t\t},\n\n\t\t_sortStart : function( event, ui ) {\n\t\t\tvar modelBeingSorted = this.collection.get( ui.item.attr( \"data-model-cid\" ) );\n\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\tthis.spawn( \"sortStart\", { modelBeingSorted : modelBeingSorted } );\n\t\t\telse this.trigger( \"sortStart\", modelBeingSorted );\n\t\t},\n\n\t\t_sortChange : function( event, ui ) {\n\t\t\tvar modelBeingSorted = this.collection.get( ui.item.attr( \"data-model-cid\" ) );\n\n\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\tthis.spawn( \"sortChange\", { modelBeingSorted : modelBeingSorted } );\n\t\t\telse this.trigger( \"sortChange\", modelBeingSorted );\n\t\t},\n\n\t\t_sortStop : function( event, ui ) {\n\t\t\tvar modelBeingSorted = this.collection.get( ui.item.attr( \"data-model-cid\" ) );\n\t\t\tvar modelViewContainerEl = this._getContainerEl();\n\t\t\tvar newIndex = modelViewContainerEl.children().index( ui.item );\n\n\t\t\tif( newIndex == -1 && modelBeingSorted ) {\n\t\t\t\t// the element was removed from this list. can happen if this sortable is connected\n\t\t\t\t// to another sortable, and the item was dropped into the other sortable.\n\t\t\t\tthis.collection.remove( modelBeingSorted );\n\t\t\t}\n\n\t\t\tif( ! modelBeingSorted ) return; // something is wacky. we don't mess with this case, preferring to guarantee that we can always provide a reference to the model\n\n\t\t\tthis._reorderCollectionBasedOnHTML();\n\t\t\tthis.updateDependentControls();\n\n\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\tthis.spawn( \"sortStop\", { modelBeingSorted : modelBeingSorted, newIndex : newIndex } );\n\t\t\telse this.trigger( \"sortStop\", modelBeingSorted, newIndex );\n\t\t},\n\n\t\t_receive : function( event, ui ) {\n\n\t\t\tvar senderListEl = ui.sender;\n\t\t\tvar senderCollectionListView = senderListEl.data( \"view\" );\n\t\t\tif( ! senderCollectionListView || ! senderCollectionListView.collection ) return;\n\n\t\t\tvar newIndex = this._getContainerEl().children().index( ui.item );\n\t\t\tvar modelReceived = senderCollectionListView.collection.get( ui.item.attr( \"data-model-cid\" ) );\n\t\t\tsenderCollectionListView.collection.remove( modelReceived );\n\t\t\tthis.collection.add( modelReceived, { at : newIndex } );\n\t\t\tmodelReceived.collection = this.collection; // otherwise will not get properly set, since modelReceived.collection might already have a value.\n\t\t\tthis.setSelectedModel( modelReceived );\n\t\t},\n\n\t\t_over : function( event, ui ) {\n\t\t\t// when an item is being dragged into the sortable,\n\t\t\t// hide the empty list caption if it exists\n\t\t\tthis._getContainerEl().find( \"> var.empty-list-caption\" ).hide();\n\t\t},\n\n\t\t_onKeydown : function( event ) {\n\t\t\tif( ! this.processKeyEvents ) return true;\n\n\t\t\tvar trap = false;\n\n\t\t\tif( this.getSelectedModels( { by : \"offset\" } ).length == 1 )\n\t\t\t{\n\t\t\t\t// need to trap down and up arrows or else the browser\n\t\t\t\t// will end up scrolling a autoscroll div.\n\n\t\t\t\tvar currentOffset = this.getSelectedModel( { by : \"offset\" } );\n\t\t\t\tif( event.which === this._charCodes.upArrow && currentOffset !== 0 )\n\t\t\t\t{\n\t\t\t\t\tthis.setSelectedModel( currentOffset - 1, { by : \"offset\" } );\n\t\t\t\t\ttrap = true;\n\t\t\t\t}\n\t\t\t\telse if( event.which === this._charCodes.downArrow && currentOffset !== this.collection.length - 1 )\n\t\t\t\t{\n\t\t\t\t\tthis.setSelectedModel( currentOffset + 1, { by : \"offset\" } );\n\t\t\t\t\ttrap = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ! trap;\n\t\t},\n\n\t\t_listItem_onMousedown : function( theEvent ) {\n\t\t\tvar clickedItemId = this._getClickedItemId( theEvent );\n\n\t\t\tif( clickedItemId ) {\n\t\t\t\tvar clickedModel = this.collection.get( clickedItemId );\n\t\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\t\tvar data = {\n\t\t\t\t\t\tclickedModel : clickedModel,\n\t\t\t\t\t\tmetaKeyPressed : theEvent.ctrlKey || theEvent.metaKey\n\t\t\t\t\t};\n\n\t\t\t\t\t_.each( [ 'preventDefault', 'stopPropagation', 'stopImmediatePropagation' ], function( thisMethod ) {\n\t\t\t\t\t\tdata[ thisMethod ] = function() {\n\t\t\t\t\t\t\ttheEvent[ thisMethod ]();\n\t\t\t\t\t\t};\n\t\t\t\t\t} );\n\n\t\t\t\t\tthis.spawn( \"click\", data );\n\t\t\t\t}\n\t\t\t\telse this.trigger( \"click\", clickedModel );\n\t\t\t}\n\n\t\t\tif( ! this.selectable || ! this.clickToSelect ) return;\n\n\t\t\tif( clickedItemId )\n\t\t\t{\n\t\t\t\t// Exit if an unselectable item was clicked\n\t\t\t\tif( _.isFunction( this.selectableModelsFilter ) &&\n\t\t\t\t\t! this.selectableModelsFilter.call( this, this.collection.get( clickedItemId ) ) )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// a selectable list item was clicked\n\t\t\t\tif( this.selectMultiple && theEvent.shiftKey )\n\t\t\t\t{\n\t\t\t\t\tvar firstSelectedItemIndex = -1;\n\n\t\t\t\t\tif( this.selectedItems.length > 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.collection.find( function( thisItemModel ) {\n\t\t\t\t\t\t\tfirstSelectedItemIndex++;\n\n\t\t\t\t\t\t\t// exit when we find our first selected element\n\t\t\t\t\t\t\treturn _.contains( this.selectedItems, thisItemModel.cid );\n\t\t\t\t\t\t}, this );\n\t\t\t\t\t}\n\n\t\t\t\t\tvar clickedItemIndex = -1;\n\t\t\t\t\tthis.collection.find( function( thisItemModel ) {\n\t\t\t\t\t\tclickedItemIndex++;\n\n\t\t\t\t\t\t// exit when we find the clicked element\n\t\t\t\t\t\treturn thisItemModel.cid == clickedItemId;\n\t\t\t\t\t}, this );\n\n\t\t\t\t\tvar shiftKeyRootSelectedItemIndex = firstSelectedItemIndex == -1 ? clickedItemIndex : firstSelectedItemIndex;\n\t\t\t\t\tvar minSelectedItemIndex = Math.min( clickedItemIndex, shiftKeyRootSelectedItemIndex );\n\t\t\t\t\tvar maxSelectedItemIndex = Math.max( clickedItemIndex, shiftKeyRootSelectedItemIndex );\n\n\t\t\t\t\tvar newSelectedItems = [];\n\t\t\t\t\tfor( var thisIndex = minSelectedItemIndex; thisIndex <= maxSelectedItemIndex; thisIndex ++ )\n\t\t\t\t\t\tnewSelectedItems.push( this.collection.at( thisIndex ).cid );\n\t\t\t\t\tthis.setSelectedModels( newSelectedItems, { by : \"cid\" } );\n\n\t\t\t\t\t// shift clicking will usually highlight selectable text, which we do not want.\n\t\t\t\t\t// this is a cross browser (hopefully) snippet that deselects all text selection.\n\t\t\t\t\tif( document.selection && document.selection.empty )\n\t\t\t\t\t\tdocument.selection.empty();\n\t\t\t\t\telse if(window.getSelection) {\n\t\t\t\t\t\tvar sel = window.getSelection();\n\t\t\t\t\t\tif( sel && sel.removeAllRanges )\n\t\t\t\t\t\t\tsel.removeAllRanges();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if( ( this.selectMultiple || _.contains( this.selectedItems, clickedItemId ) ) && ( this.clickToToggle || theEvent.metaKey || theEvent.ctrlKey ) )\n\t\t\t\t{\n\t\t\t\t\tif( _.contains( this.selectedItems, clickedItemId ) )\n\t\t\t\t\t\tthis.setSelectedModels( _.without( this.selectedItems, clickedItemId ), { by : \"cid\" } );\n\t\t\t\t\telse this.setSelectedModels( _.union( this.selectedItems, [clickedItemId] ), { by : \"cid\" } );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tthis.setSelectedModels( [ clickedItemId ], { by : \"cid\" } );\n\t\t\t}\n\t\t\telse\n\t\t\t\t// the blank area of the list was clicked\n\t\t\t\tthis.setSelectedModels( [] );\n\n\t\t},\n\n\t\t_listItem_onDoubleClick : function( theEvent ) {\n\n\t\t\tvar clickedItemId = this._getClickedItemId( theEvent );\n\n\t\t\tif( clickedItemId )\n\t\t\t{\n\t\t\t\tvar clickedModel = this.collection.get( clickedItemId );\n\n\t\t\t\tif( this._isBackboneCourierAvailable() )\n\t\t\t\t\tthis.spawn( \"doubleClick\", { clickedModel : clickedModel, metaKeyPressed : theEvent.ctrlKey || theEvent.metaKey } );\n\t\t\t\telse this.trigger( \"doubleClick\", clickedModel );\n\t\t\t}\n\t\t},\n\n\t\t_listBackground_onClick : function( theEvent ) {\n\t\t\tif( ! this.selectable || ! this.clickToSelect ) return;\n\t\t\tif( ! $( theEvent.target ).is( \".collection-view\" ) ) return;\n\n\t\t\tthis.setSelectedModels( [] );\n\t\t}\n\n\t}, {\n\t\tsetDefaultModelViewConstructor : function( theConstructor ) {\n\t\t\tmDefaultModelViewConstructor = theConstructor;\n\t\t}\n\t});\n\n\t/*\n\t* Backbone.ViewOptions, v0.2.4\n\t* Copyright (c)2014 Rotunda Software, LLC.\n\t* Distributed under MIT license\n\t* http://github.com/rotundasoftware/backbone.viewOptions\n\t*/\n\n\tBackbone.ViewOptions = {};\n\n\tBackbone.ViewOptions.add = function( view, optionsDeclarationsProperty ) {\n\t\tif( _.isUndefined( optionsDeclarationsProperty ) ) optionsDeclarationsProperty = \"options\";\n\n\t\t// ****************** Public methods added to view ******************\n\n\t\tview.setOptions = function( options ) {\n\t\t\tvar _this = this;\n\t\t\tvar optionsThatWereChanged = {};\n\t\t\tvar optionsThatWereChangedPreviousValues = {};\n\n\t\t\tvar optionDeclarations = _.result( this, optionsDeclarationsProperty );\n\n\t\t\tif( ! _.isUndefined( optionDeclarations ) ) {\n\t\t\t\tvar normalizedOptionDeclarations = _normalizeOptionDeclarations( optionDeclarations );\n\n\t\t\t\t_.each( normalizedOptionDeclarations, function( thisOptionProperties, thisOptionName ) {\n\t\t\t\t\tvar thisOptionRequired = thisOptionProperties.required;\n\t\t\t\t\tvar thisOptionDefaultValue = thisOptionProperties.defaultValue;\n\n\t\t\t\t\tif( thisOptionRequired ) {\n\t\t\t\t\t\t// note we do not throw an error if a required option is not supplied, but it is\n\t\t\t\t\t\t// found on the object itself (due to a prior call of view.setOptions, most likely)\n\n\t\t\t\t\t\tif( ( ! options || ! _.contains( _.keys( options ), thisOptionName ) ) && _.isUndefined( _this[ thisOptionName ] ) )\n\t\t\t\t\t\t\tthrow new Error( \"Required option \\\"\" + thisOptionName + \"\\\" was not supplied.\" );\n\n\t\t\t\t\t\tif( options && _.contains( _.keys( options ), thisOptionName ) && _.isUndefined( options[ thisOptionName ] ) )\n\t\t\t\t\t\t\tthrow new Error( \"Required option \\\"\" + thisOptionName + \"\\\" can not be set to undefined.\" );\n\t\t\t\t\t}\n\n\t\t\t\t\t// attach the supplied value of this option, or the appropriate default value, to the view object\n\t\t\t\t\tif( options && thisOptionName in options && ! _.isUndefined( options[ thisOptionName ] ) ) {\n\t\t\t\t\t\tvar oldValue = _this[ thisOptionName ];\n\t\t\t\t\t\tvar newValue = options[ thisOptionName ];\n\t\t\t\t\t\t// if this option already exists on the view, and the new value is different,\n\t\t\t\t\t\t// make a note that we will be changing it\n\t\t\t\t\t\tif( ! _.isUndefined( oldValue ) && oldValue !== newValue ) {\n\t\t\t\t\t\t\toptionsThatWereChangedPreviousValues[ thisOptionName ] = oldValue;\n\t\t\t\t\t\t\toptionsThatWereChanged[ thisOptionName ] = newValue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t_this[ thisOptionName ] = newValue;\n\t\t\t\t\t\t// note we do NOT delete the option off the options object here so that\n\t\t\t\t\t\t// multiple views can be passed the same options object without issue.\n\t\t\t\t\t}\n\t\t\t\t\telse if( _.isUndefined( _this[ thisOptionName ] ) ) {\n\t\t\t\t\t\t// note defaults do not write over any existing properties on the view itself.\n\t\t\t\t\t\t_this[ thisOptionName ] = thisOptionDefaultValue;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif( _.keys( optionsThatWereChanged ).length > 0 ) {\n\t\t\t\tif( _.isFunction( _this.onOptionsChanged ) )\n\t\t\t\t\t_this.onOptionsChanged( optionsThatWereChanged, optionsThatWereChangedPreviousValues );\n\t\t\t\telse if( _.isFunction( _this._onOptionsChanged ) )\n\t\t\t\t\t_this._onOptionsChanged( optionsThatWereChanged, optionsThatWereChangedPreviousValues );\n\t\t\t}\n\t\t};\n\n\t\tview.getOptions = function() {\n\t\t\tvar optionDeclarations = _.result( this, optionsDeclarationsProperty );\n\t\t\tif( _.isUndefined( optionDeclarations ) ) return {};\n\n\t\t\tvar normalizedOptionDeclarations = _normalizeOptionDeclarations( optionDeclarations );\n\t\t\tvar optionsNames = _.keys( normalizedOptionDeclarations );\n\n\t\t\treturn _.pick( this, optionsNames );\n\t\t};\n\t};\n\n\t// ****************** Private Utility Functions ******************\n\n\tfunction _normalizeOptionDeclarations( optionDeclarations ) {\n\t\t// convert our short-hand option syntax (with exclamation marks, etc.)\n\t\t// to a simple array of standard option declaration objects.\n\n\t\tvar normalizedOptionDeclarations = {};\n\n\t\tif( ! _.isArray( optionDeclarations ) ) throw new Error( \"Option declarations must be an array.\" );\n\n\t\t_.each( optionDeclarations, function( thisOptionDeclaration ) {\n\t\t\tvar thisOptionName, thisOptionRequired, thisOptionDefaultValue;\n\n\t\t\tthisOptionRequired = false;\n\t\t\tthisOptionDefaultValue = undefined;\n\n\t\t\tif( _.isString( thisOptionDeclaration ) )\n\t\t\t\tthisOptionName = thisOptionDeclaration;\n\t\t\telse if( _.isObject( thisOptionDeclaration ) ) {\n\t\t\t\tthisOptionName = _.first( _.keys( thisOptionDeclaration ) );\n\t\t\t\tif( _.isFunction( thisOptionDeclaration[ thisOptionName ] ) )\n\t\t\t\t\tthisOptionDefaultValue = thisOptionDeclaration[ thisOptionName ];\n\t\t\t\telse\n\t\t\t\t\tthisOptionDefaultValue = _.clone( thisOptionDeclaration[ thisOptionName ] );\n\t\t\t}\n\t\t\telse throw new Error( \"Each element in the option declarations array must be either a string or an object.\" );\n\n\t\t\tif( thisOptionName[ thisOptionName.length - 1 ] === \"!\" ) {\n\t\t\t\tthisOptionRequired = true;\n\t\t\t\tthisOptionName = thisOptionName.slice( 0, thisOptionName.length - 1 );\n\t\t\t}\n\n\t\t\tnormalizedOptionDeclarations[ thisOptionName ] = normalizedOptionDeclarations[ thisOptionName ] || {};\n\t\t\tnormalizedOptionDeclarations[ thisOptionName ].required = thisOptionRequired;\n\t\t\tif( ! _.isUndefined( thisOptionDefaultValue ) ) normalizedOptionDeclarations[ thisOptionName ].defaultValue = thisOptionDefaultValue;\n\t\t} );\n\n\t\treturn normalizedOptionDeclarations;\n\t}\n\n\n\t// Backbone.BabySitter\n\t// -------------------\n\t// v0.0.6\n\t//\n\t// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.\n\t// Distributed under MIT license\n\t//\n\t// http://github.com/babysitterjs/backbone.babysitter\n\n\t// Backbone.ChildViewContainer\n\t// ---------------------------\n\t//\n\t// Provide a container to store, retrieve and\n\t// shut down child views.\n\n\tChildViewContainer = (function(Backbone, _){\n\n\t\t// Container Constructor\n\t\t// ---------------------\n\n\t\tvar Container = function(views){\n\t\t\tthis._views = {};\n\t\t\tthis._indexByModel = {};\n\t\t\tthis._indexByCustom = {};\n\t\t\tthis._updateLength();\n\n\t\t\t_.each(views, this.add, this);\n\t\t};\n\n\t\t// Container Methods\n\t\t// -----------------\n\n\t\t_.extend(Container.prototype, {\n\n\t\t\t// Add a view to this container. Stores the view\n\t\t\t// by `cid` and makes it searchable by the model\n\t\t\t// cid (and model itself). Optionally specify\n\t\t\t// a custom key to store an retrieve the view.\n\t\t\tadd: function(view, customIndex){\n\t\t\t\tvar viewCid = view.cid;\n\n\t\t\t\t// store the view\n\t\t\t\tthis._views[viewCid] = view;\n\n\t\t\t\t// index it by model\n\t\t\t\tif (view.model){\n\t\t\t\t\tthis._indexByModel[view.model.cid] = viewCid;\n\t\t\t\t}\n\n\t\t\t\t// index by custom\n\t\t\t\tif (customIndex){\n\t\t\t\t\tthis._indexByCustom[customIndex] = viewCid;\n\t\t\t\t}\n\n\t\t\t\tthis._updateLength();\n\t\t\t},\n\n\t\t\t// Find a view by the model that was attached to\n\t\t\t// it. Uses the model's `cid` to find it.\n\t\t\tfindByModel: function(model){\n\t\t\t\treturn this.findByModelCid(model.cid);\n\t\t\t},\n\n\t\t\t// Find a view by the `cid` of the model that was attached to\n\t\t\t// it. Uses the model's `cid` to find the view `cid` and\n\t\t\t// retrieve the view using it.\n\t\t\tfindByModelCid: function(modelCid){\n\t\t\t\tvar viewCid = this._indexByModel[modelCid];\n\t\t\t\treturn this.findByCid(viewCid);\n\t\t\t},\n\n\t\t\t// Find a view by a custom indexer.\n\t\t\tfindByCustom: function(index){\n\t\t\t\tvar viewCid = this._indexByCustom[index];\n\t\t\t\treturn this.findByCid(viewCid);\n\t\t\t},\n\n\t\t\t// Find by index. This is not guaranteed to be a\n\t\t\t// stable index.\n\t\t\tfindByIndex: function(index){\n\t\t\t\treturn _.values(this._views)[index];\n\t\t\t},\n\n\t\t\t// retrieve a view by it's `cid` directly\n\t\t\tfindByCid: function(cid){\n\t\t\t\treturn this._views[cid];\n\t\t\t},\n\n\t\t\tfindIndexByCid : function( cid ) {\n\t\t\t\tvar index = -1;\n\t\t\t\tvar view = _.find( this._views, function ( view ) {\n\t\t\t\t\tindex++;\n\t\t\t\t\tif( view.model.cid == cid )\n\t\t\t\t\t\treturn view;\n\t\t\t\t} );\n\t\t\t\treturn ( view ) ? index : -1;\n\t\t\t},\n\n\t\t\t// Remove a view\n\t\t\tremove: function(view){\n\t\t\t\tvar viewCid = view.cid;\n\n\t\t\t\t// delete model index\n\t\t\t\tif (view.model){\n\t\t\t\t\tdelete this._indexByModel[view.model.cid];\n\t\t\t\t}\n\n\t\t\t\t// delete custom index\n\t\t\t\t_.any(this._indexByCustom, function(cid, key) {\n\t\t\t\t\tif (cid === viewCid) {\n\t\t\t\t\t\tdelete this._indexByCustom[key];\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}, this);\n\n\t\t\t\t// remove the view from the container\n\t\t\t\tdelete this._views[viewCid];\n\n\t\t\t\t// update the length\n\t\t\t\tthis._updateLength();\n\t\t\t},\n\n\t\t\t// Call a method on every view in the container,\n\t\t\t// passing parameters to the call method one at a\n\t\t\t// time, like `function.call`.\n\t\t\tcall: function(method){\n\t\t\t\tthis.apply(method, _.tail(arguments));\n\t\t\t},\n\n\t\t\t// Apply a method on every view in the container,\n\t\t\t// passing parameters to the call method one at a\n\t\t\t// time, like `function.apply`.\n\t\t\tapply: function(method, args){\n\t\t\t\t_.each(this._views, function(view){\n\t\t\t\t\tif (_.isFunction(view[method])){\n\t\t\t\t\t\tview[method].apply(view, args || []);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\n\t\t\t// Update the `.length` attribute on this container\n\t\t\t_updateLength: function(){\n\t\t\t\tthis.length = _.size(this._views);\n\t\t\t}\n\t\t});\n\n\t\t// Borrowing this code from Backbone.Collection:\n\t\t// http://backbonejs.org/docs/backbone.html#section-106\n\t\t//\n\t\t// Mix in methods from Underscore, for iteration, and other\n\t\t// collection related features.\n\t\tvar methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',\n\t\t\t 'select', 'reject', 'every', 'all', 'some', 'any', 'include',\n\t\t\t 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',\n\t\t\t 'last', 'without', 'isEmpty', 'pluck'];\n\n\t\t_.each(methods, function(method) {\n\t\t\tContainer.prototype[method] = function() {\n\t\t\t\tvar views = _.values(this._views);\n\t\t\t\tvar args = [views].concat(_.toArray(arguments));\n\t\t\t\treturn _[method].apply(_, args);\n\t\t\t};\n\t\t});\n\n\t\t// return the public API\n\t\treturn Container;\n\t})(Backbone, _);\n\n\treturn Backbone.CollectionView;\n} ) );\n\n","//\n// backbone.trackit - 0.1.0\n// The MIT License\n// Copyright (c) 2013 The New York Times, CMS Group, Matthew DeLambo \n//\n(function() {\n\n\t// Unsaved Record Keeping\n\t// ----------------------\n\n\t// Collection of all models in an app that have unsaved changes.\n\tvar unsavedModels = [];\n\n\t// If the given model has unsaved changes then add it to\n\t// the `unsavedModels` collection, otherwise remove it.\n\tvar updateUnsavedModels = function(model) {\n\t\tif (!_.isEmpty(model._unsavedChanges)) {\n\t\t\tif (!_.findWhere(unsavedModels, {cid:model.cid})) unsavedModels.push(model);\n\t\t} else {\n\t\t\tunsavedModels = _.filter(unsavedModels, function(m) { return model.cid != m.cid; });\n\t\t}\n\t};\n\n\t// Unload Handlers\n\t// ---------------\n\n\t// Helper which returns a prompt message for an unload handler.\n\t// Uses the given function name (one of the callback names\n\t// from the `model.unsaved` configuration hash) to evaluate\n\t// whether a prompt is needed/returned.\n\tvar getPrompt = function(fnName) {\n\t\tvar prompt, args = _.rest(arguments);\n\t\t// Evaluate and return a boolean result. The given `fn` may be a\n\t\t// boolean value, a function, or the name of a function on the model.\n\t\tvar evaluateModelFn = function(model, fn) {\n\t\t\tif (_.isBoolean(fn)) return fn;\n\t\t\treturn (_.isString(fn) ? model[fn] : fn).apply(model, args);\n\t\t};\n\t\t_.each(unsavedModels, function(model) {\n\t\t\tif (!prompt && evaluateModelFn(model, model._unsavedConfig[fnName]))\n\t\t\t\tprompt = model._unsavedConfig.prompt;\n\t\t});\n\t\treturn prompt;\n\t};\n\n\t// Wrap Backbone.History.navigate so that in-app routing\n\t// (`router.navigate('/path')`) can be intercepted with a\n\t// confirmation if there are any unsaved models.\n\tBackbone.History.prototype.navigate = _.wrap(Backbone.History.prototype.navigate, function(oldNav, fragment, options) {\n\t\tvar prompt = getPrompt('unloadRouterPrompt', fragment, options);\n\t\tif (prompt) {\n\t\t\tif (confirm(prompt + ' \\n\\nAre you sure you want to leave this page?')) {\n\t\t\t\toldNav.call(this, fragment, options);\n\t\t\t}\n\t\t} else {\n\t\t\toldNav.call(this, fragment, options);\n\t\t}\n\t});\n\n\t// Create a browser unload handler which is triggered\n\t// on the refresh, back, or forward button.\n\twindow.onbeforeunload = function(e) {\n\t\treturn getPrompt('unloadWindowPrompt', e);\n\t};\n\n\t// Backbone.Model API\n\t// ------------------\n\n\t_.extend(Backbone.Model.prototype, {\n\n\t\tunsaved: {},\n\t\t_trackingChanges: false,\n\t\t_originalAttrs: {},\n\t\t_unsavedChanges: {},\n\n\t\t// Opt in to tracking attribute changes\n\t\t// between saves.\n\t\tstartTracking: function() {\n\t\t\tthis._unsavedConfig = _.extend({}, {\n\t\t\t\tprompt: 'You have unsaved changes!',\n\t\t\t\tunloadRouterPrompt: false,\n\t\t\t\tunloadWindowPrompt: false\n\t\t\t}, this.unsaved || {});\n\t\t\tthis._trackingChanges = true;\n\t\t\tthis._resetTracking();\n\t\t\tthis._triggerUnsavedChanges();\n\t\t\treturn this;\n\t\t},\n\n\t\t// Resets the default tracking values\n\t\t// and stops tracking attribute changes.\n\t\tstopTracking: function() {\n\t\t\tthis._trackingChanges = false;\n\t\t\tthis._originalAttrs = {};\n\t\t\tthis._unsavedChanges = {};\n\t\t\tthis._triggerUnsavedChanges();\n\t\t\treturn this;\n\t\t},\n\n\t\t// Gets rid of accrued changes and\n\t\t// resets state.\n\t\trestartTracking: function() {\n\t\t\tthis._resetTracking();\n\t\t\tthis._triggerUnsavedChanges();\n\t\t\treturn this;\n\t\t},\n\n\t\t// Restores this model's attributes to\n\t\t// their original values since tracking\n\t\t// started, the last save, or last restart.\n\t\tresetAttributes: function() {\n\t\t\tif (!this._trackingChanges) return;\n\t\t\tthis.attributes = this._originalAttrs;\n\t\t\tthis._resetTracking();\n\t\t\tthis._triggerUnsavedChanges();\n\t\t\treturn this;\n\t\t},\n\n\t\t// Symmetric to Backbone's `model.changedAttributes()`,\n\t\t// except that this returns a hash of the model's attributes that\n\t\t// have changed since the last save, or `false` if there are none.\n\t\t// Like `changedAttributes`, an external attributes hash can be\n\t\t// passed in, returning the attributes in that hash which differ\n\t\t// from the model.\n\t\tunsavedAttributes: function(attrs) {\n\t\t\tif (!attrs) return _.isEmpty(this._unsavedChanges) ? false : _.clone(this._unsavedChanges);\n\t\t\tvar val, changed = false, old = this._unsavedChanges;\n\t\t\tfor (var attr in attrs) {\n\t\t\t\tif (_.isEqual(old[attr], (val = attrs[attr]))) continue;\n\t\t\t\t(changed || (changed = {}))[attr] = val;\n\t\t\t}\n\t\t\treturn changed;\n\t\t},\n\n\t\t_resetTracking: function() {\n\t\t\tthis._originalAttrs = _.clone(this.attributes);\n\t\t\tthis._unsavedChanges = {};\n\t\t},\n\n\t\t// Trigger an `unsavedChanges` event on this model,\n\t\t// supplying the result of whether there are unsaved\n\t\t// changes and a changed attributes hash.\n\t\t_triggerUnsavedChanges: function() {\n\t\t\tthis.trigger('unsavedChanges', !_.isEmpty(this._unsavedChanges), _.clone(this._unsavedChanges));\n\t\t\tif (this.unsaved) updateUnsavedModels(this);\n\t\t}\n\t});\n\n\t// Wrap `model.set()` and update the internal\n\t// unsaved changes record keeping.\n\tBackbone.Model.prototype.set = _.wrap(Backbone.Model.prototype.set, function(oldSet, key, val, options) {\n\t\tvar attrs, ret;\n\t\tif (key == null) return this;\n\t\t// Handle both `\"key\", value` and `{key: value}` -style arguments.\n\t\tif (typeof key === 'object') {\n\t\t\tattrs = key;\n\t\t\toptions = val;\n\t\t} else {\n\t\t\t(attrs = {})[key] = val;\n\t\t}\n\t\toptions || (options = {});\n\n\t\t// Delegate to Backbone's set.\n\t\tret = oldSet.call(this, attrs, options);\n\n\t\tif (this._trackingChanges && !options.silent) {\n\t\t\t_.each(attrs, _.bind(function(val, key) {\n\t\t\t\tif (_.isEqual(this._originalAttrs[key], val))\n\t\t\t\t\tdelete this._unsavedChanges[key];\n\t\t\t\telse\n\t\t\t\t\tthis._unsavedChanges[key] = val;\n\t\t\t}, this));\n\t\t\tthis._triggerUnsavedChanges();\n\t\t}\n\t\treturn ret;\n\t});\n\n\t// Intercept `model.save()` and reset tracking/unsaved\n\t// changes if it was successful.\n\tBackbone.sync = _.wrap(Backbone.sync, function(oldSync, method, model, options) {\n\t\toptions || (options = {});\n\n\t\tif (method == 'update') {\n\t\t\toptions.success = _.wrap(options.success, _.bind(function(oldSuccess, data, textStatus, jqXHR) {\n\t\t\t\tvar ret;\n\t\t\t\tif (oldSuccess) ret = oldSuccess.call(this, data, textStatus, jqXHR);\n\t\t\t\tif (model._trackingChanges) {\n\t\t\t\t\tmodel._resetTracking();\n\t\t\t\t\tmodel._triggerUnsavedChanges();\n\t\t\t\t}\n\t\t\t\treturn ret;\n\t\t\t}, this));\n\t\t}\n\t\treturn oldSync(method, model, options);\n\t});\n\n})();\ndefine(\"vendor/backbone.trackit\", function(){});\n\n","/**\n * Image object model for use in various models for the 'image' attribute\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Models/Image',[], function() {\n\n\treturn Backbone.Model.extend( {\n\n\t\tdefaults: {\n\t\t\tenabled: 'no',\n\t\t\tid: '',\n\t\t\tsize: 'full',\n\t\t\tsrc: '',\n\t\t},\n\n\t\tinitialize: function() {\n\t\t\tthis.startTracking();\n\t\t},\n\n\t} );\n} );\n\n","/**\n * Model relationships mixin\n * @since 3.16.0\n * @version 3.16.11\n */\ndefine( 'Models/_Relationships',[], function() {\n\n\treturn {\n\n\t\t/**\n\t\t * Default relationship settings object\n\t\t * @type {Object}\n\t\t */\n\t\trelationship_defaults: {\n\t\t\tparent: {},\n\t\t\tchildren: {},\n\t\t},\n\n\t\t/**\n\t\t * Relationship settings object\n\t\t * Should be overriden in the model\n\t\t * @type {Object}\n\t\t */\n\t\trelationships: {},\n\n\t\t/**\n\t\t * Initialize all parent and child relationships\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinit_relationships: function( options ) {\n\n\t\t\tvar rels = this.get_relationships();\n\n\t\t\t// initialize parent relaxtionships\n\t\t\t// useful when adding a model to ensure parent is initialized\n\t\t\tif ( rels.parent && options && options.parent ) {\n\t\t\t\tthis.set_parent( options.parent );\n\t\t\t}\n\n\t\t\t// initialize all children relationships\n\t\t\t_.each( rels.children, function( child_data, child_key ) {\n\n\t\t\t\tif ( ! child_data.conditional || true === child_data.conditional( this ) ) {\n\n\t\t\t\t\tvar child_val = this.get( child_key ),\n\t\t\t\t\t\tchild;\n\n\t\t\t\t\tif ( child_data.lookup ) {\n\t\t\t\t\t\tchild = child_data.lookup( child_val );\n\t\t\t\t\t} else if ( 'model' === child_data.type ) {\n\t\t\t\t\t\tchild = window.llms_builder.construct.get_model( child_data.class, child_val );\n\t\t\t\t\t} else if ( 'collection' === child_data.type ) {\n\t\t\t\t\t\tchild = window.llms_builder.construct.get_collection( child_data.class, child_val );\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.set( child_key, child );\n\n\t\t\t\t\t// if the child defines a parent, save a reference to the parent on the child\n\t\t\t\t\tif ( 'model' === child_data.type ) {\n\t\t\t\t\t\tthis._maybe_set_parent_reference( child );\n\n\t\t\t\t\t// save directly to each model in the collection\n\t\t\t\t\t} else if ( 'collection' === child_data.type ) {\n\n\t\t\t\t\t\tchild.parent = this;\n\t\t\t\t\t\tchild.each( function( child_model ) {\n\n\t\t\t\t\t\t\tthis._maybe_set_parent_reference( child_model );\n\n\t\t\t\t\t\t}, this );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the property names for all children of the model\n\t\t * @return array\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\tget_child_props: function() {\n\n\t\t\tvar props = [];\n\n\t\t\t_.each( this.get_relationships().children, function( data, key ) {\n\n\t\t\t\tif ( ! data.conditional || true === data.conditional( this ) ) {\n\t\t\t\t\tprops.push( key );\n\t\t\t\t}\n\n\t\t\t}, this );\n\n\t\t\treturn props;\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the model's parent (if set)\n\t\t * @return obj|false\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_parent: function() {\n\n\t\t\tvar rels = this.get_relationships();\n\n\t\t\tif ( rels.parent ) {\n\t\t\t\treturn rels.parent.reference;\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve relationships for the model\n\t\t * Extends with defaults\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_relationships: function() {\n\n\t\t\treturn $.extend( true, this.relationships, this.relationship_defaults );\n\n\t\t},\n\n\t\t/**\n\t\t * Set the parent reference for the given model\n\t\t * @param obj obj parent model obj\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tset_parent: function( obj ) {\n\t\t\tthis.relationships.parent.reference = obj;\n\t\t},\n\n\t\t/**\n\t\t * Set up the parent relationships for qualifying children during relationship initialization\n\t\t * @param obj model child model\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t_maybe_set_parent_reference: function( model ) {\n\n\t\t\tif ( ! model || ! model.get_relationships ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar rels = model.get_relationships();\n\t\t\tif ( rels.parent && rels.parent.model === this.get( 'type' ) ) {\n\t\t\t\tmodel.set_parent( this );\n\t\t\t}\n\n\t\t},\n\n\t};\n\n} );\n\n","/**\n * Quiz Question Choice\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Models/QuestionChoice',[ 'Models/Image', 'Models/_Relationships' ], function( Image, Relationships ) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\t/**\n\t\t * Model relationships\n\t\t * @type {Object}\n\t\t */\n\t\trelationships: {\n\t\t\tparent: {\n\t\t\t\tmodel: 'llms_question',\n\t\t\t\ttype: 'model',\n\t\t\t},\n\t\t\tchildren: {\n\t\t\t\tchoice: {\n\t\t\t\t\tconditional: function( model ) {\n\t\t\t\t\t\treturn ( 'image' === model.get( 'choice_type' ) );\n\t\t\t\t\t},\n\t\t\t\t\tclass: 'Image',\n\t\t\t\t\tmodel: 'image',\n\t\t\t\t\ttype: 'model',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Model defaults\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tid: _.uniqueId( 'temp_' ),\n\t\t\t\tchoice: '',\n\t\t\t\tchoice_type: 'text',\n\t\t\t\tcorrect: false,\n\t\t\t\tmarker: 'A',\n\t\t\t\tquestion_id: '',\n\t\t\t\ttype: 'choice',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Initializer\n\t\t * @param obj data object of model attributes\n\t\t * @param obj options additional options\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function( data, options ) {\n\n\t\t\tthis.startTracking();\n\t\t\tthis.init_relationships( options );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the choice's parent question\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_parent: function() {\n\t\t\treturn this.collection.parent;\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the ID used when trashing the model\n\t\t * @return string\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\tget_trash_id: function() {\n\t\t\treturn this.get( 'question_id' ) + ':' + this.get( 'id' );\n\t\t},\n\n\t\t/**\n\t\t * Determine if \"selection\" is enabled for the question type\n\t\t * Choice type questions are selectable by reorder type questions are not but still use choices\n\t\t * @return {Boolean}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tis_selectable: function() {\n\t\t\treturn this.get_parent().get( 'question_type' ).get_choice_selectable();\n\t\t},\n\n\t}, Relationships ) );\n\n} );\n\n","/**\n * Question Choice Collection\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Collections/QuestionChoices',[ 'Models/QuestionChoice' ], function( model ) {\n\n\treturn Backbone.Collection.extend( {\n\n\t\t/**\n\t\t * Model for collection items\n\t\t * @type obj\n\t\t */\n\t\tmodel: model,\n\n\t\tinitialize: function() {\n\n\t\t\t// reorder called by QuestionList view when sortable drops occur\n\t\t\tthis.on( 'reorder', this.update_order );\n\n\t\t\t// when a choice is added or removed, update order\n\t\t\tthis.on( 'add', this.update_order );\n\t\t\tthis.on( 'remove', this.update_order );\n\n\t\t\t// when a choice is added or remove, ensure min/max correct answers exist\n\t\t\tthis.on( 'add', this.update_correct );\n\t\t\tthis.on( 'remove', this.update_correct );\n\n\t\t\t// when a choice is toggled, ensure min/max correct exist\n\t\t\tthis.on( 'correct-update', this.update_correct );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the number of correct choices in the collection\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tcount_correct: function() {\n\n\t\t\treturn _.size( this.get_correct() );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the collection reduced to only correct choices\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_correct: function() {\n\t\t\treturn this.filter( function( choice ) {\n\t\t\t\treturn choice.get( 'correct' );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Ensure min/max correct choices exist in the collection based on the question's settings\n\t\t * @param obj choice model of the choice that was toggled\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_correct: function( choice ) {\n\n\t\t\tif ( ! this.parent.get( 'question_type' ).get_choice_selectable() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar siblings = this.without( choice ), // exclude the toggled choice from loops\n\t\t\t\tquestion = this.parent;\n\n\t\t\t// if multiple choices aren't enabled turn all other choices to incorrect\n\t\t\tif ( 'no' === question.get( 'multi_choices' ) ) {\n\t\t\t\t_.each( siblings, function( model ) {\n\t\t\t\t\tmodel.set( 'correct', false );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// if we don't have a single corret answer & the question has points, set one\n\t\t\t// allows users to create quizzes / questions with no points and therefore no correct answers are allowed\n\t\t\tif ( 0 === this.count_correct() && question.get( 'points' ) > 0 ) {\n\t\t\t\tvar models = 1 === this.size() ? this.models : siblings;\n\t\t\t\t_.first( models ).set( 'correct', true );\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Update the marker attr of each choice in the list to reflect the order of the collection\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_order: function() {\n\n\t\t\tvar self = this,\n\t\t\t\tquestion = this.parent;\n\n\t\t\tthis.each( function( choice ) {\n\t\t\t\tchoice.set( 'marker', question.get( 'question_type' ).get_choice_markers()[ self.indexOf( choice ) ] );\n\t\t\t} );\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Quiz Question Type\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Models/QuestionType',[], function() {\n\n\treturn Backbone.Model.extend( {\n\n\t\t/**\n\t\t * Get model default attributes\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tchoices: false,\n\t\t\t\tclarifications: true,\n\t\t\t\tdefault_choices: [],\n\t\t\t\tdescription: true,\n\t\t\t\ticon: 'question',\n\t\t\t\tid: 'generic',\n\t\t\t\timage: true,\n\t\t\t\tkeywords: [],\n\t\t\t\tname: 'Generic',\n\t\t\t\tplaceholder: '',\n\t\t\t\tpoints: true,\n\t\t\t\tvideo: true,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Retrieve an array of keywords for the question type\n\t\t * Used for filtering questions by search term in the quiz builder\n\t\t * @return array\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_keywords: function() {\n\n\t\t\tvar name = this.get( 'name' ),\n\t\t\t\twords = [ name ];\n\n\t\t\treturn words.concat( this.get( 'keywords' ) ).concat( name.split( ' ' ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Get marker array for the question choices\n\t\t * @return array\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_choice_markers: function() {\n\n\t\t\treturn this._get_choice_option( 'markers' );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if the question's choices are selectable\n\t\t * @return bool\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_choice_selectable: function() {\n\n\t\t\treturn this._get_choice_option( 'selectable' );\n\n\t\t},\n\n\t\t/**\n\t\t * Get the choice type (text,image)\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_choice_type: function() {\n\n\t\t\treturn this._get_choice_option( 'type' );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve defined min. choices\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_min_choices: function() {\n\n\t\t\treturn this._get_choice_option( 'min' );\n\n\t\t},\n\n\t\t/**\n\t\t * Get type-defined max choices\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_max_choices: function() {\n\n\t\t\treturn this._get_choice_option( 'max' );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if multi-choice selection is enabled\n\t\t * @return bool\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_multi_choices: function() {\n\n\t\t\tvar choices = this.get( 'choices' );\n\n\t\t\tif ( ! choices ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn this._get_choice_option( 'multi' );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve data from the type's \"choices\" attribute\n\t\t * Allows quick handling of types with no choice definitions w/o additional checks\n\t\t * @param string option name of the choice option to retrieve\n\t\t * @return mixed\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t_get_choice_option: function( option ) {\n\n\t\t\tvar choices = this.get( 'choices' );\n\n\t\t\tif ( ! choices || ! choices[ option ] ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn choices[ option ];\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Quiz Question\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Models/Question',[\n\t\t'Models/Image',\n\t\t'Collections/Questions',\n\t\t'Collections/QuestionChoices',\n\t\t'Models/QuestionType',\n\t\t'Models/_Relationships'\n\t], function(\n\t\tImage,\n\t\tQuestions,\n\t\tQuestionChoices,\n\t\tQuestionType,\n\t\tRelationships\n\t) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\t/**\n\t\t * Model relationships\n\t\t * @type {Object}\n\t\t */\n\t\trelationships: {\n\t\t\tparent: {\n\t\t\t\tmodel: 'llms_quiz',\n\t\t\t\ttype: 'model',\n\t\t\t},\n\t\t\tchildren: {\n\t\t\t\tchoices: {\n\t\t\t\t\tclass: 'QuestionChoices',\n\t\t\t\t\tmodel: 'choice',\n\t\t\t\t\ttype: 'collection',\n\t\t\t\t},\n\t\t\t\timage: {\n\t\t\t\t\tclass: 'Image',\n\t\t\t\t\tmodel: 'image',\n\t\t\t\t\ttype: 'model',\n\t\t\t\t},\n\t\t\t\tquestions: {\n\t\t\t\t\tclass: 'Questions',\n\t\t\t\t\tconditional: function( model ) {\n\t\t\t\t\t\tvar type = model.get( 'question_type' ),\n\t\t\t\t\t\t\ttype_id = _.isString( type ) ? type : type.get( 'id' );\n\t\t\t\t\t\treturn ( 'group' === type_id );\n\t\t\t\t\t},\n\t\t\t\t\tmodel: 'llms_question',\n\t\t\t\t\ttype: 'collection',\n\t\t\t\t},\n\t\t\t\tquestion_type: {\n\t\t\t\t\tclass: 'QuestionType',\n\t\t\t\t\tlookup: function( val ) {\n\t\t\t\t\t\tif ( _.isString( val ) ) {\n\t\t\t\t\t\t\treturn window.llms_builder.questions.get( val );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn val;\n\t\t\t\t\t},\n\t\t\t\t\tmodel: 'question_type',\n\t\t\t\t\ttype: 'model',\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Model defaults\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tid: _.uniqueId( 'temp_' ),\n\t\t\t\tchoices: [],\n\t\t\t\tcontent: '',\n\t\t\t\tdescription_enabled: 'no',\n\t\t\t\timage: {},\n\t\t\t\tmulti_choices: 'no',\n\t\t\t\tmenu_order: 1,\n\t\t\t\tpoints: 1,\n\t\t\t\tquestion_type: 'generic',\n\t\t\t\tquestions: [], // for question groups\n\t\t\t\tparent_id: '',\n\t\t\t\ttitle: '',\n\t\t\t\ttype: 'llms_question',\n\t\t\t\tvideo_enabled: 'no',\n\t\t\t\tvideo_src: '',\n\n\t\t\t\t_expanded: false,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Initializer\n\t\t * @param obj data object of data for the model\n\t\t * @param obj options additional options\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function( data, options ) {\n\n\t\t\tvar self = this;\n\n\t\t\tthis.startTracking();\n\t\t\tthis.init_relationships( options );\n\n\t\t\tif ( false !== this.get( 'question_type' ).choices ) {\n\n\t\t\t\tthis._ensure_min_choices();\n\n\t\t\t\t// when a choice is removed, maybe add back some defaults so we always have the minimum\n\t\t\t\tthis.listenTo( this.get( 'choices' ), 'remove', function() {\n\t\t\t\t\t// new itmes are added at index 0 when there's only 1 item in the collection, not sure why exactly...\n\t\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t\tself._ensure_min_choices();\n\t\t\t\t\t}, 0 );\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\t// ensure question types that don't support points don't record default 1 point in database\n\t\t\tif ( ! this.get( 'question_type' ).get( 'points' ) ) {\n\t\t\t\tthis.set( 'points', 0 );\n\t\t\t}\n\n\t\t\t_.delay( function( self ) {\n\t\t\t\tself.on( 'change:points', self.get_parent().update_points, self.get_parent() );\n\t\t\t}, 1, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Add a new question choice\n\t\t * @param obj data object of choice data\n\t\t * @param obj options additional options\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tadd_choice: function( data, options ) {\n\n\t\t\tvar max = this.get( 'question_type' ).get_max_choices();\n\t\t\tif ( this.get( 'choices' ).size() >= max ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tdata = data || {};\n\t\t\toptions = options || {};\n\n\t\t\tdata.choice_type = this.get( 'question_type' ).get_choice_type();\n\t\t\tdata.question_id = this.get( 'id' );\n\t\t\toptions.parent = this;\n\n\t\t\tvar choice = this.get( 'choices' ).add( data, options );\n\n\t\t\tBackbone.pubSub.trigger( 'question-add-choice', choice, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Collapse question_type attribute during full syncs to save to database\n\t\t * Not needed because question types cannot be adjusted after question creation\n\t\t * Called from sync controller\n\t\t * @param obj atts flat object of attributes to be saved to db\n\t\t * @param string sync_type full or partial\n\t\t * full indicates a force resync or that the model isn't persisted yet\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tbefore_save: function( atts, sync_type ) {\n\t\t\tif ( 'full' === sync_type ) {\n\t\t\t\tatts.question_type = this.get( 'question_type' ).get( 'id' );\n\t\t\t}\n\t\t\treturn atts;\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the model's parent (if set)\n\t\t * @return obj|false\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_parent: function() {\n\n\t\t\tvar rels = this.get_relationships();\n\n\t\t\tif ( rels.parent ) {\n\t\t\t\tif ( this.collection && this.collection.parent ) {\n\t\t\t\t\treturn this.collection.parent;\n\t\t\t\t} else if ( rels.parent.reference ) {\n\t\t\t\t\treturn rels.parent.reference;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\t/**\n\t\t * Gets the index of the question within it's parent\n\t\t * Question numbers skip content elements\n\t\t * & content elements skip questions\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_type_index: function() {\n\n\t\t\t// current models type, used to check the predicate in the filter function below\n\t\t\tvar curr_type = this.get( 'question_type' ).get( 'id' ),\n\t\t\t\tquestions;\n\n\t\t\tquestions = this.collection.filter( function( question ) {\n\n\t\t\t\tvar type = question.get( 'question_type' ).get( 'id' );\n\n\t\t\t\t// if current model is not content, return all non-content questions\n\t\t\t\tif ( curr_type !== 'content' ) {\n\t\t\t\t\treturn ( 'content' !== type );\n\t\t\t\t}\n\n\t\t\t\t// current model is content, return only content questions\n\t\t\t\treturn 'content' === type;\n\n\t\t\t} );\n\n\t\t\treturn questions.indexOf( this );\n\n\t\t},\n\n\t\t/**\n\t\t * Gets iterator for the given type\n\t\t * Questions use numbers and content uses alphabet\n\t\t * @return mixed\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_type_iterator: function() {\n\n\t\t\tvar index = this.get_type_index();\n\n\t\t\tif ( -1 === index ) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tif ( 'content' === this.get( 'question_type' ).get( 'id' ) ) {\n\t\t\t\tvar alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split( '' );\n\t\t\t\treturn alphabet[ index ];\n\t\t\t}\n\n\t\t\treturn index + 1;\n\n\t\t},\n\n\n\t\tget_qid: function() {\n\n\t\t\tvar parent = this.get_parent_question(),\n\t\t\t\tprefix = '';\n\n\t\t\tif ( parent ) {\n\n\t\t\t\tprefix = parent.get_qid() + '.';\n\n\t\t\t}\n\n\t\t\t// return short_id + this.get_type_iterator();\n\t\t\treturn prefix + this.get_type_iterator();\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the parent question (if the question is in a question group)\n\t\t * @return obj|false\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_parent_question: function() {\n\n\t\t\tif ( this.is_in_group() ) {\n\n\t\t\t\treturn this.collection.parent;\n\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the parent quiz\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_parent_quiz: function() {\n\t\t\treturn this.get_parent();\n\t\t},\n\n\t\t/**\n\t\t * Points getter\n\t\t * ensures that 0 is always returned if the question type doesn't support points\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_points: function() {\n\n\t\t\tif ( ! this.get( 'question_type' ).get( 'points' ) ) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn this.get( 'points' );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the questions percentage value within the quiz\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_points_percentage: function() {\n\n\t\t\tvar total = this.get_parent().get( '_points' ),\n\t\t\t\tpoints = this.get( 'points' );\n\n\t\t\tif ( 0 === total ) {\n\t\t\t\treturn '0%';\n\t\t\t}\n\n\t\t\treturn ( ( points / total ) * 100 ).toFixed( 2 ) + '%';\n\n\t\t},\n\n\t\t/**\n\t\t * Deterine if the question belongs to a question group\n\t\t * @return {Boolean}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tis_in_group: function() {\n\n\t\t\treturn ( 'question' === this.collection.parent.get( 'type' ) );\n\n\t\t},\n\n\t\t_ensure_min_choices: function() {\n\n\t\t\tvar choices = this.get( 'choices' );\n\t\t\twhile ( choices.size() < this.get( 'question_type' ).get_min_choices() ) {\n\t\t\t\tthis.add_choice();\n\t\t\t}\n\n\t\t},\n\n\t}, Relationships ) );\n\n} );\n\n","/**\n * Questions Collection\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Collections/Questions',[ 'Models/Question' ], function( model ) {\n\n\treturn Backbone.Collection.extend( {\n\n\t\t/**\n\t\t * Model for collection items\n\t\t * @type obj\n\t\t */\n\t\tmodel: model,\n\n\t\t/**\n\t\t * Initialize\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\t// reorder called by QuestionList view when sortable drops occur\n\t\t\tthis.on( 'reorder', this.update_order );\n\n\t\t\t// when a question is added or removed, update order\n\t\t\tthis.on( 'add', this.update_order );\n\t\t\tthis.on( 'remove', this.update_order );\n\n\t\t\tthis.on( 'add', this.update_parent );\n\n\t\t},\n\n\t\t/**\n\t\t * Update the order attr of each question in the list to reflect the order of the collection\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_order: function() {\n\n\t\t\tvar self = this;\n\n\t\t\tthis.each( function( question ) {\n\n\t\t\t\tquestion.set( 'menu_order', self.indexOf( question ) + 1 );\n\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * When adding a question to a question list, update the question's parent\n\t\t * Will ensure that questions moved into and out of groups always have the corerct parent_id\n\t\t * @param obj model instance of the question model\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_parent: function( model ) {\n\n\t\t\tmodel.set( 'parent_id', this.parent.get( 'id' ) );\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Utility functions for Models\n * @since 3.16.0\n * @version 3.17.1\n */\ndefine( 'Models/_Utilities',[], function() {\n\n\treturn {\n\n\t\tfields: [],\n\n\t\t/**\n\t\t * Retrieve the edit post link for the current model\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_edit_post_link: function() {\n\n\t\t\tif ( this.has_temp_id() ) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\treturn window.llms_builder.admin_url + 'post.php?post=' + this.get( 'id' ) + '&action=edit';\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve schema fields defined for the model\n\t\t * @return object\n\t\t * @since 3.17.0\n\t\t * @version 3.17.1\n\t\t */\n\t\tget_settings_fields: function() {\n\n\t\t\tvar schema = this.schema || {};\n\t\t\treturn window.llms_builder.schemas.get( schema, this.get( 'type' ).replace( 'llms_', '' ), this );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if the model has a temporary ID\n\t\t * @return {Boolean}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\thas_temp_id: function() {\n\n\t\t\treturn ( ! _.isNumber( this.get( 'id' ) ) && 0 === this.get( 'id' ).indexOf( 'temp_' ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Initializes 3rd party custom schema (field) data for a model\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tinit_custom_schema: function() {\n\n\t\t\tvar groups = _.filter( this.get_settings_fields(), function( group ) {\n\t\t\t\treturn ( group.custom );\n\t\t\t} );\n\n\t\t\t_.each( groups, function( group ) {\n\t\t\t\t_.each( _.flatten( group.fields ), function( field ) {\n\n\n\t\t\t\t\tvar keys = [ field.attribute ],\n\t\t\t\t\t\tcustoms = this.get( 'custom' );\n\n\t\t\t\t\tif ( field.switch_attribute ) {\n\t\t\t\t\t\tkeys.push( field.switch_attribute );\n\t\t\t\t\t}\n\n\t\t\t\t\t_.each( keys, function( key ) {\n\t\t\t\t\t\tvar attr = field.attribute_prefix ? field.attribute_prefix + key : key;\n\t\t\t\t\t\tif ( customs && customs[ attr ] ) {\n\t\t\t\t\t\t\tthis.set( key, customs[ attr ][0] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}, this );\n\n\t\t\t\t}, this );\n\t\t\t}, this );\n\n\t\t},\n\n\t};\n\n} );\n\n","/**\n * Quiz Schema\n * @since 3.17.6\n * @version 3.17.6\n */\ndefine( 'Schemas/Quiz',[], function() {\n\n\treturn {\n\n\t\tdefault: {\n\t\t\ttitle: LLMS.l10n.translate( 'General Settings' ),\n\t\t\ttoggleable: true,\n\t\t\tfields: [\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'permalink',\n\t\t\t\t\t\tid: 'permalink',\n\t\t\t\t\t\ttype: 'permalink',\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'content',\n\t\t\t\t\t\tid: 'description',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Description' ),\n\t\t\t\t\t\ttype: 'editor',\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'passing_percent',\n\t\t\t\t\t\tid: 'passing-percent',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Passing Percentage' ),\n\t\t\t\t\t\tmin: 0,\n\t\t\t\t\t\tmax: 100,\n\t\t\t\t\t\ttip: LLMS.l10n.translate( 'Minimum percentage of total points required to pass the quiz' ),\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'allowed_attempts',\n\t\t\t\t\t\tid: 'allowed-attempts',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Limit Attempts' ),\n\t\t\t\t\t\tswitch_attribute: 'limit_attempts',\n\t\t\t\t\t\ttip: LLMS.l10n.translate( 'Limit the maximum number of times a student can take this quiz' ),\n\t\t\t\t\t\ttype: 'switch-number',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'time_limit',\n\t\t\t\t\t\tid: 'time-limit',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Time Limit' ),\n\t\t\t\t\t\tmin: 1,\n\t\t\t\t\t\tmax: 360,\n\t\t\t\t\t\tswitch_attribute: 'limit_time',\n\t\t\t\t\t\ttip: LLMS.l10n.translate( 'Enforce a maximum number of minutes a student can spend on each attempt' ),\n\t\t\t\t\t\ttype: 'switch-number',\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'show_correct_answer',\n\t\t\t\t\t\tid: 'show-correct-answer',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Show Correct Answers' ),\n\t\t\t\t\t\ttip: LLMS.l10n.translate( 'When enabled, students will be shown the correct answer to any question they answered incorrectly.' ),\n\t\t\t\t\t\ttype: 'switch',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'random_questions',\n\t\t\t\t\t\tid: 'random-questions',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Randomize Question Order' ),\n\t\t\t\t\t\ttip: LLMS.l10n.translate( 'Display questions in a random order for each attempt. Content questions are locked into their defined positions.' ),\n\t\t\t\t\t\ttype: 'switch',\n\t\t\t\t\t},\n\t\t\t\t],\n\n\t\t\t],\n\t\t},\n\n\t};\n\n} );\n\n","/**\n * Quiz Model\n * @since 3.16.0\n * @version 3.19.2\n */\ndefine( 'Models/Quiz',[\n\t\t'Collections/Questions',\n\t\t'Models/Lesson',\n\t\t'Models/Question',\n\t\t'Models/_Relationships',\n\t\t'Models/_Utilities',\n\t\t'Schemas/Quiz',\n\t], function(\n\t\tQuestions,\n\t\tLesson,\n\t\tQuestion,\n\t\tRelationships,\n\t\tUtilities,\n\t\tQuizSchema\n\t) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\t/**\n\t\t * model relationships\n\t\t * @type {Object}\n\t\t */\n\t\trelationships: {\n\t\t\tparent: {\n\t\t\t\tmodel: 'lesson',\n\t\t\t\ttype: 'model',\n\t\t\t},\n\t\t\tchildren: {\n\t\t\t\tquestions: {\n\t\t\t\t\tclass: 'Questions',\n\t\t\t\t\tmodel: 'llms_question',\n\t\t\t\t\ttype: 'collection',\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Lesson Settings Schema\n\t\t * @type {Object}\n\t\t */\n\t\tschema: QuizSchema,\n\n\t\t/**\n\t\t * New lesson defaults\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.6\n\t\t */\n\t\tdefaults: function() {\n\n\t\t\treturn {\n\t\t\t\tid: _.uniqueId( 'temp_' ),\n\t\t\t\ttitle: LLMS.l10n.translate( 'New Quiz' ),\n\t\t\t\ttype: 'llms_quiz',\n\t\t\t\tlesson_id: '',\n\n\t\t\t\tstatus: 'draft',\n\n\t\t\t\t// editable fields\n\t\t\t\tcontent: '',\n\t\t\t\tallowed_attempts: 5,\n\t\t\t\tlimit_attempts: 'no',\n\t\t\t\tlimit_time: 'no',\n\t\t\t\tpassing_percent: 65,\n\t\t\t\tname: '',\n\t\t\t\trandom_answers: 'no',\n\t\t\t\ttime_limit: 30,\n\t\t\t\tshow_correct_answer: 'no',\n\n\t\t\t\tquestions: [],\n\n\t\t\t\t// calculated\n\t\t\t\t_points: 0,\n\n\t\t\t\t// display\n\t\t\t\tpermalink: '',\n\t\t\t\t_show_settings: false,\n\t\t\t\t_questions_loaded: false,\n\t\t\t};\n\n\t\t},\n\n\t\t/**\n\t\t * Initializer\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.6\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.init_custom_schema();\n\t\t\tthis.startTracking();\n\t\t\tthis.init_relationships();\n\n\t\t\tthis.listenTo( this.get( 'questions' ), 'add', this.update_points );\n\t\t\tthis.listenTo( this.get( 'questions' ), 'remove', this.update_points );\n\n\t\t\tthis.set( '_points', this.get_total_points() );\n\n\t\t\t// when a quiz is published, ensure the parent lesson is marked as \"Enabled\" for quizzing\n\t\t\tthis.on( 'change:status', function() {\n\t\t\t\tif ( 'publish' === this.get( 'status' ) ) {\n\t\t\t\t\tthis.get_parent().set( 'quiz_enabled', 'yes' );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Add a new question to the quiz\n\t\t * @param obj data question data\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tadd_question: function( data ) {\n\n\t\t\tdata.parent_id = this.get( 'id' );\n\t\t\tvar question = this.get( 'questions' ).add( data, {\n\t\t\t\tparent: this,\n\t\t\t} );\n\t\t\tBackbone.pubSub.trigger( 'quiz-add-question', question, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the translated post type name for the model's type\n\t\t * @param bool plural if true, returns the plural, otherwise returns singular\n\t\t * @return string\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tget_l10n_type: function( plural ) {\n\n\t\t\tif ( plural ) {\n\t\t\t\treturn LLMS.l10n.translate( 'quizzes' );\n\t\t\t}\n\n\t\t\treturn LLMS.l10n.translate( 'quiz' );\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the quiz's total points\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_total_points: function() {\n\n\t\t\tvar points = 0;\n\n\t\t\tthis.get( 'questions' ).each( function( question ) {\n\t\t\t\tpoints += question.get_points();\n\t\t\t} );\n\n\t\t\treturn points;\n\n\t\t},\n\n\t\t/**\n\t\t * Lazy load questions via AJAX\n\t\t * @param {Function} cb callback function\n\t\t * @return void\n\t\t * @since 3.19.2\n\t\t * @version 3.19.2\n\t\t */\n\t\tload_questions: function( cb ) {\n\n\t\t\tif ( this.get( '_questions_loaded' ) ) {\n\n\t\t\t\tcb();\n\n\t\t\t} else {\n\n\t\t\t\tvar self = this;\n\n\t\t\t\tLLMS.Ajax.call( {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\taction: 'llms_builder',\n\t\t\t\t\t\taction_type: 'lazy_load',\n\t\t\t\t\t\tcourse_id: window.llms_builder.CourseModel.get( 'id' ),\n\t\t\t\t\t\tload_id: this.get( 'id' ),\n\t\t\t\t\t},\n\t\t\t\t\terror: function( xhr, status, error ) {\n\n\t\t\t\t\t\tconsole.log( xhr, status, error );\n\t\t\t\t\t\twindow.llms_builder.debug.log( '==== start load_questions error ====', xhr, status, error, '==== finish load_questions error ====' );\n\t\t\t\t\t\tcb( true );\n\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function( res ) {\n\t\t\t\t\t\tif ( res && res.questions ) {\n\t\t\t\t\t\t\tself.set( '_questions_loaded', true );\n\t\t\t\t\t\t\tif ( res.questions ) {\n\t\t\t\t\t\t\t\t_.each( res.questions, self.add_question, self );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcb( true );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\n\t\t},\n\n\t\t/**\n\t\t * Update total number of points calculated property\n\t\t * @return int\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_points: function() {\n\n\t\t\tthis.set( '_points', this.get_total_points() );\n\n\t\t},\n\n\t}, Relationships, Utilities ) );\n\n} );\n\n","/**\n * Lesson Schemas\n * @since 3.17.0\n * @version 3.17.1\n */\ndefine( 'Schemas/Lesson',[], function() {\n\n\treturn {\n\n\t\tdefault: {\n\t\t\ttitle: LLMS.l10n.translate( 'General Settings' ),\n\t\t\ttoggleable: true,\n\t\t\tfields: [\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'permalink',\n\t\t\t\t\t\tid: 'permalink',\n\t\t\t\t\t\ttype: 'permalink',\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'video_embed',\n\t\t\t\t\t\tid: 'video-embed',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Video Embed URL' ),\n\t\t\t\t\t\ttype: 'video_embed',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'audio_embed',\n\t\t\t\t\t\tid: 'audio-embed',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Audio Embed URL' ),\n\t\t\t\t\t\ttype: 'audio_embed',\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'free_lesson',\n\t\t\t\t\t\tid: 'free-lesson',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Free Lesson' ),\n\t\t\t\t\t\ttip: LLMS.l10n.translate( \"Free lessons can be accessed without enrollment.\" ),\n\t\t\t\t\t\ttype: 'switch',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'require_passing_grade',\n\t\t\t\t\t\tid: 'require-passing-grade',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Require Passing Grade on Quiz' ),\n\t\t\t\t\t\ttip: LLMS.l10n.translate( \"When enabled, students must pass this lesson's quiz before the lesson can be completed.\" ),\n\t\t\t\t\t\ttype: 'switch',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( 'yes' === this.get( 'quiz_enabled' ) );\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'require_assignment_passing_grade',\n\t\t\t\t\t\tid: 'require-assignment-passing-grade',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Require Passing Grade on Assignment' ),\n\t\t\t\t\t\ttip: LLMS.l10n.translate( \"When enabled, students must pass this lesson's assignment before the lesson can be completed.\" ),\n\t\t\t\t\t\ttype: 'switch',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( 'undefined' !== window.llms_builder.assignments && 'yes' === this.get( 'assignment_enabled' ) );\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'prerequisite',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( false === this.is_first_in_course() );\n\t\t\t\t\t\t},\n\t\t\t\t\t\tid: 'prerequisite',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Prerequisite' ),\n\t\t\t\t\t\tswitch_attribute: 'has_prerequisite',\n\t\t\t\t\t\ttype: 'switch-select',\n\t\t\t\t\t\toptions: function() {\n\t\t\t\t\t\t\treturn this.get_available_prereq_options();\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t], [\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'drip_method',\n\t\t\t\t\t\tid: 'drip-method',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Drip Method' ),\n\t\t\t\t\t\tswitch_attribute: 'drip_method',\n\t\t\t\t\t\ttype: 'select',\n\t\t\t\t\t\toptions: function() {\n\n\t\t\t\t\t\t\tvar options = [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tkey: '',\n\t\t\t\t\t\t\t\t\tval: LLMS.l10n.translate( 'None' ),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tkey: 'date',\n\t\t\t\t\t\t\t\t\tval: LLMS.l10n.translate( 'On a specific date' ),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tkey: 'enrollment',\n\t\t\t\t\t\t\t\t\tval: LLMS.l10n.translate( '# of days after course enrollment' ),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t];\n\n\t\t\t\t\t\t\tif ( this.get_course().get( 'start_date' ) ) {\n\t\t\t\t\t\t\t\toptions.push( {\n\t\t\t\t\t\t\t\t\tkey: 'start',\n\t\t\t\t\t\t\t\t\tval: LLMS.l10n.translate( '# of days after course start date' ),\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( 'yes' === this.get( 'has_prerequisite' ) ) {\n\t\t\t\t\t\t\t\toptions.push( {\n\t\t\t\t\t\t\t\t\tkey: 'prerequisite',\n\t\t\t\t\t\t\t\t\tval: LLMS.l10n.translate( '# of days after prerequisite lesson completion' ),\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn options;\n\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'days_before_available',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( -1 !== [ 'enrollment', 'start', 'prerequisite' ].indexOf( this.get( 'drip_method' ) ) );\n\t\t\t\t\t\t},\n\t\t\t\t\t\tid: 'days-before-available',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( '# of days' ),\n\t\t\t\t\t\tmin: 0,\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'date_available',\n\t\t\t\t\t\tdate_format: 'Y-m-d',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( 'date' === this.get( 'drip_method' ) );\n\t\t\t\t\t\t},\n\t\t\t\t\t\tid: 'date-available',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Date' ),\n\t\t\t\t\t\ttimepicker: 'false',\n\t\t\t\t\t\ttype: 'datepicker',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tattribute: 'time_available',\n\t\t\t\t\t\tcondition: function() {\n\t\t\t\t\t\t\treturn ( 'date' === this.get( 'drip_method' ) );\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdatepicker: 'false',\n\t\t\t\t\t\tdate_format: 'h:i A',\n\t\t\t\t\t\tid: 'time-available',\n\t\t\t\t\t\tlabel: LLMS.l10n.translate( 'Time' ),\n\t\t\t\t\t\ttype: 'datepicker',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t],\n\t\t},\n\n\t};\n\n} );\n\n","/**\n * Lesson Model\n * @since 3.13.0\n * @version 3.19.3\n */\ndefine( 'Models/Lesson',[ 'Models/Quiz', 'Models/_Relationships', 'Models/_Utilities', 'Schemas/Lesson' ], function( Quiz, Relationships, Utilities, LessonSchema ) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\t/**\n\t\t * Model relationships\n\t\t * @type {Object}\n\t\t */\n\t\trelationships: {\n\t\t\tparents: {\n\t\t\t\tmodel: 'section',\n\t\t\t\ttype: 'model',\n\t\t\t},\n\t\t\tchildren: {\n\t\t\t\tquiz: {\n\t\t\t\t\tclass: 'Quiz',\n\t\t\t\t\tconditional: function( model ) {\n\t\t\t\t\t\t// if quiz is enabled OR not enabled but we have some quiz data as an obj\n\t\t\t\t\t\treturn ( 'yes' === model.get( 'quiz_enabled' ) || ! _.isEmpty( model.get( 'quiz' ) ) );\n\t\t\t\t\t},\n\t\t\t\t\tmodel: 'llms_quiz',\n\t\t\t\t\ttype: 'model',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Lesson Settings Schema\n\t\t * @type {Object}\n\t\t */\n\t\tschema: LessonSchema,\n\n\t\t/**\n\t\t * New lesson defaults\n\t\t * @return obj\n\t\t * @since 3.13.0\n\t\t * @version 3.17.1\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tid: _.uniqueId( 'temp_' ),\n\t\t\t\ttitle: LLMS.l10n.translate( 'New Lesson' ),\n\t\t\t\ttype: 'lesson',\n\t\t\t\torder: this.collection ? this.collection.length + 1 : 1,\n\t\t\t\tparent_course: window.llms_builder.course.id,\n\t\t\t\tparent_section: '',\n\n\t\t\t\t// urls\n\t\t\t\tedit_url: '',\n\t\t\t\tview_url: '',\n\n\t\t\t\t// editable fields\n\t\t\t\tcontent: '',\n\t\t\t\taudio_embed: '',\n\t\t\t\thas_prerequisite: 'no',\n\t\t\t\trequire_passing_grade: 'yes',\n\t\t\t\trequire_assignment_passing_grade: 'yes',\n\t\t\t\tvideo_embed: '',\n\t\t\t\tfree_lesson: '',\n\n\t\t\t\t// other fields\n\t\t\t\tassignment: {}, // assignment model/data\n\t\t\t\tassignment_enabled: 'no',\n\n\t\t\t\tquiz: {}, // quiz model/data\n\t\t\t\tquiz_enabled: 'no',\n\n\t\t\t\t_forceSync: false,\n\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Initializer\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.init_custom_schema();\n\t\t\tthis.startTracking();\n\t\t\tthis.maybe_init_assignments();\n\t\t\tthis.init_relationships();\n\n\t\t\t// if the lesson ID isn't set on a quiz, set it\n\t\t\tvar quiz = this.get( 'quiz' );\n\t\t\tif ( ! _.isEmpty( quiz ) && ! quiz.get( 'lesson_id' ) ) {\n\t\t\t\tquiz.set( 'lesson_id', this.get( 'id' ) );\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve a reference to the parent course of the lesson\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_course: function() {\n\t\t\treturn this.get_parent().get_parent();\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the translated post type name for the model's type\n\t\t * @param bool plural if true, returns the plural, otherwise returns singular\n\t\t * @return string\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tget_l10n_type: function( plural ) {\n\n\t\t\tif ( plural ) {\n\t\t\t\treturn LLMS.l10n.translate( 'lessons' );\n\t\t\t}\n\n\t\t\treturn LLMS.l10n.translate( 'lesson' );\n\t\t},\n\n\t\t/**\n\t\t * Override default get_parent to grab from collection if models parent isn't set\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tget_parent: function() {\n\n\t\t\tvar rels = this.get_relationships();\n\t\t\tif ( rels.parent && rels.parent.reference ) {\n\t\t\t\treturn rels.parent.reference;\n\t\t\t} else if ( this.collection && this.collection.parent ) {\n\t\t\t\treturn this.collection.parent;\n\t\t\t}\n\t\t\treturn false;\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve an array of prerequisite options available for the current lesson\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tget_available_prereq_options: function() {\n\n\t\t\tvar parent_section_index = this.get_parent().collection.indexOf( this.get_parent() ),\n\t\t\t\tlesson_index_in_section = this.collection.indexOf( this ),\n\t\t\t\toptions = [];\n\n\t\t\tthis.get_course().get( 'sections' ).each( function( section, curr_sec_index ) {\n\t\t\t\tif ( curr_sec_index <= parent_section_index ) {\n\t\t\t\t\tvar group = {\n\t\t\t\t\t\t\t/* translators: %1$d = section order number, %2$s = section title */\n\t\t\t\t\t\t\tlabel: LLMS.l10n.replace( 'Section %1$d: %2$s', {\n\t\t\t\t\t\t\t\t'%1$d': section.get( 'order' ),\n\t\t\t\t\t\t\t\t'%2$s': section.get( 'title' )\n\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\toptions: [],\n\t\t\t\t\t\t};\n\n\t\t\t\t\tsection.get( 'lessons' ).each( function( lesson, curr_les_index ) {\n\t\t\t\t\t\tif ( curr_sec_index !== parent_section_index || curr_les_index < lesson_index_in_section ) {\n\t\t\t\t\t\t\t/* translators: %1$d = lesson order number, %2$s = lesson title */\n\t\t\t\t\t\t\tgroup.options.push( {\n\t\t\t\t\t\t\t\tkey: lesson.get( 'id' ),\n\t\t\t\t\t\t\t\tval: LLMS.l10n.replace( 'Lesson %1$d: %2$s', {\n\t\t\t\t\t\t\t\t\t'%1$d': lesson.get( 'order' ),\n\t\t\t\t\t\t\t\t\t'%2$s': lesson.get( 'title' )\n\t\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t}, this );\n\n\t\t\t\t\toptions.push( group );\n\t\t\t\t}\n\t\t\t}, this );\n\n\t\t\treturn options;\n\n\t\t},\n\n\t\t/**\n\t\t * Add a new quiz to the lesson\n\t\t * @param obj data object of quiz data used to construct a new quiz model\n\t\t * @return obj model for the created quiz\n\t\t * @since 3.16.0\n\t\t * @version 3.19.3\n\t\t */\n\t\tadd_quiz: function( data ) {\n\n\t\t\tdata = data || {};\n\n\t\t\tdata.lesson_id = this.id;\n\t\t\tdata._questions_loaded = true;\n\n\t\t\tif ( ! data.title ) {\n\n\t\t\t\tdata.title = LLMS.l10n.replace( '%1$s Quiz', {\n\t\t\t\t\t'%1$s': this.get( 'title' ),\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tthis.set( 'quiz', data );\n\t\t\tthis.init_relationships();\n\n\t\t\tvar quiz = this.get( 'quiz' );\n\t\t\tthis.set( 'quiz_enabled', 'yes' );\n\n\t\t\treturn quiz;\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if this is the first lesson\n\t\t * @return {Boolean}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tis_first_in_course: function() {\n\n\t\t\t// if it's not the first item in the section it cant be the first lesson\n\t\t\tif ( this.collection.indexOf( this ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// if it's not the first section it cant' be first lesson\n\t\t\tvar section = this.get_parent();\n\t\t\tif ( section.collection.indexOf( section ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// it's first lesson in first section\n\t\t\treturn true;\n\n\t\t},\n\n\t\t/**\n\t\t * Initialize lesson assignments *if* the assignments addon is availalbe and enabled\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tmaybe_init_assignments: function() {\n\n\t\t\tif ( ! window.llms_builder.assignments ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.relationships.children.assignment = {\n\t\t\t\tclass: 'Assignment',\n\t\t\t\tconditional: function( model ) {\n\t\t\t\t\t// if assignment is enabled OR not enabled but we have some assignment data as an obj\n\t\t\t\t\treturn ( 'yes' === model.get( 'assignment_enabled' ) || ! _.isEmpty( model.get( 'assignment' ) ) );\n\t\t\t\t},\n\t\t\t\tmodel: 'llms_assignment',\n\t\t\t\ttype: 'model',\n\t\t\t};\n\n\t\t},\n\n\t}, Relationships, Utilities ) );\n\n} );\n\n","/**\n * Lessons Collection\n * @since 3.13.0\n * @version 3.17.0\n */\ndefine( 'Collections/Lessons',[ 'Models/Lesson' ], function( model ) {\n\n\treturn Backbone.Collection.extend( {\n\n\t\t/**\n\t\t * Model for collection items\n\t\t * @type obj\n\t\t */\n\t\tmodel: model,\n\n\t\t/**\n\t\t * Initializer\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\t// reorder called by LessonList view when sortable drops occur\n\t\t\tthis.on( 'reorder', this.on_reorder );\n\n\t\t\t// when a lesson is added or removed, update order\n\t\t\tthis.on( 'add', this.on_reorder );\n\t\t\tthis.on( 'remove', this.on_reorder );\n\n\t\t},\n\n\t\t/**\n\t\t * On lesson reorder callback\n\t\t *\n\t\t * Update the order attr of each lesson to reflect the new lesson order\n\t\t * Validate prerequisite (if set) and unset it if it's no longer a valid prereq\n\t\t *\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\ton_reorder: function() {\n\t\t\tthis.update_order();\n\t\t\tthis.validate_prereqs();\n\t\t},\n\n\t\t/**\n\t\t * Update lesson order attribute of all lessons when lessons are reordered\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tupdate_order: function() {\n\n\t\t\tthis.each( function( lesson ) {\n\t\t\t\tlesson.set( 'order', this.indexOf( lesson ) + 1 );\n\t\t\t}, this );\n\n\t\t},\n\n\n\t\t/**\n\t\t * Validate prerequisite (if set) and unset it if it's no longer a valid prereq\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tvalidate_prereqs: function() {\n\n\t\t\tthis.each( function( lesson ) {\n\n\t\t\t\t// validate prereqs\n\t\t\t\tif ( 'yes' === lesson.get( 'has_prerequisite' ) ) {\n\t\t\t\t\tvar valid = _.pluck( _.flatten( _.pluck( lesson.get_available_prereq_options(), 'options' ) ), 'key' );\n\t\t\t\t\tif ( -1 === valid.indexOf( lesson.get( 'prerequisite' ) * 1 ) ) {\n\t\t\t\t\t\tlesson.set( {\n\t\t\t\t\t\t\tprerequisite: 0,\n\t\t\t\t\t\t\thas_prerequisite: 'no',\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}, this );\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Quiz Question Type Collection\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Collections/QuestionTypes',[ 'Models/QuestionType' ], function( model ) {\n\n\treturn Backbone.Collection.extend( {\n\n\t\t/**\n\t\t * Model for collection items\n\t\t * @type obj\n\t\t */\n\t\tmodel: model,\n\n\t\t/**\n\t\t * Initializer\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.on( 'add', this.comparator );\n\t\t\tthis.on( 'remove', this.comparator );\n\n\t\t},\n\n\t\t/**\n\t\t * Comparator (sorts collection)\n\t\t * @param obj model QuestionType model\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tcomparator: function( model ) {\n\n\t\t\treturn model.get( 'group' ).order;\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Section Model\n * @since 3.16.0\n * @version 3.16.12\n */\ndefine( 'Models/Section',[ 'Collections/Lessons', 'Models/_Relationships' ], function( Lessons, Relationships ) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\trelationships: {\n\t\t\tparent: {\n\t\t\t\tmodel: 'course',\n\t\t\t\ttype: 'model',\n\t\t\t},\n\t\t\tchildren: {\n\t\t\t\tlessons: {\n\t\t\t\t\tclass: 'Lessons',\n\t\t\t\t\tmodel: 'lesson',\n\t\t\t\t\ttype: 'collection',\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * New section defaults\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tid: _.uniqueId( 'temp_' ),\n\t\t\t\tlessons: [],\n\t\t\t\torder: this.collection ? this.collection.length + 1 : 1,\n\t\t\t\tparent_course: window.llms_builder.course.id,\n\t\t\t\ttitle: LLMS.l10n.translate( 'New Section' ),\n\t\t\t\ttype: 'section',\n\n\t\t\t\t_expanded: false,\n\t\t\t\t_selected: false,\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Initialize\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.startTracking();\n\t\t\tthis.init_relationships();\n\n\t\t},\n\n\t\t/**\n\t\t * Add a lesson to the section\n\t\t * @param obj data hash of lesson data (creates new lesson)\n\t\t * or existing lesson as a Backbone.Model\n\t\t * @param obj options has of options\n\t\t * @return obj Backbone.Model of the new/updated lesson\n\t\t * @since 3.16.0\n\t\t * @version 3.16.11\n\t\t */\n\t\tadd_lesson: function( data, options ) {\n\n\t\t\tdata = data || {};\n\t\t\toptions = options || {};\n\n\t\t\tif ( data instanceof Backbone.Model ) {\n\t\t\t\tdata.set( 'parent_section', this.get( 'id' ) );\n\t\t\t\tdata.set_parent( this );\n\t\t\t} else {\n\t\t\t\tdata.parent_section = this.get( 'id' );\n\t\t\t}\n\n\t\t\treturn this.get( 'lessons' ).add( data, options );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the translated post type name for the model's type\n\t\t * @param bool plural if true, returns the plural, otherwise returns singular\n\t\t * @return string\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tget_l10n_type: function( plural ) {\n\n\t\t\tif ( plural ) {\n\t\t\t\treturn LLMS.l10n.translate( 'sections' );\n\t\t\t}\n\n\t\t\treturn LLMS.l10n.translate( 'section' );\n\t\t},\n\n\t\t/**\n\t\t * Get next section in the collection\n\t\t * @param bool circular if true handles the collection in a circle\n\t\t * \tif current is the last section, returns the first section\n\t\t * \tif current is the first section, returns the last section\n\t\t * @return obj|false\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\tget_next: function( circular ) {\n\t\t\treturn this._get_sibling( 'next', circular );\n\t\t},\n\n\t\t/**\n\t\t * Get prev section in the collection\n\t\t * @param bool circular if true handles the collection in a circle\n\t\t * \tif current is the last section, returns the first section\n\t\t * \tif current is the first section, returns the last section\n\t\t * @return obj|false\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\tget_prev: function( circular ) {\n\t\t\treturn this._get_sibling( 'prev', circular );\n\t\t},\n\n\t\t/**\n\t\t * Get a sibling section\n\t\t * @param string direction siblings direction [next|prev]\n\t\t * @param bool circular if true handles the collection in a circle\n\t\t * \tif current is the last section, returns the first section\n\t\t * \tif current is the first section, returns the last section\n\t\t * @return obj|false\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\t_get_sibling: function( direction, circular ) {\n\n\t\t\tcircular = ( 'undefined' === circular ) ? true : circular;\n\n\t\t\tvar max = this.collection.size() - 1,\n\t\t\t\tindex = this.collection.indexOf( this ),\n\t\t\t\tsibling_index;\n\n\t\t\tif ( 'next' === direction ) {\n\t\t\t\tsibling_index = index + 1;\n\t\t\t} else if ( 'prev' === direction ) {\n\t\t\t\tsibling_index = index - 1;\n\t\t\t}\n\n\t\t\t// dont retrieve greater than max or less than min\n\t\t\tif ( sibling_index <= max || sibling_index <= 0 ) {\n\n\t\t\t\treturn this.collection.at( sibling_index );\n\n\t\t\t} else if ( circular ) {\n\n\t\t\t\tif ( 'next' === direction ) {\n\t\t\t\t\treturn this.collection.first();\n\t\t\t\t} else if ( 'prev' === direction ) {\n\t\t\t\t\treturn this.collection.last();\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t}, Relationships ) );\n\n} );\n\n","/**\n * Sections Collection\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Collections/Sections',[ 'Models/Section' ], function( model ) {\n\n\treturn Backbone.Collection.extend( {\n\n\t\t/**\n\t\t * Model for collection items\n\t\t * @type obj\n\t\t */\n\t\tmodel: model,\n\n\t\t/**\n\t\t * Initialize\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tvar self = this;\n\n\t\t\t// reorder called by SectionList view when sortable drops occur\n\t\t\tthis.on( 'reorder', this.update_order );\n\n\t\t\t// when a section is added or removed, update order\n\t\t\tthis.on( 'add', this.update_order );\n\t\t\tthis.on( 'remove', this.update_order );\n\n\t\t},\n\n\t\t/**\n\t\t * Update the order attr of each section in the list to reflect the order of the collection\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tupdate_order: function() {\n\n\t\t\tvar self = this;\n\n\t\t\tthis.each( function( section ) {\n\n\t\t\t\tsection.set( 'order', self.indexOf( section ) + 1 );\n\n\t\t\t} );\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Lessons Collection\n * @since 3.13.0\n * @version 3.16.0\n */\ndefine( 'Collections/loader',[\n\t\t'Collections/Lessons',\n\t\t'Collections/QuestionChoices',\n\t\t'Collections/Questions',\n\t\t'Collections/QuestionTypes',\n\t\t'Collections/Sections'\n\t], function(\n\t\tLessons,\n\t\tQuestionChoices,\n\t\tQuestions,\n\t\tQuestionTypes,\n\t\tSections\n\t) {\n\n\treturn {\n\t\tLessons: Lessons,\n\t\tQuestionChoices: QuestionChoices,\n\t\tQuestions: Questions,\n\t\tQuestionTypes: QuestionTypes,\n\t\tSections: Sections,\n\t};\n\n} );\n\n","/**\n * Abstract LifterLMS Model\n * @since 3.17.0\n * @version 3.17.0\n */\ndefine( 'Models/Abstract',[ 'Models/_Relationships', 'Models/_Utilities' ], function( Relationships, Utilities ) {\n\n\treturn Backbone.Model.extend( _.defaults( {}, Relationships, Utilities ) );\n\n} );\n\n","/**\n * Course Model\n * @since 3.16.0\n * @version 3.16.11\n */\ndefine( 'Models/Course',[ 'Collections/Sections', 'Models/_Relationships', 'Models/_Utilities' ], function( Sections, Relationships, Utilities ) {\n\n\treturn Backbone.Model.extend( _.defaults( {\n\n\t\trelationships: {\n\t\t\tchildren: {\n\t\t\t\tsections: {\n\t\t\t\t\tclass: 'Sections',\n\t\t\t\t\tmodel: 'section',\n\t\t\t\t\ttype: 'collection',\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * New Course Defaults\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tdefaults: function() {\n\t\t\treturn {\n\t\t\t\tedit_url: '',\n\t\t\t\tsections: [],\n\t\t\t\ttitle: 'New Course',\n\t\t\t\ttype: 'course',\n\t\t\t\tview_url: '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Init\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.startTracking();\n\t\t\tthis.init_relationships();\n\n\t\t\t// Sidebar \"New Section\" button broadcast\n\t\t\tBackbone.pubSub.on( 'add-new-section', this.add_section, this );\n\n\t\t\t// Sidebar \"New Lesson\" button broadcast\n\t\t\tBackbone.pubSub.on( 'add-new-lesson', this.add_lesson, this );\n\n\t\t\tBackbone.pubSub.on( 'lesson-search-select', this.add_existing_lesson, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Add an existing lesson to the course\n\t\t * Duplicate a lesson from this or another course or attach an orphaned lesson\n\t\t * @param obj lesson lesson data obj\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.11\n\t\t */\n\t\tadd_existing_lesson: function( lesson ) {\n\n\t\t\tvar data = lesson.data;\n\n\t\t\tif ( 'clone' === lesson.action ) {\n\n\t\t\t\tdelete data.id;\n\t\t\t\tif ( data.quiz ) {\n\t\t\t\t\tdelete data.quiz;\n\t\t\t\t\tdata.quiz_enabled = 'no';\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tdata._forceSync = true;\n\n\t\t\t}\n\n\t\t\tdelete data.order;\n\t\t\tdelete data.parent_course;\n\t\t\tdelete data.parent_section;\n\n\t\t\tthis.add_lesson( data );\n\n\t\t},\n\n\t\t/**\n\t\t * Add a new lesson to the course\n\t\t * @param obj data lesson data\n\t\t * @return obj Backbone.Model of the lesson\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tadd_lesson: function( data ) {\n\n\t\t\tdata = data || {};\n\t\t\tvar options = {},\n\t\t\t\tsection;\n\n\t\t\tif ( ! data.parent_section ) {\n\t\t\t\tsection = this.get_selected_section();\n\t\t\t\tif ( ! section ) {\n\t\t\t\t\tsection = this.get( 'sections' ).last();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsection = this.get( 'sections' ).get( data.parent_section );\n\t\t\t}\n\n\t\t\tdata._selected = true;\n\n\t\t\tdata.parent_course = this.get( 'id' );\n\n\t\t\tvar lesson = section.add_lesson( data, options );\n\t\t\tBackbone.pubSub.trigger( 'new-lesson-added', lesson );\n\n\t\t\t// expand the section\n\t\t\tsection.set( '_expanded', true );\n\n\t\t\treturn lesson;\n\n\t\t},\n\n\t\t/**\n\t\t * Add a new section to the course\n\t\t * @param obj data section data\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tadd_section: function( data ) {\n\n\t\t\tdata = data || {};\n\t\t\tvar sections = this.get( 'sections' ),\n\t\t\t\toptions = {},\n\t\t\t\tselected = this.get_selected_section();\n\n\t\t\t// if a section is selected, add the new section after the currently selected one\n\t\t\tif ( selected ) {\n\t\t\t\toptions.at = sections.indexOf( selected ) + 1;\n\t\t\t}\n\n\t\t\tsections.add( data, options );\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the currently selected section in the course\n\t\t * @return obj|undefined\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_selected_section: function() {\n\n\t\t\treturn this.get( 'sections' ).find( function( model ) {\n\t\t\t\treturn model.get( '_selected' );\n\t\t\t} );\n\n\t\t},\n\n\t}, Relationships, Utilities ) );\n\n} );\n\n","/**\n * Load all models\n * @return obj\n * @since 3.16.0\n * @version 3.17.0\n */\ndefine( 'Models/loader',[\n\t\t'Models/Abstract',\n\t\t'Models/Course',\n\t\t'Models/Image',\n\t\t'Models/Lesson',\n\t\t'Models/Question',\n\t\t'Models/QuestionChoice',\n\t\t'Models/QuestionType',\n\t\t'Models/Quiz',\n\t\t'Models/Section'\n\t],\n\tfunction(\n\t\tAbstract,\n\t\tCourse,\n\t\tImage,\n\t\tLesson,\n\t\tQuestion,\n\t\tQuestionChoice,\n\t\tQuestionType,\n\t\tQuiz,\n\t\tSection\n\t) {\n\n\treturn {\n\t\tAbstract: Abstract,\n\t\tCourse: Course,\n\t\tImage: Image,\n\t\tLesson: Lesson,\n\t\tQuestion: Question,\n\t\tQuestionChoice: QuestionChoice,\n\t\tQuestionType: QuestionType,\n\t\tQuiz: Quiz,\n\t\tSection: Section,\n\t};\n\n} );\n\n","/**\n * Detachable model\n * @type {Object}\n * @since 3.16.12\n * @version 3.16.12\n */\ndefine( 'Views/_Detachable',[], function() {\n\n\treturn {\n\n\t\t/**\n\t\t * DOM Events\n\t\t * @type {Object}\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tevents: {\n\t\t\t'click a[href=\"#llms-detach-model\"]': 'detach_model',\n\t\t},\n\n\t\t/**\n\t\t * Detaches a model from it's parent (doesn't delete)\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tdetach_model: function( event ) {\n\n\t\t\tif ( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}\n\n\t\t\tvar msg = LLMS.l10n.replace( 'Are you sure you want to detach this %s?', {\n\t\t\t\t'%s': this.model.get_l10n_type(),\n\t\t\t} );\n\n\t\t\tif ( window.confirm( msg ) ) {\n\n\t\t\t\tif ( this.model.collection ) {\n\t\t\t\t\tthis.model.collection.remove( this.model );\n\t\t\t\t}\n\n\t\t\t\t// publish global event\n\t\t\t\tBackbone.pubSub.trigger( 'model-detached', this.model );\n\n\t\t\t\t// trigger local event so extending views can run other actions where necessary\n\t\t\t\tthis.trigger( 'model-trashed', this.model );\n\n\t\t\t}\n\n\t\t},\n\n\t}\n\n} );\n\n","/**\n * Handles UX and Events for inline editing of views\n * Use with a Model's View\n * Allows editing model.title field via .llms-editable-title elements\n * @type {Object}\n * @since 3.16.0\n * @version 3.17.8\n */\ndefine( 'Views/_Editable',[], function() {\n\n\treturn {\n\n\t\tmedia_lib: null,\n\n\t\t/**\n\t\t * DOM Events\n\t\t * @type {Object}\n\t\t * @since 3.16.0\n\t\t * @version 3.17.8\n\t\t */\n\t\tevents: {\n\t\t\t'click .llms-add-image': 'open_media_lib',\n\t\t\t'click a[href=\"#llms-edit-slug\"]': 'make_slug_editable',\n\t\t\t'click a[href=\"#llms-remove-image\"]': 'remove_image',\n\t\t\t'change .llms-editable-select select': 'on_select',\n\t\t\t'change .llms-switch input[type=\"checkbox\"]': 'toggle_switch',\n\t\t\t'change .llms-editable-radio input': 'on_radio_select',\n\t\t\t'focusin .llms-input': 'on_focus',\n\t\t\t'focusout .llms-input': 'on_blur',\n\t\t\t'keydown .llms-input': 'on_keydown',\n\t\t\t'input .llms-input[type=\"number\"]': 'on_blur',\n\t\t\t'paste .llms-input[data-formatting]': 'on_paste',\n\t\t},\n\n\t\t/**\n\t\t * Retrieve a list of allowed tags for a given element\n\t\t * @param obj $el jQuery selector for the element\n\t\t * @return array\n\t\t * @since 3.16.0\n\t\t * @version 3.17.8\n\t\t */\n\t\tget_allowed_tags: function( $el ) {\n\n\t\t\tif ( $el.attr( 'data-formatting' ) ) {\n\t\t\t\treturn _.map( $el.attr( 'data-formatting' ).split( ',' ), function( tag ) {\n\t\t\t\t\treturn tag.trim();\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn [ 'b', 'i', 'u', 'strong', 'em' ];\n\n\t\t},\n\n\t\t/**\n\t\t * Retrieve the content of an element\n\t\t * @param obj $el jQuery object of the element\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.17.8\n\t\t */\n\t\tget_content: function( $el ) {\n\n\t\t\tif ( 'INPUT' === $el[0].tagName ) {\n\t\t\t\treturn $el.val();\n\t\t\t}\n\n\t\t\tif ( ! $el.attr( 'data-formatting' ) && ! $el.hasClass( 'ql-editor' ) ) {\n\t\t\t\treturn $el.text();\n\t\t\t}\n\n\t\t\treturn _.stripFormatting( $el.html(), this.get_allowed_tags( $el ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if changes have been made to the element\n\t\t * @param {[obj]} event js event object\n\t\t * @return {Boolean} true when changes have been made, false otherwise\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\thas_changed: function( event ) {\n\t\t\tvar $el = $( event.target );\n\t\t\treturn ( $el.attr( 'data-original-content' ) !== this.get_content( $el ) );\n\t\t},\n\n\t\t/**\n\t\t * Ensure that new content is at least 1 character long\n\t\t * @param obj event js event object\n\t\t * @return boolean\n\t\t * @since 3.16.0\n\t\t * @version 3.17.2\n\t\t */\n\t\tis_valid: function( event ) {\n\n\t\t\tvar self = this,\n\t\t\t\t$el = $( event.target ),\n\t\t\t\tcontent = this.get_content( $el ),\n\t\t\t\ttype = $el.attr( 'data-type' );\n\n\t\t\tif ( ( $el.attr( 'required' ) || $el.attr( 'data-required' ) ) && content.length < 1 ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( 'url' === type || 'video' === type ) {\n\t\t\t\tif ( ! this._validate_url( this.get_content( $el ) ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t} else if ( 'permalink' === type ) {\n\n\t\t\t\tLLMS.Ajax.call( {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\taction: 'llms_builder',\n\t\t\t\t\t\taction_type: 'get_permalink',\n\t\t\t\t\t\tcourse_id: window.llms_builder.CourseModel.get( 'id' ),\n\t\t\t\t\t\tid: self.model.get( 'id' ),\n\t\t\t\t\t\ttitle: self.model.get( 'title' ),\n\t\t\t\t\t\tslug: content,\n\t\t\t\t\t},\n\t\t\t\t\tbeforeSend: function() {\n\t\t\t\t\t\tLLMS.Spinner.start( $el.closest( '.llms-editable-toggle-group' ), 'small' );\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function( r ) {\n\n\t\t\t\t\t\tif ( r.permalink && r.slug ) {\n\t\t\t\t\t\t\tself.model.set( 'permalink', r.permalink );\n\t\t\t\t\t\t\tself.model.set( 'name', r.slug );\n\t\t\t\t\t\t\tself.render();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t},\n\n\t\t/**\n\t\t * Initialize datepicker elements\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tinit_datepickers: function() {\n\n\t\t\tthis.$el.find( '.llms-editable-date input' ).each( function() {\n\n\t\t\t\t$( this ).datetimepicker( {\n\t\t\t\t\tformat: $( this ).attr( 'data-date-format' ) || 'Y-m-d h:i A',\n\t\t\t\t\tdatepicker: ( undefined === $( this ).attr( 'data-date-datepicker' ) ) ? true : ( 'true' == $( this ).attr( 'data-date-datepicker' ) ),\n\t\t\t\t\ttimepicker: ( undefined === $( this ).attr( 'data-date-timepicker' ) ) ? true : ( 'true' == $( this ).attr( 'data-date-timepicker' ) ),\n\t\t\t\t\tonClose: function( current_time, $input ) {\n\t\t\t\t\t\t$input.blur();\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Initialize elements that allow inline formatting\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinit_formatting_els: function() {\n\n\t\t\tvar self = this;\n\n\t\t\tthis.$el.find( '.llms-input-formatting[data-formatting]' ).each( function() {\n\n\t\t\t\tvar formatting = $( this ).attr( 'data-formatting' ).split( ',' ),\n\t\t\t\t\tattr = $( this ).attr( 'data-attribute' );\n\n\t\t\t\tvar ed = new Quill( this, {\n\t\t\t\t\tmodules: {\n\t\t\t\t\t\ttoolbar: [ formatting ],\n\t\t\t\t\t\tkeyboard: {\n\t\t\t\t\t\t\tbindings: {\n\t\t\t\t\t\t\t\ttab: {\n\t\t\t\t\t\t\t\t\tkey: 9,\n\t\t\t\t\t\t\t\t\thandler: function( range, context ) {\n\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t13: {\n\t\t\t\t\t\t\t\t\tkey: 13,\n\t\t\t\t\t\t\t\t\thandler: function( range, context ) {\n\t\t\t\t\t\t\t\t\t\ted.root.blur();\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tplaceholder: $( this ).attr( 'data-placeholder' ),\n\t\t\t\t\ttheme: 'bubble',\n\t\t\t\t} );\n\n\t\t\t\ted.on( 'text-change', function( delta, oldDelta, source ) {\n\t\t\t\t\tself.model.set( attr, self.get_content( $( ed.root ) ) );\n\t\t\t\t} );\n\n\t\t\t\tBackbone.pubSub.trigger( 'formatting-ed-init', ed, $( this ), self );\n\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Initialize editable select elements\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinit_selects: function() {\n\n\t\t\tthis.$el.find( '.llms-editable-select select' ).llmsSelect2( {\n\t\t\t\twidth: '100%',\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Blur/focusout function for .llms-editable-title elements\n\t\t * Automatically saves changes if changes have been made\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.6\n\t\t */\n\t\ton_blur: function( event ) {\n\n\t\t\tevent.stopPropagation();\n\n\t\t\tthis.model.set( '_has_focus', false, { silent: true } );\n\n\t\t\tvar self = this,\n\t\t\t\t$el = $( event.target ),\n\t\t\t\tchanged = this.has_changed( event );\n\n\t\t\tif ( changed ) {\n\n\t\t\t\tif ( ! self.is_valid( event ) ) {\n\t\t\t\t\tself.revert_edits( event );\n\t\t\t\t} else {\n\t\t\t\t\tthis.save_edits( event );\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Focus event for editable inputs\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.6\n\t\t * @version 3.16.6\n\t\t */\n\t\ton_focus: function( event ) {\n\n\t\t\tevent.stopPropagation();\n\t\t\tthis.model.set( '_has_focus', true, { silent: true } );\n\n\t\t},\n\n\t\t/**\n\t\t * Handle content pasted into contenteditable fields\n\t\t * This will ensure that HTML from RTF editors isn't pasted into the dom\n\t\t * @param obj event js event obj\n\t\t * @return void\n\t\t * @since 3.17.8\n\t\t * @version 3.17.8\n\t\t */\n\t\ton_paste: function( event ) {\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tvar text = ( event.originalEvent || event ).clipboardData.getData( 'text/plain' );\n\t\t\twindow.document.execCommand( 'insertText', false, text );\n\n\t\t},\n\n\t\t/**\n\t\t * Change event for selectables\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ton_select: function( event ) {\n\n\t\t\tvar $el = $( event.target ),\n\t\t\t\tmulti = ( $el.attr( 'multiple' ) ),\n\t\t\t\tattr = $el.attr( 'name' ),\n\t\t\t\t$selected = $el.find( 'option:selected' ),\n\t\t\t\tval;\n\n\t\t\tif ( multi ) {\n\t\t\t\tval = [];\n\t\t\t\tval = $selected.map( function() {\n\t\t\t\t\treturn this.value;\n\t\t\t\t} ).get();\n\t\t\t} else {\n\t\t\t\tval = $selected[0].value;\n\t\t\t}\n\n\t\t\tthis.model.set( attr, val );\n\n\t\t},\n\n\t\t/**\n\t\t * Change event for radio element groups\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.17.6\n\t\t * @version 3.17.6\n\t\t */\n\t\ton_radio_select: function( event ) {\n\n\t\t\tvar $el = $( event.target ),\n\t\t\t\tattr = $el.attr( 'name' ),\n\t\t\t\tval = $el.val();\n\n\t\t\tthis.model.set( attr, val );\n\n\t\t},\n\n\t\t/**\n\t\t * Keydown function for .llms-editable-title elements\n\t\t * Blurs\n\t\t * @param {obj} event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.8\n\t\t */\n\t\ton_keydown: function( event ) {\n\n\t\t\tevent.stopPropagation();\n\n\t\t\tvar self = this,\n\t\t\t\tkey = event.which || event.keyCode,\n\t\t\t\tshift = event.shiftKey;\n\t\t\t\t// ctrl = event.metaKey || event.ctrlKey;\n\n\t\t\tswitch ( key ) {\n\n\t\t\t\tcase 13: // enter\n\t\t\t\t\t// shift + enter should add a return\n\t\t\t\t\tif ( ! shift ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tevent.target.blur();\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\t\tcase 27: // escape\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tthis.revert_edits( event );\n\t\t\t\t\tevent.target.blur();\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Open the WP media lib\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.6\n\t\t */\n\t\topen_media_lib: function( event ) {\n\n\t\t\tevent.stopPropagation();\n\n\t\t\tvar self = this,\n\t\t\t\t$el = $( event.currentTarget );\n\n\t\t\tif ( self.media_lib ) {\n\n\t\t\t\tself.media_lib.uploader.uploader.param( 'post_id' );\n\n\t\t\t} else {\n\n\t\t\t\tself.media_lib = wp.media.frames.file_frame = wp.media( {\n\t\t\t\t\ttitle: LLMS.l10n.translate( 'Select an image' ),\n\t\t\t\t\tbutton: {\n\t\t\t\t\t\ttext: LLMS.l10n.translate( 'Use this image' ),\n\t\t\t\t\t},\n\t\t\t\t\tmultiple: false\t// Set to true to allow multiple files to be selected\n\t\t\t\t} );\n\n\t\t\t\tself.media_lib.on( 'select', function() {\n\n\t\t\t\t\tvar size = $el.attr( 'data-image-size' ),\n\t\t\t\t\t\tattachment = self.media_lib.state().get( 'selection' ).first().toJSON(),\n\t\t\t\t\t\timage = self.model.get( $el.attr( 'data-attribute' ) ),\n\t\t\t\t\t\turl;\n\n\t\t\t\t\tif ( size && attachment.sizes[ size ] ) {\n\t\t\t\t\t\turl = attachment.sizes[ size ].url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\turl = attachment.url;\n\t\t\t\t\t}\n\n\t\t\t\t\timage.set( {\n\t\t\t\t\t\tid: attachment.id,\n\t\t\t\t\t\tsrc: url,\n\t\t\t\t\t} );\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tself.media_lib.open();\n\n\n\t\t},\n\n\t\t/**\n\t\t * Click event to remove an image\n\t\t * @param obj event js event obj\n\t\t * @return voids\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tremove_image: function( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t\tthis.model.get( $( event.currentTarget ).attr( 'data-attribute' ) ).set( {\n\t\t\t\tid: '',\n\t\t\t\tsrc: '',\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Helper to undo changes\n\t\t * Bound to \"escape\" key via on_keydwon function\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trevert_edits: function( event ) {\n\t\t\tvar $el = $( event.target ),\n\t\t\t\tval = $el.attr( 'data-original-content' );\n\t\t\t$el.html( val );\n\t\t},\n\n\t\t/**\n\t\t * Sync chages to the model and DB\n\t\t * @param {obj} event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tsave_edits: function( event ) {\n\n\t\t\tvar $el = $( event.target ),\n\t\t\t\tval = this.get_content( $el );\n\n\t\t\tthis.model.set( $el.attr( 'data-attribute' ), val );\n\n\t\t},\n\n\t\t/**\n\t\t * Change event for a switch element\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.0\n\t\t */\n\t\ttoggle_switch: function( event ) {\n\n\t\t\tevent.stopPropagation();\n\t\t\tvar $el = $( event.target ),\n\t\t\t\tattr = $el.attr( 'name' ),\n\t\t\t\trerender = $el.attr( 'data-rerender' ),\n\t\t\t\tval;\n\n\t\t\tif ( $el.is( ':checked' ) ) {\n\t\t\t\tval = $el.attr( 'data-on' ) ? $el.attr( 'data-on' ) : 'yes';\n\t\t\t} else {\n\t\t\t\tval = $el.attr( 'data-off' ) ? $el.attr( 'data-off' ) : 'no';\n\t\t\t}\n\n\t\t\tif ( -1 !== attr.indexOf( '.' ) ) {\n\n\t\t\t\tvar split = attr.split( '.' );\n\n\t\t\t\tif ( 'parent' === split[0] ) {\n\t\t\t\t\tthis.model.get_parent().set( split[1], val );\n\t\t\t\t} else {\n\t\t\t\t\tthis.model.get( split[0] ).set( split[1], val );\n\t\t\t\t}\n\n\n\t\t\t} else {\n\n\t\t\t\tthis.model.set( attr, val );\n\n\t\t\t}\n\n\t\t\tthis.trigger( attr.replace( '.', '-' ) + '_toggle', val );\n\n\t\t\tif ( ! rerender || 'yes' === rerender ) {\n\t\t\t\tvar self = this;\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\tself.render();\n\t\t\t\t}, 100 );\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Initializes a WP Editor on a textarea\n\t\t * @param string id CSS ID of the editor (don't include #)\n\t\t * @param obj settings optional object of settings to pass to wp.editor.initialize()\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinit_editor: function( id, settings ) {\n\n\t\t\tsettings = settings || {};\n\n\t\t\twp.editor.remove( id );\n\n\t\t\twp.editor.initialize( id, $.extend( true, wp.editor.getDefaultSettings(), {\n\t\t\t\tmediaButtons: true,\n\t\t\t\ttinymce: {\n\t\t\t\t\ttoolbar1: 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_adv',\n\t\t\t\t\ttoolbar2: 'formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',\n\t\t\t\t\tsetup: _.bind( this.on_editor_ready, this ),\n\t\t\t\t}\n\t\t\t}, settings ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Setup a permalink editor to allow editing of a permalink\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.6\n\t\t * @version 3.16.6\n\t\t */\n\t\tmake_slug_editable: function( event ) {\n\n\t\t\tvar self = this,\n\t\t\t\t$btn = $( event.currentTarget ),\n\t\t\t\t$link = $btn.prevAll( 'a' ),\n\t\t\t\t$input = $btn.prev( 'input.permalink' ),\n\t\t\t\tfull_url = $link.attr( 'href' ),\n\t\t\t\tslug = $input.val(),\n\t\t\t\tshort_url = full_url.replace( slug, '' );\n\n\t\t\t// hide the button\n\t\t\t$btn.hide();\n\n\t\t\t// make the link not clickable\n\t\t\t$link.css( {\n\t\t\t\tcolor: '#999',\n\t\t\t\t'pointer-events': 'none',\n\t\t\t\t'text-decoration': 'none',\n\t\t\t} );\n\n\t\t\t// remove the current slug & trailing slash from the URL\n\t\t\t$link.text( short_url.substring( 0, short_url.length - 1 ) );\n\n\t\t\t// focus in on the field\n\t\t\t$input.show().focus();\n\n\t\t},\n\n\t\t/**\n\t\t * Callback function called after initialization of an editor\n\t\t * Updates UI if a label is present\n\t\t * Binds a change event to ensure editor changes are saved to the model\n\t\t * @param obj editor wp.editor instance\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.17.1\n\t\t */\n\t\ton_editor_ready: function( editor ) {\n\n\t\t\tvar self = this,\n\t\t\t\t$ed = $( '#' + editor.id ),\n\t\t\t\t$parent = $ed.closest( '.llms-editable-editor' ),\n\t\t\t\t$label = $parent.find( '.llms-label' ),\n\t\t\t\tprop = $ed.attr( 'data-attribute' )\n\n\t\t\tif ( $label.length ) {\n\t\t\t\t$label.prependTo( $parent.find( '.wp-editor-tools' ) );\n\t\t\t}\n\n\t\t\t// save changes to the model via Visual ed\n\t\t\teditor.on( 'change', function( event ) {\n\t\t\t\tself.model.set( prop, wp.editor.getContent( editor.id ) );\n\t\t\t} );\n\n\t\t\t// save changes via Text ed\n\t\t\t$ed.on( 'input', function( event ) {\n\t\t\t\tself.model.set( prop, $ed.val() );\n\t\t\t} );\n\n\t\t\t// trigger an input on the Text ed when quicktags buttons are clicked\n\t\t\t$parent.on( 'click', '.quicktags-toolbar .ed_button', function() {\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t$ed.trigger( 'input' );\n\t\t\t\t}, 10 );\n\t\t\t} );\n\n\t\t},\n\n\t\t_validate_url: function( str ) {\n\n\t\t\tvar a = document.createElement( 'a' );\n\t\t\ta.href = str;\n\t\t\treturn ( a.host && a.host !== window.location.host );\n\n\t\t}\n\n\t};\n\n} );\n\n","/**\n * _receive override for Backbone.CollectionView core\n * enables connection with jQuery UI draggable buttons\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Views/_Receivable',[], function() {\n\n\treturn {\n\n\t\t/**\n\t\t * Overloads the function from Backbone.CollectionView core because it doesn't properly handle\n\t\t * receieves from a jQuery UI draggable object\n\t\t * @param obj event js event object\n\t\t * @param obj ui jQuery UI object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t_receive : function( event, ui ) {\n\n\t\t\t// came from sidebar drag\n\t\t\tif ( ui.sender.hasClass( 'ui-draggable' ) ) {\n\t\t\t\tvar index = this._getContainerEl().children().index( ui.helper );\n\t\t\t\tui.helper.remove(); // remove the helper\n\t\t\t\tthis.collection.add( {}, { at: index } );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar senderListEl = ui.sender;\n\t\t\tvar senderCollectionListView = senderListEl.data( 'view' );\n\t\t\tif( ! senderCollectionListView || ! senderCollectionListView.collection ) return;\n\n\t\t\tvar newIndex = this._getContainerEl().children().index( ui.item );\n\t\t\tvar modelReceived = senderCollectionListView.collection.get( ui.item.attr( 'data-model-cid' ) );\n\t\t\tsenderCollectionListView.collection.remove( modelReceived );\n\t\t\tthis.collection.add( modelReceived, { at : newIndex } );\n\t\t\tmodelReceived.collection = this.collection; // otherwise will not get properly set, since modelReceived.collection might already have a value.\n\t\t\tthis.setSelectedModel( modelReceived );\n\t\t},\n\n\t}\n\n} );\n\n\n","/**\n * Shiftable view mixin function\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Views/_Shiftable',[], function() {\n\n\treturn {\n\n\t\t/**\n\t\t * Conditionally hide action buttons based on section position in collection\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tmaybe_hide_shiftable_buttons: function() {\n\n\t\t\tif ( ! this.model.collection ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar type = this.model.get( 'type' );\n\n\t\t\tif ( this.model.collection.first() === this.model ) {\n\t\t\t\tthis.$el.find( '.shift-up--' + type ).hide();\n\t\t\t} else if ( this.model.collection.last() === this.model ) {\n\t\t\t\tthis.$el.find( '.shift-down--' + type ).hide();\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Move an item in a collection from one position to another\n\t\t * @param int old_index current (old) index within the collection\n\t\t * @param int new_index desired (new) index within the collection\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tshift: function( old_index, new_index ) {\n\n\t\t\tvar collection = this.model.collection;\n\n\t\t\tcollection.remove( this.model );\n\t\t\tcollection.add( this.model, { at: new_index } );\n\t\t\tcollection.trigger( 'reorder' );\n\n\t\t},\n\n\t\t/**\n\t\t * Move an item down the tree one position\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tshift_down: function( e ) {\n\n\t\t\te.preventDefault();\n\t\t\tvar index = this.model.collection.indexOf( this.model );\n\t\t\tthis.shift( index, index + 1 );\n\n\t\t},\n\n\t\t/**\n\t\t * Move an item up the tree one position\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tshift_up: function( e ) {\n\n\t\t\te.preventDefault();\n\t\t\tvar index = this.model.collection.indexOf( this.model );\n\t\t\tthis.shift( index, index - 1 );\n\n\t\t},\n\n\t};\n\n} );\n\n","/**\n * Subview utility mixin\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Views/_Subview',[], function() {\n\n\treturn {\n\n\t\tsubscriptions: {},\n\n\t\t/**\n\t\t * Name of the current subview\n\t\t * @type {String}\n\t\t */\n\t\tstate: '',\n\n\t\t/**\n\t\t * Object of subview data\n\t\t * @type {Object}\n\t\t */\n\t\tviews: {},\n\n\t\t/**\n\t\t * Retrieve a subview by name from this.views\n\t\t * @param string name name of the subview\n\t\t * @return obl|false\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tget_subview: function( name ) {\n\n\t\t\tif ( this.views[ name ] ) {\n\t\t\t\treturn this.views[ name ];\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\tevents_subscribe: function( events ) {\n\n\t\t\t_.each( events, function( func, event ) {\n\n\t\t\t\tthis.subscriptions[ event ] = func;\n\t\t\t\tBackbone.pubSub.on( event, func, this );\n\n\t\t\t}, this );\n\n\t\t},\n\n\t\tevents_unsubscribe: function() {\n\n\t\t\t_.each( this.subscriptions, function( func, event ) {\n\n\t\t\t\tBackbone.pubSub.off( event, func, this );\n\t\t\t\tdelete this.subscriptions[ event ];\n\n\t\t\t}, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Remove a single subview (and all it's subviews) by name\n\t\t * @param string name name of the subview\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tremove_subview: function( name ) {\n\n\t\t\tvar view = this.get_subview( name );\n\n\t\t\tif ( ! view ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( view.instance ) {\n\n\t\t\t\t// remove the subviews if the view has subviews\n\t\t\t\tif ( ! _.isEmpty( view.instance.views ) ) {\n\t\t\t\t\tview.instance.events_unsubscribe();\n\t\t\t\t\tview.instance.remove_subviews();\n\t\t\t\t}\n\n\t\t\t\tview.instance.off();\n\t\t\t\tview.instance.off( null, null, null );\n\t\t\t\tview.instance.remove();\n\t\t\t\tview.instance.undelegateEvents();\n\n\t\t\t\t// _.each( view.instance, function( val, key ) {\n\t\t\t\t// \tdelete view.instance[ key ];\n\t\t\t\t// } );\n\n\t\t\t\tview.instance = null;\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Remove all subviews (and all the subviews of those subviews)\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tremove_subviews: function() {\n\n\t\t\t_.each( this.views, function( data, name ) {\n\n\t\t\t\tthis.remove_subview( name );\n\n\t\t\t}, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Render subviews based on current state\n\t\t * @param obj view_data additional data to pass to the subviews\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trender_subviews: function( view_data ) {\n\n\t\t\tview_data = view_data || {};\n\n\t\t\t_.each( this.views, function( data, name ) {\n\n\t\t\t\tif ( this.state === data.state ) {\n\n\t\t\t\t\tthis.render_subview( name, view_data );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.remove_subview( name );\n\n\t\t\t\t}\n\n\t\t\t}, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Render a single subview by name\n\t\t * @param string name name of the subview\n\t\t * @param obj view_data additional data to pass to the subview initializer\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trender_subview: function( name, view_data ) {\n\n\t\t\tvar view = this.get_subview( name );\n\n\t\t\tif ( ! view ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.remove_subview( name );\n\n\t\t\tif ( ! view.instance ) {\n\t\t\t\tview.instance = new view.class( view_data );\n\t\t\t}\n\n\t\t\tview.instance.render();\n\n\t\t},\n\n\t\t/**\n\t\t * Set the current subview\n\t\t * Must call render after!\n\t\t * @param string state name of the state [builder|editor]\n\t\t * @return obj this for chaining\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tset_state: function ( state ) {\n\n\t\t\tthis.state = state;\n\t\t\treturn this;\n\n\t\t},\n\n\t}\n\n} );\n\n","/**\n * Trashable model\n * @type {Object}\n * @since 3.16.12\n * @version 3.16.12\n */\ndefine( 'Views/_Trashable',[], function() {\n\n\treturn {\n\n\t\t/**\n\t\t * DOM Events\n\t\t * @type {Object}\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tevents: {\n\t\t\t'click a[href=\"#llms-trash-model\"]': 'trash_model',\n\t\t},\n\n\t\t/**\n\t\t * Remove a model from it's parent and delete it\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\ttrash_model: function( event ) {\n\n\t\t\tif ( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}\n\n\t\t\tvar msg = LLMS.l10n.replace( 'Are you sure you want to move this %s to the trash?', {\n\t\t\t\t'%s': this.model.get_l10n_type(),\n\t\t\t} );\n\n\t\t\tif ( window.confirm( msg ) ) {\n\n\t\t\t\tif ( this.model.collection ) {\n\t\t\t\t\tthis.model.collection.remove( this.model );\n\t\t\t\t}\n\n\t\t\t\t// publish event\n\t\t\t\tBackbone.pubSub.trigger( 'model-trashed', this.model );\n\n\t\t\t\t// trigger local event so extending views can run other actions where necessary\n\t\t\t\tthis.trigger( 'model-trashed', this.model );\n\n\t\t\t}\n\n\t\t},\n\n\t}\n\n} );\n\n","/**\n * Load view mixins\n * @return obj\n * @since 3.17.1\n * @version 3.17.1\n */\ndefine( 'Views/_loader',[\n\t\t'Views/_Detachable',\n\t\t'Views/_Editable',\n\t\t'Views/_Receivable',\n\t\t'Views/_Shiftable',\n\t\t'Views/_Subview',\n\t\t'Views/_Trashable'\n\t],\n\tfunction(\n\t\tDetachable,\n\t\tEditable,\n\t\tReceivable,\n\t\tShiftable,\n\t\tSubview,\n\t\tTrashable\n\t) {\n\n\treturn {\n\t\tDetachable: Detachable,\n\t\tEditable: Editable,\n\t\tReceivable: Receivable,\n\t\tShiftable: Shiftable,\n\t\tSubview: Subview,\n\t\tTrashable: Trashable,\n\t};\n\n} );\n\n","/**\n * Constructor functions for constructing models, views, and collections\n * @since 3.16.0\n * @version 3.17.1\n */\ndefine( 'Controllers/Construct',[\n\t\t'Collections/loader',\n\t\t'Models/loader',\n\t\t'Views/_loader'\n\t], function(\n\t\tCollections,\n\t\tModels,\n\t\tViews\n\t) {\n\n\treturn function() {\n\n\t\t/**\n\t\t * Internal getter\n\t\t * Constructs new Collections, Models, and Views\n\t\t * @param obj type type of object to construct [Collection,Model,View]\n\t\t * @param string name name of the object to construct\n\t\t * @param obj data object data to pass into the object's constructor\n\t\t * @param obj options object options to pass into the constructor\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tfunction get( type, name, data, options ) {\n\n\t\t\tif ( ! type[ name ] ) {\n\t\t\t\tconsole.log( '\"' + name + '\" not found.' );\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn new type[ name ]( data, options );\n\n\t\t}\n\n\t\t/**\n\t\t * Instantiate a collection\n\t\t * @param string name Collection class name (EG: \"Sections\")\n\t\t * @param array data Array of model objects to pass to the constructor\n\t\t * @param obj options Object of options to pass to the constructor\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tthis.get_collection = function( name, data, options ) {\n\n\t\t\treturn get( Collections, name, data, options );\n\n\t\t};\n\n\t\t/**\n\t\t * Instantiate a model\n\t\t * @param string name Model class name (EG: \"Section\")\n\t\t * @param obj data Object of model attributes to pass to the constructor\n\t\t * @param obj options Object of options to pass to the constructor\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tthis.get_model = function( name, data, options ) {\n\n\t\t\treturn get( Models, name, data, options );\n\n\t\t};\n\n\t\t/**\n\t\t * Let 3rd parties extend a view using any of the mixin (_) views\n\t\t * @param {obj} view base object used for the view\n\t\t * @param... {string} extends any number of strings that should be mixed into the view\n\t\t * @return obj\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\tthis.extend_view = function() {\n\n\t\t\tvar view = arguments[0],\n\t\t\t\ti = 1;\n\n\t\t\twhile ( arguments[ i ] ) {\n\n\t\t\t\tvar classname = arguments[ i ];\n\t\t\t\tif ( Views[ classname ] ) {\n\n\t\t\t\t\tif ( view.events && Views[ classname ].events ) {\n\t\t\t\t\t\tview.events = _.defaults( view.events, Views[ classname ].events );\n\t\t\t\t\t}\n\n\t\t\t\t\tview = _.defaults( view, Views[ classname ] );\n\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\treturn Backbone.View.extend( view );\n\n\t\t};\n\n\t\t/**\n\t\t * Allows custom collection registration by extending the default BackBone collection\n\t\t * @param string name model name\n\t\t * @param obj props properties to extend the collection with\n\t\t * @return void\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\tthis.register_collection = function( name, props ) {\n\n\t\t\tCollections[ name ] = Backbone.Collection.extend( props );\n\n\t\t};\n\n\t\t/**\n\t\t * Allows custom model registration by extending the default abstract model\n\t\t * @param string name model name\n\t\t * @param obj props properties to extend the abstract model with\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tthis.register_model = function( name, props ) {\n\n\t\t\tModels[ name ] = Models['Abstract'].extend( props );\n\n\t\t};\n\n\t\treturn this;\n\n\t};\n\n} );\n\n","/**\n * LifterLMS Builder Debugging suite\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Controllers/Debug',[], function() {\n\n \treturn function( settings ) {\n\n \t\tvar self = this,\n \t\t\tenabled = settings.enabled || false;\n\n\t\t/**\n\t\t * Disable debugging\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n \t\tthis.disable = function() {\n\n \t\t\tself.log( 'LifterLMS Builder debugging disabled' );\n \t\t\tenabled = false;\n\n \t\t};\n\n\t\t/**\n\t\t * Enable debugging\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n \t\tthis.enable = function() {\n\n \t\t\tenabled = true;\n \t\t\tself.log( 'LifterLMS Builder debugging enabled' );\n\n \t\t};\n\n \t\t/**\n \t\t * General logging function\n \t\t * Logs to the js console only if logging is enabled\n \t\t * @return void\n \t\t * @since 3.16.0\n \t\t * @version 3.16.0\n \t\t */\n \t\tthis.log = function() {\n\n\t\t\tif ( ! enabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_.each( arguments, function( data ) {\n\t\t\t\tconsole.log( data );\n\t\t\t} );\n\n \t\t};\n\n \t\t/**\n \t\t * Toggles current state of the logger on or off\n \t\t * @return void\n \t\t * @since 3.16.0\n \t\t * @version 3.16.0\n \t\t */\n \t\tthis.toggle = function() {\n\n\t\t\tif ( enabled ) {\n\t\t\t\tself.disable();\n\t\t\t} else {\n\t\t\t\tself.enable();\n\t\t\t}\n\n \t\t};\n\n \t\t// on startup, log a message if logging is enabled\n \t\tif ( enabled ) {\n \t\t\tself.enable();\n \t\t}\n\n \t}\n\n } );\n\n","/**\n * Model schema functions\n * @since 3.17.0\n * @version 3.17.0\n */\ndefine( 'Controllers/Schemas',[], function() {\n\n\t/**\n\t * Main Schemas class\n\t * @param obj schemas schemas definitions initialized via PHP filters\n\t * @return obj\n\t * @since 3.17.0\n\t * @version 3.17.0\n\t */\n\treturn function( schemas ) {\n\n\t\t// initialize any custom schemas defined via PHP\n\t\tvar custom_schemas = schemas;\n\t\t_.each( custom_schemas, function( type ) {\n\t\t\t_.each( type, function( schema ) {\n\t\t\t\tschema.custom = true;\n\t\t\t} );\n\t\t} );\n\n\t\t/**\n\t\t * Retrieve a schema for a given model by type\n\t\t * Extends default schemas definitions with custom 3rd party definitions\n\t\t * @param obj schema default schema definition from the model (or empty object if none defined)\n\t\t * @param string model_type the model type ('lesson', 'quiz', etc)\n\t\t * @param obj model Instance of the Backbone.Model for the given model\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tthis.get = function( schema, model_type, model ) {\n\n\t\t\t// extend the default schema with custom php schemas for the type if they exist\n\t\t\tif ( custom_schemas[ model_type ] ) {\n\t\t\t\tschema = _.extend( schema, custom_schemas[ model_type ] );\n\t\t\t}\n\n\t\t\treturn schema;\n\n\t\t};\n\n\t\treturn this;\n\n\t};\n\n} );\n\n","/**\n * Sync builder data to the server\n * @since 3.16.0\n * @version 3.17.1\n */\ndefine( 'Controllers/Sync',[], function() {\n\n \treturn function( Course, settings ) {\n\n \t\tthis.saving = false;\n\n \t\tvar self = this,\n \t\t\tautosave = true,\n \t\t\tcheck_interval = null,\n \t\t\tcheck_interval_ms = settings.check_interval_ms || 10000,\n \t\t\tdetached = new Backbone.Collection(),\n \t\t\ttrashed = new Backbone.Collection();\n\n\t\t/**\n\t\t * init\n\t\t * @return void\n\t\t * @since 3.16.7\n\t\t * @version 3.16.7\n\t\t */\n \t\tfunction init() {\n\n \t\t\t// determine if autosaving is possible\n \t\t\tif ( 'undefined' === typeof wp.heartbeat ) {\n\n \t\t\t\twindow.llms_builder.debug.log( 'WordPress Heartbeat disabled. Autosaving is disabled!' );\n \t\t\t\tautosave = false;\n\n \t\t\t}\n\n\t\t\t// setup the check interval\n\t\t\tif ( check_interval_ms ) {\n\t\t\t\tself.set_check_interval( check_interval_ms );\n\t\t\t}\n\n\t\t\t// warn when users attempt to leave the page\n\t\t\t$( window ).on( 'beforeunload', function() {\n\n\t\t\t\tif ( self.has_unsaved_changes() ) {\n\t\t\t\t\tcheck_for_changes();\n\t\t\t\t\treturn 'Are you sure you want to abandon your changes?';\n\t\t\t\t}\n\n\t\t\t} );\n\n \t\t};\n\n \t\t/*\n \t\t\t /$$ /$$ /$$ /$$\n \t\t\t|__/ | $$ | $$ |__/\n \t\t\t /$$ /$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ | $$ /$$$$$$ /$$$$$$ /$$\n \t\t\t| $$| $$__ $$|_ $$_/ /$$__ $$ /$$__ $$| $$__ $$ |____ $$| $$ |____ $$ /$$__ $$| $$\n \t\t\t| $$| $$ \\ $$ | $$ | $$$$$$$$| $$ \\__/| $$ \\ $$ /$$$$$$$| $$ /$$$$$$$| $$ \\ $$| $$\n \t\t\t| $$| $$ | $$ | $$ /$$| $$_____/| $$ | $$ | $$ /$$__ $$| $$ /$$__ $$| $$ | $$| $$\n \t\t\t| $$| $$ | $$ | $$$$/| $$$$$$$| $$ | $$ | $$| $$$$$$$| $$ | $$$$$$$| $$$$$$$/| $$\n \t\t\t|__/|__/ |__/ \\___/ \\_______/|__/ |__/ |__/ \\_______/|__/ \\_______/| $$____/ |__/\n \t\t\t | $$\n \t\t\t | $$\n \t\t\t |__/\n \t\t*/\n\n \t\t/**\n \t\t * Adds error message(s) to the data object returned by heartbeat-tick\n \t\t * @param obj data llms_builder data object from heartbeat-tick\n \t\t * @param string|array err error messages array or string\n \t\t * @return obj\n \t\t * @since 3.16.0\n \t\t * @version 3.16.0\n \t\t */\n\t\tfunction add_error_msg( data, err ) {\n\n\t\t\tif ( 'success' === data.status ) {\n\t\t\t\tdata.message = [];\n\t\t\t}\n\n\t\t\tdata.status = 'error';\n\t\t\tif ( 'string' === typeof err ) {\n\t\t\t\terr = [ err ];\n\t\t\t}\n\t\t\tdata.message = data.message.concat( err );\n\n\t\t\treturn data;\n\n\t\t};\n\n\t\t/**\n\t\t * Publish sync status so other areas of the application can see what's happening here\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tfunction check_for_changes() {\n\n\t\t\tvar data = {};\n\t\t\tdata.changes = self.get_unsaved_changes();\n\t\t\tdata.has_unsaved_changes = self.has_unsaved_changes( data.changes );\n\t\t\tdata.saving = self.saving;\n\n\t\t\twindow.llms_builder.debug.log( '==== start changes check ====', data, '==== finish changes check ====' );\n\n\t\t\tBackbone.pubSub.trigger( 'current-save-status', data );\n\n\t\t};\n\n\t\t/**\n\t\t * Manually Save data via Admin AJAX when the heartbeat API has been disabled\n\t\t * @return void\n\t\t * @since 3.16.7\n\t\t * @version 3.16.7\n\t\t */\n\t\tfunction do_ajax_save() {\n\n\t\t\t// prevent simultaneous saves\n\t\t\tif ( self.saving ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar changes = self.get_unsaved_changes();\n\n\t\t\t// only send data if we have data to send\n\t\t\tif ( self.has_unsaved_changes( changes ) ) {\n\n\t\t\t\tchanges.id = Course.get( 'id' );\n\n\t\t\t\tLLMS.Ajax.call( {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\taction: 'llms_builder',\n\t\t\t\t\t\taction_type: 'ajax_save',\n\t\t\t\t\t\tcourse_id: changes.id,\n\t\t\t\t\t\tllms_builder: JSON.stringify( changes ),\n\t\t\t\t\t},\n\t\t\t\t\tbeforeSend: function() {\n\n\t\t\t\t\t\twindow.llms_builder.debug.log( '==== start do_ajax_save before ====', changes, '==== finish do_ajax_save before ====' );\n\n\t\t\t\t\t\tself.saving = true;\n\n\t\t\t\t\t\tBackbone.pubSub.trigger( 'heartbeat-send', self );\n\n\t\t\t\t\t},\n\t\t\t\t\terror: function( xhr, status, error ) {\n\n\t\t\t\t\t\twindow.llms_builder.debug.log( '==== start do_ajax_save error ====', data, '==== finish do_ajax_save error ====' );\n\n\t\t\t\t\t\tself.saving = false;\n\n\t\t\t\t\t\tBackbone.pubSub.trigger( 'heartbeat-tick', self, {\n\t\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\t\tmessage: xhr.responseText + ' (' + error + ' ' + status +')',\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function( res ) {\n\n\t\t\t\t\t\tif ( ! res.llms_builder ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\twindow.llms_builder.debug.log( '==== start do_ajax_save success ====', res, '==== finish do_ajax_save success ====' );\n\n\t\t\t\t\t\tres.llms_builder = process_removals( res.llms_builder );\n\t\t\t\t\t\tres.llms_builder = process_updates( res.llms_builder );\n\n\t\t\t\t\t\tself.saving = false;\n\n\t\t\t\t\t\tBackbone.pubSub.trigger( 'heartbeat-tick', self, res.llms_builder );\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\n\t\t};\n\n\t\t/**\n\t\t * Retrieve all the attributes changed on a model since the last sync\n\t\t *\n\t\t * For a new model (a model with a temp ID) or a model where _forceSync has been defined ALL atts will be returned\n\t\t * For an existing model (without a temp ID) only retrieves changed attributes as tracked by Backbone.TrackIt\n\t\t *\n\t\t * This function excludes any attributes defined as child attributes via the models relationship settings\n\t\t *\n\t\t * @param obj model instance of a Backbone.Model\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.6\n\t\t */\n\t\tfunction get_changed_attributes( model ) {\n\n\t\t\tvar atts = {},\n\t\t\t\tsync_type;\n\n\t\t\t// don't save mid editing\n\t\t\tif ( model.get( '_has_focus' ) ) {\n\t\t\t\treturn atts;\n\t\t\t}\n\n\t\t\t// model hasn't been persisted to the database to get a real ID yet\n\t\t\t// send *all* of it's atts\n\t\t\tif ( has_temp_id( model ) || true === model.get( '_forceSync' ) ) {\n\n\t\t\t\tatts = _.clone( model.attributes );\n\t\t\t\tsync_type = 'full';\n\n\t\t\t// only send the changed atts\n\t\t\t} else {\n\n\t\t\t\tatts = model.unsavedAttributes();\n\t\t\t\tsync_type = 'partial';\n\n\t\t\t}\n\n\t\t\tvar exclude = ( model.get_relationships ) ? model.get_child_props() : [];\n\t\t\tatts = _.omit( atts, function( val, key ) {\n\n\t\t\t\t// exclude keys that start with an underscore which are used by the\n\t\t\t\t// application but don't need to be stored in the database\n\t\t\t\tif ( 0 === key.indexOf( '_' ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else if ( -1 !== exclude.indexOf( key ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\n\t\t\t} );\n\n\t\t\tif ( model.before_save ) {\n\t\t\t\tatts = model.before_save( atts, sync_type );\n\t\t\t}\n\n\t\t\treturn atts;\n\n\t\t};\n\n\t\t/**\n\t\t * Get all the changes to an object (either a Model or a Collection of models)\n\t\t * Returns only changes to models and the IDs of that model (should changes exist)\n\t\t * Uses get_changed_attributes() to determine if all atts or only changed atts are needed\n\t\t * Processes children intelligently to only return changed children rather than the entire collection of children\n\t\t *\n\t\t * @param obj object instance of a Backbone.Model or Backbone.Collection\n\t\t * @return obj|array\t \t\tif object is a model, returns an object\n\t\t * \tif object is a collection, returns an array of objects\n\t\t * @since 3.16.0\n\t\t * @version 3.16.11\n\t\t */\n\t\tfunction get_changes_to_object( object ) {\n\n\t\t\tvar changed_atts;\n\n\t\t\tif ( object instanceof Backbone.Model ) {\n\n\t\t\t\tchanged_atts = get_changed_attributes( object );\n\n\t\t\t\tif ( object.get_relationships ) {\n\n\t\t\t\t\t_.each( object.get_child_props(), function( prop ) {\n\n\t\t\t\t\t\tvar children = get_changes_to_object( object.get( prop ) );\n\t\t\t\t\t\tif ( ! _.isEmpty( children ) ) {\n\t\t\t\t\t\t\tchanged_atts[ prop ] = children;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\t// if we have any data, add the id to the model\n\t\t\t\tif ( ! _.isEmpty( changed_atts ) ) {\n\t\t\t\t\tchanged_atts.id = object.get( 'id' );\n\t\t\t\t}\n\n\t\t\t} else if ( object instanceof Backbone.Collection ) {\n\n\t\t\t\tchanged_atts = [];\n\t\t\t\tobject.each( function( model ) {\n\t\t\t\t\tvar model_changes = get_changes_to_object( model );\n\t\t\t\t\tif ( ! _.isEmpty( model_changes ) ) {\n\t\t\t\t\t\tchanged_atts.push( model_changes );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn changed_atts;\n\n\t\t};\n\n\t\t/**\n\t\t * Determines if a model has a temporary ID or a real persisted ID\n\t\t * @param obj model instance of a model\n\t\t * @return boolean\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tfunction has_temp_id( model ) {\n\n\t\t\treturn ( ! _.isNumber( model.id ) && 0 === model.id.indexOf( 'temp_' ) );\n\n\t\t};\n\n\t\t/**\n\t\t * Compares changes synced to the server against current model and restarts\n\t\t * tracking on elements that haven't changed since the last sync\n\t\t * @param obj model instance of a Backbone.Model\n\t\t * @param obj data data set that was processed by the server\n\t\t * @return void\n\t\t * @since 3.16.11\n\t\t * @version 3.16.6\n\t\t */\n\t\tfunction maybe_restart_tracking( model, data ) {\n\n\t\t\tvar omit = [ 'id', 'orig_id' ];\n\n\t\t\tif ( model.get_relationships ) {\n\t\t\t\tomit.concat( model.get_child_props() );\n\t\t\t}\n\n\t\t\t_.each( _.omit( data, omit ), function( val, prop ) {\n\n\t\t\t\tif ( _.isEqual( model.get( prop ), val ) ) {\n\t\t\t\t\tdelete model._unsavedChanges[ prop ];\n\t\t\t\t\tmodel._originalAttrs[ prop ] = val;\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\t// if syncing was forced, allow tracking to move forward as normal moving forward\n\t\t\tmodel.unset( '_forceSync' );\n\n\t\t};\n\n\t\t/**\n\t\t * Processes response data from heartbeat-tick related to trashing & detaching models\n\t\t * On success, removes from local removal collection\n\t\t * On error, appends error messages to the data object returned to UI for on-screen feedback\n\t\t * @param obj data data.llms_builder object from heartbeat-tick response\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.17.1\n\t\t */\n\t\tfunction process_removals( data ) {\n\n\t\t\t// check removals for errors\n\t\t\tvar removals = {\n\t\t\t\tdetach: detached,\n\t\t\t\ttrash: trashed,\n\t\t\t};\n\n\t\t\t_.each( removals, function( coll, key ) {\n\n\t\t\t\tif ( data[ key ] ) {\n\n\t\t\t\t\tvar errors = [];\n\n\t\t\t\t\t_.each( data[ key ] , function( info ) {\n\n\t\t\t\t\t\t// succesfully detached, remove it from the detached collection\n\t\t\t\t\t\tif ( ! info.error ) {\n\n\t\t\t\t\t\t\tcoll.remove( info.id );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\terrors.push( info.error );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t\tif ( errors.length ) {\n\t\t\t\t\t\t_.extend( data, add_error_msg( data, errors ) );\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\treturn data;\n\t\t}\n\n\t\t/**\n\t\t * Processes response data from heartbeat-tick related to creating / updating a single object\n\t\t * Handles both collections and models as a recursive function\n\t\t * @param {[type]} data [description]\n\t\t * @param {[type]} type [description]\n\t\t * @param {[type]} parent [description]\n\t\t * @param {[type]} main_data [description]\n\t\t * @return {[type]}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.11\n\t\t */\n\t\tfunction process_object_updates( data, type, parent, main_data ) {\n\n\t\t\tif ( ! data[ type ] ) {\n\t\t\t\treturn data;\n\t\t\t}\n\n\t\t\tif ( parent.get( type ) instanceof Backbone.Model ) {\n\n\t\t\t\tvar info = data[ type ];\n\n\t\t\t\tif ( info.error ) {\n\n\t\t\t\t\t_.extend( main_data, add_error_msg( main_data, info.error ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar model = parent.get( type );\n\n\t\t\t\t\t// update temp ids with the real id\n\t\t\t\t\tif ( info.id != info.orig_id ) {\n\t\t\t\t\t\tmodel.set( 'id', info.id );\n\t\t\t\t\t\tdelete model._unsavedChanges.id;\n\t\t\t\t\t}\n\t\t\t\t\tmaybe_restart_tracking( model, info );\n\n\t\t\t\t\t// check children\n\t\t\t\t\tif ( model.get_relationships ) {\n\n\t\t\t\t\t\t_.each( model.get_child_props(), function( child_key ) {\n\t\t\t\t\t\t\t_.extend( data[ type ], process_object_updates( data[ type ], child_key, model, main_data ) );\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( parent.get( type ) instanceof Backbone.Collection ) {\n\n\t\t\t\t_.each( data[ type ], function( info, index ) {\n\n\t\t\t\t\tif ( info.error ) {\n\n\t\t\t\t\t\t_.extend( main_data, add_error_msg( main_data, info.error ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar model = parent.get( type ).get( info.orig_id );\n\n\t\t\t\t\t\t// update temp ids with the real id\n\t\t\t\t\t\tif ( info.id != info.orig_id ) {\n\t\t\t\t\t\t\tmodel.set( 'id', info.id );\n\t\t\t\t\t\t\tdelete model._unsavedChanges.id;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmaybe_restart_tracking( model, info );\n\n\t\t\t\t\t\t// check children\n\t\t\t\t\t\tif ( model.get_relationships ) {\n\n\t\t\t\t\t\t\t_.each( model.get_child_props(), function( child_key ) {\n\t\t\t\t\t\t\t\t_.extend( data[ type ], process_object_updates( data[ type ][ index ], child_key, model, main_data ) );\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn main_data;\n\n\t\t};\n\n\t\t/**\n\t\t * Processes response data from heartbeat-tick related to updating & creating new models\n\t\t * On success, removes from local removal collection\n\t\t * On error, appends error messages to the data object returned to UI for on-screen feedback\n\t\t * @param obj data data.llms_builder object from heartbeat-tick response\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tfunction process_updates( data ) {\n\n\t\t\t// only mess with updates data\n\t\t\tif ( ! data.updates ) {\n\t\t\t\treturn data;\n\t\t\t}\n\n\t\t\tif ( data.updates ) {\n\t\t\t\tdata = process_object_updates( data.updates, 'sections', Course, data );\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t};\n\n\t\t/*\n\t\t\t /$$ /$$ /$$ /$$\n\t\t\t | $$ | $$|__/ |__/\n\t\t\t /$$$$$$ /$$ /$$| $$$$$$$ | $$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$ /$$\n\t\t\t /$$__ $$| $$ | $$| $$__ $$| $$| $$ /$$_____/ |____ $$ /$$__ $$| $$\n\t\t\t| $$ \\ $$| $$ | $$| $$ \\ $$| $$| $$| $$ /$$$$$$$| $$ \\ $$| $$\n\t\t\t| $$ | $$| $$ | $$| $$ | $$| $$| $$| $$ /$$__ $$| $$ | $$| $$\n\t\t\t| $$$$$$$/| $$$$$$/| $$$$$$$/| $$| $$| $$$$$$$ | $$$$$$$| $$$$$$$/| $$\n\t\t\t| $$____/ \\______/ |_______/ |__/|__/ \\_______/ \\_______/| $$____/ |__/\n\t\t\t| $$ | $$\n\t\t\t| $$ | $$\n\t\t\t|__/ |__/\n\t\t*/\n\n\t\t/**\n\t\t * Retrieve all unsaved changes for the builder instance\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.17.1\n\t\t */\n\t\tthis.get_unsaved_changes = function() {\n\n\t\t\treturn {\n\t\t\t\tdetach: detached.pluck( 'id' ),\n\t\t\t\ttrash: trashed.pluck( 'id' ),\n\t\t\t\tupdates: get_changes_to_object( Course ),\n\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Check if the builder instance has unsaved changes\n\t\t * @param obj changes optionally pass in an object from the return of this.get_unsaved_changes()\n\t\t * save some resources by not running the check twice during heartbeats\n\t\t * @return boolean\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tthis.has_unsaved_changes = function( changes ) {\n\n\t\t\tif ( 'undefined' === typeof changes ) {\n\t\t\t\tchanges = self.get_unsaved_changes();\n\t\t\t}\n\n\t\t\t// check all possible keys, once we find one with content we have some changes to persist\n\t\t\tvar found = _.find( changes, function( data ) {\n\n\t\t\t\treturn ( false === _.isEmpty( data ) );\n\n\t\t\t} );\n\n\t\t\treturn found ? true : false;\n\n\t\t};\n\n\t\t/**\n\t\t * Save changes right now.\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.7\n\t\t */\n\t\tthis.save_now = function() {\n\t\t\tif ( autosave ) {\n\t\t\t\twp.heartbeat.connectNow();\n\t\t\t} else {\n\t\t\t\tdo_ajax_save();\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Update the interval that checks for changes to the builder instance\n\t\t * @param int ms time (in milliseconds) to run the check on\n\t\t * pass 0 to disable the check\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tthis.set_check_interval = function( ms ) {\n\t\t\tcheck_interval_ms = ms;\n\t\t\tif ( check_interval ) {\n\t\t\t\tclearInterval( check_interval );\n\t\t\t}\n\t\t\tif ( check_interval_ms ) {\n\t\t\t\tcheck_interval = setInterval( check_for_changes, check_interval_ms );\n\t\t\t}\n\t\t};\n\n\t\t/*\n\t\t\t /$$ /$$ /$$\n\t\t\t| $$|__/ | $$\n\t\t\t| $$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$\n\t\t\t| $$| $$ /$$_____/|_ $$_/ /$$__ $$| $$__ $$ /$$__ $$ /$$__ $$ /$$_____/\n\t\t\t| $$| $$| $$$$$$ | $$ | $$$$$$$$| $$ \\ $$| $$$$$$$$| $$ \\__/| $$$$$$\n\t\t\t| $$| $$ \\____ $$ | $$ /$$| $$_____/| $$ | $$| $$_____/| $$ \\____ $$\n\t\t\t| $$| $$ /$$$$$$$/ | $$$$/| $$$$$$$| $$ | $$| $$$$$$$| $$ /$$$$$$$/\n\t\t\t|__/|__/|_______/ \\___/ \\_______/|__/ |__/ \\_______/|__/ |_______/\n\t\t*/\n\n\t\t/**\n\t\t * Listen for detached models and send them to the server for persistence\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tBackbone.pubSub.on( 'model-detached', function( model ) {\n\n\t\t\t// detached models with temp ids haven't been persisted so we don't care\n\t\t\tif ( has_temp_id( model ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tdetached.add( _.clone( model.attributes ) );\n\n\t\t} );\n\n\t\t/**\n\t\t * Listen for trashed models and send them to the server for deletion\n\t\t * @since 3.16.0\n\t\t * @version 3.17.1\n\t\t */\n\t\tBackbone.pubSub.on( 'model-trashed', function( model ) {\n\n\t\t\t// if the model has a temp ID we don't have to persist the deletion\n\t\t\tif ( has_temp_id( model ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar data = _.clone( model.attributes );\n\n\t\t\tif ( model.get_trash_id ) {\n\t\t\t\tdata.id = model.get_trash_id();\n\t\t\t}\n\n\t\t\ttrashed.add( data );\n\n\t\t} );\n\n\t\t/*\n\t\t\t /$$ /$$ /$$ /$$\n\t\t\t| $$ | $$ | $$ | $$\n\t\t\t| $$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$ | $$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$\n\t\t\t| $$__ $$ /$$__ $$ |____ $$ /$$__ $$|_ $$_/ | $$__ $$ /$$__ $$ |____ $$|_ $$_/\n\t\t\t| $$ \\ $$| $$$$$$$$ /$$$$$$$| $$ \\__/ | $$ | $$ \\ $$| $$$$$$$$ /$$$$$$$ | $$\n\t\t\t| $$ | $$| $$_____/ /$$__ $$| $$ | $$ /$$| $$ | $$| $$_____/ /$$__ $$ | $$ /$$\n\t\t\t| $$ | $$| $$$$$$$| $$$$$$$| $$ | $$$$/| $$$$$$$/| $$$$$$$| $$$$$$$ | $$$$/\n\t\t\t|__/ |__/ \\_______/ \\_______/|__/ \\___/ |_______/ \\_______/ \\_______/ \\___/\n\t\t*/\n\n\t\t/**\n\t\t * Add data to the WP heartbeat to persist new models, changes, and deletions to the DB\n\t\t * @since 3.16.0\n\t\t * @version 3.16.7\n\t\t */\n\t\t$( document ).on( 'heartbeat-send', function( event, data ) {\n\n\t\t\t// prevent simultaneous saves\n\t\t\tif ( self.saving ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar changes = self.get_unsaved_changes();\n\n\t\t\t// only send data if we have data to send\n\t\t\tif ( self.has_unsaved_changes( changes ) ) {\n\n\t\t\t\tchanges.id = Course.get( 'id' );\n\t\t\t\tself.saving = true;\n\t\t\t\tdata.llms_builder = JSON.stringify( changes );\n\n\t\t\t}\n\n\t\t\twindow.llms_builder.debug.log( '==== start heartbeat-send ====', data, '==== finish heartbeat-send ====' );\n\n\t\t\tBackbone.pubSub.trigger( 'heartbeat-send', self );\n\n\t\t} );\n\n\t\t/**\n\t\t * Confirm detachments & deletions and replace temp IDs with new persisted IDs\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t$( document ).on( 'heartbeat-tick', function( event, data ) {\n\n\t\t\tif ( ! data.llms_builder ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twindow.llms_builder.debug.log( '==== start heartbeat-tick ====', data, '==== finish heartbeat-tick ====' );\n\n\t\t\tdata.llms_builder = process_removals( data.llms_builder );\n\t\t\tdata.llms_builder = process_updates( data.llms_builder );\n\n\t\t\tself.saving = false;\n\n\t\t\tBackbone.pubSub.trigger( 'heartbeat-tick', self, data.llms_builder );\n\n\t\t} );\n\n\t\t/**\n\t\t * On heartbeat errors publish an error to the main builder application\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t$( document ).on( 'heartbeat-error', function( event, data ) {\n\n\t\t\twindow.llms_builder.debug.log( '==== start heartbeat-error ====', data, '==== finish heartbeat-error ====' );\n\n\t\t\tself.saving = false;\n\n\t\t\tBackbone.pubSub.trigger( 'heartbeat-tick', self, {\n\t\t\t\tstatus: 'error',\n\t\t\t\tmessage: data.responseText + ' (' + data.status + ' ' + data.statusText +')',\n\t\t\t} );\n\n\t\t} );\n\n\t\t/*\n\t\t\t /$$ /$$ /$$\n\t\t\t|__/ |__/ | $$\n\t\t\t /$$ /$$$$$$$ /$$ /$$$$$$\n\t\t\t| $$| $$__ $$| $$|_ $$_/\n\t\t\t| $$| $$ \\ $$| $$ | $$\n\t\t\t| $$| $$ | $$| $$ | $$ /$$\n\t\t\t| $$| $$ | $$| $$ | $$$$/\n\t\t\t|__/|__/ |__/|__/ \\___/\n\t\t*/\n\t\tinit();\n\n\t\treturn this;\n\n\t};\n\n} );\n\n","/**\n * Single Lesson View\n * @since 3.16.0\n * @version 3.17.0\n */\ndefine( 'Views/Lesson',[\n\t\t'Views/_Detachable',\n\t\t'Views/_Editable',\n\t\t'Views/_Shiftable',\n\t\t'Views/_Trashable'\n\t], function(\n\t\tDetachable,\n\t\tEditable,\n\t\tShiftable,\n\t\tTrashable\n\t) {\n\n\treturn Backbone.View.extend( _.defaults( {\n\n\t\t/**\n\t\t * Get default attributes for the html wrapper element\n\t\t * @return obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tattributes: function() {\n\t\t\treturn {\n\t\t\t\t'data-id': this.model.id,\n\t\t\t\t'data-section-id': this.model.get( 'parent_section' ),\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * HTML class names\n\t\t * @type {String}\n\t\t */\n\t\tclassName: 'llms-builder-item llms-lesson',\n\n\t\t/**\n\t\t * Events\n\t\t * @type {Object}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\tevents: _.defaults( {\n\t\t\t'click .edit-lesson': 'open_lesson_editor',\n\t\t\t'click .edit-quiz': 'open_quiz_editor',\n\t\t\t'click .edit-assignment': 'open_assignment_editor',\n\t\t\t'click .section-prev': 'section_prev',\n\t\t\t'click .section-next': 'section_next',\n\t\t\t'click .shift-up--lesson': 'shift_up',\n\t\t\t'click .shift-down--lesson': 'shift_down',\n\t\t}, Detachable.events, Editable.events, Trashable.events ),\n\n\t\t/**\n\t\t * HTML element wrapper ID attribute\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tid: function() {\n\t\t\treturn 'llms-lesson-' + this.model.id;\n\t\t},\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'li',\n\n\t\t/**\n\t\t * Get the underscore template\n\t\t * @type {[type]}\n\t\t */\n\t\ttemplate: wp.template( 'llms-lesson-template' ),\n\n\t\t/**\n\t\t * Initialization callback func (renders the element on screen)\n\t\t * @return void\n\t\t * @since 3.14.1\n\t\t * @version 3.14.1\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.render();\n\n\t\t\tthis.listenTo( this.model, 'change', this.render );\n\n\t\t\tBackbone.pubSub.on( 'lesson-selected', this.on_select, this );\n\t\t\tBackbone.pubSub.on( 'new-lesson-added', this.on_select, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Compiles the template and renders the view\n\t\t * @return self (for chaining)\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trender: function() {\n\n\t\t\tthis.$el.html( this.template( this.model ) );\n\t\t\tthis.maybe_hide_shiftable_buttons();\n\t\t\tif ( this.model.get( '_selected' ) ) {\n\t\t\t\tthis.$el.addClass( 'selected' );\n\t\t\t} else {\n\t\t\t\tthis.$el.removeClass( 'selected' );\n\t\t\t}\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Click event for the assignment editor action icon\n\t\t * Opens sidebar to the assignment editor tab\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\topen_assignment_editor: function() {\n\n\t\t\tBackbone.pubSub.trigger( 'lesson-selected', this.model, 'assignment' );\n\t\t\tthis.model.set( '_selected', true );\n\n\t\t},\n\n\t\t/**\n\t\t * Click event for lesson settings action icon\n\t\t * Opens sidebar to the lesson editor tab\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\topen_lesson_editor: function() {\n\n\t\t\tBackbone.pubSub.trigger( 'lesson-selected', this.model, 'lesson' );\n\t\t\tthis.model.set( '_selected', true );\n\n\t\t},\n\n\t\t/**\n\t\t * Click event for the quiz editor action icon\n\t\t * Opens sidebar to the quiz editor tab\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\topen_quiz_editor: function() {\n\n\t\t\tBackbone.pubSub.trigger( 'lesson-selected', this.model, 'quiz' );\n\t\t\tthis.model.set( '_selected', true );\n\n\t\t},\n\n\t\t/**\n\t\t * When a lesson is selected mark it as selected in the hidden prop\n\t\t * Allows views to re-render and reflect current state properly\n\t\t * @param obj model lesson model that's been selected\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ton_select: function( model ) {\n\n\t\t\tif ( this.model.id !== model.id ) {\n\t\t\t\tthis.model.set( '_selected', false );\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Click event for the \"Next Section\" button\n\t\t * @param obj event js event obj\n\t\t * @return void\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\tsection_next: function( event ) {\n\t\t\tevent.preventDefault();\n\t\t\tthis._move_to_section( 'next' );\n\t\t},\n\n\t\t/**\n\t\t * Click event for the \"Previous Section\" button\n\t\t * @param obj event js event obj\n\t\t * @return void\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\tsection_prev: function( event ) {\n\t\t\tevent.preventDefault();\n\t\t\tthis._move_to_section( 'prev' );\n\t\t},\n\n\t\t/**\n\t\t * Move the lesson into a new section\n\t\t * @param string direction direction [prev|next]\n\t\t * @return void\n\t\t * @since 3.16.11\n\t\t * @version 3.16.11\n\t\t */\n\t\t_move_to_section: function( direction ) {\n\n\t\t\tvar from_coll = this.model.collection,\n\t\t\t\tto_section;\n\n\t\t\tif ( 'next' === direction ) {\n\t\t\t\tto_section = from_coll.parent.get_next();\n\t\t\t} else if ( 'prev' === direction ) {\n\t\t\t\tto_section = from_coll.parent.get_prev();\n\t\t\t}\n\n\t\t\tif ( to_section ) {\n\n\t\t\t\tfrom_coll.remove( this.model );\n\t\t\t\tto_section.add_lesson( this.model );\n\t\t\t\tto_section.set( '_expanded', true );\n\n\t\t\t}\n\n\t\t},\n\n\t}, Detachable, Editable, Shiftable, Trashable ) );\n\n} );\n\n","/**\n * Single Section View\n * @since 3.13.0\n * @version 3.16.0\n */\ndefine( 'Views/LessonList',[ 'Views/Lesson', 'Views/_Receivable' ], function( LessonView, Receivable ) {\n\n\treturn Backbone.CollectionView.extend( _.defaults( {\n\n\t\tclassName: 'llms-lessons',\n\n\t\t/**\n\t\t * Section model\n\t\t * @type {[type]}\n\t\t */\n\t\tmodelView: LessonView,\n\n\t\t/**\n\t\t * Are sections selectable?\n\t\t * @type {Bool}\n\t\t */\n\t\tselectable: false,\n\n\t\t/**\n\t\t * Are sections sortable?\n\t\t * @type {Bool}\n\t\t */\n\t\tsortable: true,\n\n\t\tsortableOptions: {\n\t\t\taxis: false,\n\t\t\tconnectWith: '.llms-lessons',\n\t\t\tcursor: 'move',\n\t\t\thandle: '.drag-lesson',\n\t\t\titems: '.llms-lesson',\n\t\t\tplaceholder: 'llms-lesson llms-sortable-placeholder',\n\t\t},\n\n\t\tsortable_start: function( collection ) {\n\t\t\t$( '.llms-lessons' ).addClass( 'dragging' );\n\t\t},\n\n\t\tsortable_stop: function( collection ) {\n\t\t\t$( '.llms-lessons' ).removeClass( 'dragging' );\n\t\t},\n\n\t\t/**\n\t\t * Overloads the function from Backbone.CollectionView core because it doesn't send stop events\n\t\t * if moving from one sortable to another... :-(\n\t\t * @param obj event js event object\n\t\t * @param obj ui jQuery UI object\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\t_sortStop : function( event, ui ) {\n\n\t\t\tvar modelBeingSorted = this.collection.get( ui.item.attr( 'data-model-cid' ) ),\n\t\t\t\tmodelViewContainerEl = this._getContainerEl(),\n\t\t\t\tnewIndex = modelViewContainerEl.children().index( ui.item );\n\n\t\t\tif ( newIndex == -1 && modelBeingSorted ) {\n\t\t\t\tthis.collection.remove( modelBeingSorted );\n\t\t\t}\n\n\t\t\tthis._reorderCollectionBasedOnHTML();\n\t\t\tthis.updateDependentControls();\n\n\t\t\tif( this._isBackboneCourierAvailable() ) {\n\t\t\t\tthis.spawn( 'sortStop', { modelBeingSorted : modelBeingSorted, newIndex : newIndex } );\n\t\t\t} else {\n\t\t\t\tthis.trigger( 'sortStop', modelBeingSorted, newIndex );\n\t\t\t}\n\n\t\t},\n\n\t}, Receivable ) );\n\n} );\n\n","/**\n * Single Section View\n * @since 3.13.0\n * @version 3.16.12\n */\ndefine( 'Views/Section',[\n\t\t'Views/LessonList',\n\t\t'Views/_Editable',\n\t\t'Views/_Shiftable',\n\t\t'Views/_Trashable'\n\t], function(\n\t\tLessonListView,\n\t\tEditable,\n\t\tShiftable,\n\t\tTrashable\n\t) {\n\n\treturn Backbone.View.extend( _.defaults( {\n\n\t\t/**\n\t\t * Get default attributes for the html wrapper element\n\t\t * @return obj\n\t\t * @since 3.13.0\n\t\t * @version 3.13.0\n\t\t */\n\t\tattributes: function() {\n\t\t\treturn {\n\t\t\t\t'data-id': this.model.id,\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Element classnames\n\t\t * @type {String}\n\t\t */\n\t\tclassName: 'llms-builder-item llms-section',\n\n\t\t/**\n\t\t * Events\n\t\t * @type {Object}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\tevents: _.defaults( {\n\n\t\t\t'click': 'select',\n\t\t\t'click .expand': 'expand',\n\t\t\t'click .collapse': 'collapse',\n\t\t\t'click .shift-up--section': 'shift_up',\n\t\t\t'click .shift-down--section': 'shift_down',\n\n\t\t\t'mouseenter .llms-lessons': 'on_mouseenter',\n\n\t\t}, Editable.events, Trashable.events ),\n\n\t\t/**\n\t\t * HTML element wrapper ID attribute\n\t\t * @return string\n\t\t * @since 3.13.0\n\t\t * @version 3.13.0\n\t\t */\n\t\tid: function() {\n\t\t\treturn 'llms-section-' + this.model.id;\n\t\t},\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'li',\n\n\t\t/**\n\t\t * Get the underscore template\n\t\t * @type {[type]}\n\t\t */\n\t\ttemplate: wp.template( 'llms-section-template' ),\n\n\t\t/**\n\t\t * Initialization callback func (renders the element on screen)\n\t\t * @return void\n\t\t * @since 3.13.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tthis.render();\n\t\t\tthis.listenTo( this.model, 'change', this.render );\n\t\t\tthis.listenTo( this.model, 'change:_expanded', this.toggle_expanded );\n\t\t\tthis.lessonListView.collection.on( 'add', this.on_lesson_add, this );\n\n\t\t\tthis.dragTimeout = null;\n\n\t\t\tBackbone.pubSub.on( 'expand-all', this.expand, this );\n\t\t\tBackbone.pubSub.on( 'collapse-all', this.collapse, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Render the section\n\t\t * Initalizes a new collection and views for all lessons in the section\n\t\t * @return void\n\t\t * @since 3.13.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trender: function() {\n\n\t\t\tthis.$el.html( this.template( this.model.toJSON() ) );\n\n\t\t\tthis.maybe_hide_shiftable_buttons();\n\n\t\t\tthis.lessonListView = new LessonListView( {\n\t\t\t\tel: this.$el.find( '.llms-lessons' ),\n\t\t\t\tcollection: this.model.get( 'lessons' ),\n\t\t\t} );\n\t\t\tthis.lessonListView.render();\n\t\t\tthis.lessonListView.on( 'sortStart', this.lessonListView.sortable_start );\n\t\t\tthis.lessonListView.on( 'sortStop', this.lessonListView.sortable_stop );\n\n\t\t\t// selection changes\n\t\t\tthis.lessonListView.on( 'selectionChanged', this.active_lesson_change, this );\n\n\t\t\tthis.maybe_hide_trash_button();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tactive_lesson_change: function( current, previous ) {\n\n\t\t\tBackbone.pubSub.trigger( 'active-lesson-change', {\n\t\t\t\tcurrent: current,\n\t\t\t\tprevious: previous,\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Collapse lessons within the section\n\t\t * @param obj event js event object\n\t\t * @param bool update if true, updates the model to reflect the new state\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tcollapse: function( event, update ) {\n\n\t\t\tif ( 'undefined' === typeof update ) {\n\t\t\t\tupdate = true;\n\t\t\t}\n\n\t\t\tif ( event ) {\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\tthis.$el.removeClass( 'expanded' ).find( '.drag-expanded' ).removeClass( 'drag-expanded' );\n\t\t\tif ( update ) {\n\t\t\t\tthis.model.set( '_expanded', false );\n\t\t\t}\n\t\t\tBackbone.pubSub.trigger( 'section-toggle', this.model );\n\n\t\t},\n\n\t\t/**\n\t\t * Expand lessons within the section\n\t\t * @param obj event js event object\n\t\t * @param bool update if true, updates the model to reflect the new state\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\texpand: function( event, update ) {\n\n\t\t\tif ( 'undefined' === typeof update ) {\n\t\t\t\tupdate = true;\n\t\t\t}\n\n\t\t\tif ( event ) {\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\tthis.$el.addClass( 'expanded' );\n\t\t\tif ( update ) {\n\t\t\t\tthis.model.set( '_expanded', true );\n\t\t\t}\n\t\t\tBackbone.pubSub.trigger( 'section-toggle', this.model );\n\n\t\t},\n\n\t\tmaybe_hide_trash_button: function() {\n\n\t\t\tvar $btn = this.$el.find( '.trash--section' );\n\n\t\t\tif ( this.model.get( 'lessons' ).isEmpty() ) {\n\n\t\t\t\t$btn.show();\n\n\t\t\t} else {\n\n\t\t\t\t$btn.hide()\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * When a lesson is added to the section trigger a collection reorder & update the lesson's id\n\t\t * @param obj model Lesson model\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ton_lesson_add: function( model ) {\n\n\t\t\tthis.lessonListView.collection.trigger( 'reorder' );\n\t\t\tmodel.set( 'parent_section', this.model.get( 'id' ) );\n\t\t\tthis.expand();\n\n\t\t},\n\n\t\ton_mouseenter: function( event ) {\n\n\n\t\t\tif ( $( event.target ).hasClass( 'dragging' ) ) {\n\n\t\t\t\t$( '.drag-expanded' ).removeClass( 'drag-expanded' );\n\t\t\t\t$( event.target ).addClass( 'drag-expanded' );\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Expand\n\t\t * @param {[type]} model [description]\n\t\t * @param {[type]} value [description]\n\t\t * @return {[type]}\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ttoggle_expanded: function( model, value ) {\n\n\t\t\tif ( value ) {\n\t\t\t\tthis.expand( null, false );\n\t\t\t} else {\n\t\t\t\tthis.collapse( null, false );\n\t\t\t}\n\n\t\t},\n\n\t}, Editable, Shiftable, Trashable ) );\n\n} );\n\n","/**\n * Single Section View\n * @since 3.13.0\n * @version 3.16.0\n */\ndefine( 'Views/SectionList',[ 'Views/Section', 'Views/_Receivable' ], function( SectionView, Receivable ) {\n\n\treturn Backbone.CollectionView.extend( _.defaults( {\n\n\t\t/**\n\t\t * Parent element\n\t\t * @type {String}\n\t\t */\n\t\tel: '#llms-sections',\n\n\t\tevents : {\n\t\t\t'mousedown > li.llms-section > .llms-builder-header .llms-headline' : '_listItem_onMousedown',\n\t\t\t// 'dblclick > li, tbody > tr > td' : '_listItem_onDoubleClick',\n\t\t\t'click' : '_listBackground_onClick',\n\t\t\t'click ul.collection-view' : '_listBackground_onClick',\n\t\t\t'keydown' : '_onKeydown'\n\t\t},\n\n\t\t/**\n\t\t * Section model\n\t\t * @type {[type]}\n\t\t */\n\t\tmodelView: SectionView,\n\n\t\t/**\n\t\t * Enable keyboard events\n\t\t * @type {Bool}\n\t\t */\n\t\tprocessKeyEvents: false,\n\n\t\t/**\n\t\t * Are sections selectable?\n\t\t * @type {Bool}\n\t\t */\n\t\tselectable: true,\n\n\t\t/**\n\t\t * Are sections sortable?\n\t\t * @type {Bool}\n\t\t */\n\t\tsortable: true,\n\n\t\tsortableOptions: {\n\t\t\taxis: false,\n\t\t\tcursor: 'move',\n\t\t\thandle: '.drag-section',\n\t\t\titems: '.llms-section',\n\t\t\tplaceholder: 'llms-section llms-sortable-placeholder',\n\t\t},\n\n\t\tsortable_start: function( collection ) {\n\t\t\tthis.$el.addClass( 'dragging' );\n\t\t},\n\n\t\tsortable_stop: function( collection ) {\n\t\t\tthis.$el.removeClass( 'dragging' );\n\t\t},\n\n\t}, Receivable ) );\n\n} );\n\n","/**\n * Single Course View\n * @since 3.13.0\n * @version 3.16.0\n */\ndefine( 'Views/Course',[ 'Views/SectionList', 'Views/_Editable' ], function( SectionListView, Editable ) {\n\n\treturn Backbone.View.extend( _.defaults( {\n\n\t\t/**\n\t\t * Get default attributes for the html wrapper element\n\t\t * @return obj\n\t\t * @since 3.13.0\n\t\t * @version 3.13.0\n\t\t */\n\t\tattributes: function() {\n\t\t\treturn {\n\t\t\t\t'data-id': this.model.id,\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * HTML element selector\n\t\t * @type {String}\n\t\t */\n\t\tel: '#llms-builder-main',\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'div',\n\n\t\t/**\n\t\t * Get the underscore template\n\t\t * @type {[type]}\n\t\t */\n\t\ttemplate: wp.template( 'llms-course-template' ),\n\n\t\t/**\n\t\t * Initialization callback func (renders the element on screen)\n\t\t * @return void\n\t\t * @since 3.13.0\n\t\t * @version 3.13.0\n\t\t */\n\t\tinitialize: function() {\n\n\t\t\tvar self = this;\n\n\t\t\t// this.listenTo( this.model, 'sync', this.render );\n\t\t\tthis.render();\n\n\t\t\tthis.sectionListView = new SectionListView( {\n\t\t\t\tcollection: this.model.get( 'sections' ),\n\t\t\t} );\n\t\t\tthis.sectionListView.render();\n\t\t\t// drag and drop start\n\t\t\tthis.sectionListView.on( 'sortStart', this.sectionListView.sortable_start );\n\t\t\t// drag and drop stop\n\t\t\tthis.sectionListView.on( 'sortStop', this.sectionListView.sortable_stop );\n\t\t\t// selection changes\n\t\t\tthis.sectionListView.on( 'selectionChanged', this.active_section_change );\n\t\t\t// \"select\" a section when it's added to the course\n\t\t\tthis.listenTo( this.model.get( 'sections'), 'add', this.on_section_add );\n\n\t\t\tBackbone.pubSub.on( 'section-toggle', this.on_section_toggle, this );\n\n\t\t\tBackbone.pubSub.on( 'expand-section', this.expand_section, this );\n\n\t\t\tBackbone.pubSub.on( 'lesson-selected', this.active_lesson_change, this );\n\n\t\t},\n\n\t\t/**\n\t\t * Compiles the template and renders the view\n\t\t * @return self (for chaining)\n\t\t * @since 3.13.0\n\t\t * @version 3.13.0\n\t\t */\n\t\trender: function() {\n\t\t\tthis.$el.html( this.template( this.model ) );\n\t\t\treturn this;\n\t\t},\n\n\t\tactive_lesson_change: function( model ) {\n\n\t\t\t// set parent section to be active\n\t\t\tvar section = this.model.get( 'sections' ).get( model.get( 'parent_section' ) );\n\t\t\tthis.sectionListView.setSelectedModel( section );\n\n\t\t},\n\n\t\t/**\n\t\t * When a section \"selection\" changes in the list\n\t\t * Update each section model so we can figure out which one is selected from other views\n\t\t * @param array current array of selected models\n\t\t * @param array previous array of previously selected models\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tactive_section_change: function( current, previous ) {\n\n\t\t\t_.each( current, function( model ) {\n\t\t\t\tmodel.set( '_selected', true );\n\t\t\t} );\n\n\t\t\t_.each( previous, function( model ) {\n\t\t\t\tmodel.set( '_selected', false );\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * \"Selects\" the new section when it's added to the course\n\t\t * @param obj model Section model that's just been added\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ton_section_add: function( model ) {\n\n\t\t\tthis.sectionListView.setSelectedModel( model );\n\n\t\t},\n\n\t\t/**\n\t\t * When expanding/collapsing sections\n\t\t * if collapsing, unselect, if expanding, select\n\t\t * @param obj model toggled section\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\ton_section_toggle: function( model ) {\n\n\t\t\tvar selected = model.get( '_expanded' ) ? [ model ] : [];\n\t\t\tthis.sectionListView.setSelectedModels( selected );\n\n\t\t}\n\n\t}, Editable ) );\n\n} );\n\n","/**\n * Model settings fields view\n * @since 3.17.0\n * @version 3.17.7\n */\ndefine( 'Views/SettingsFields',[], function() {\n\n\treturn Backbone.View.extend( _.defaults( {\n\n\t\t/**\n\t\t * DOM events\n\t\t * @type {Object}\n\t\t */\n\t\tevents: {\n\t\t\t'click .llms-settings-group-toggle': 'toggle_group',\n\t\t},\n\n\t\t/**\n\t\t * Processed fields data\n\t\t * Allows access by ID without traversing the schema\n\t\t * @type {Object}\n\t\t */\n\t\tfields: {},\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'div',\n\n\t\t/**\n\t\t * Get the underscore template\n\t\t * @type {[type]}\n\t\t */\n\t\ttemplate: wp.template( 'llms-settings-fields-template' ),\n\n\t\t/**\n\t\t * Initialization callback func (renders the element on screen)\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\t// initialize: function() {},\n\n\t\t/**\n\t\t * Retrieve an array of all editor fields in all groups\n\t\t * @return array\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\tget_editor_fields: function() {\n\t\t\treturn _.filter( this.fields, function( field ) {\n\t\t\t\treturn this.is_editor_field( field.type );\n\t\t\t}, this );\n\t\t},\n\n\t\t/**\n\t\t * Get settings group data from a model\n\t\t * @return {[type]}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tget_groups: function() {\n\n\t\t\treturn this.model.get_settings_fields();\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if a settings group is hidden in localStorage\n\t\t * @param string group_id id of the group\n\t\t * @return {Boolean}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tis_group_hidden: function( group_id ) {\n\n\t\t\tvar id = 'llms-' + this.model.get( 'type' ) + '-settings-group--' + group_id;\n\n\t\t\tif ( 'undefined' !== window.localStorage ) {\n\t\t\t\treturn ( 'hidden' === window.localStorage.getItem( id ) );\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\t/**\n\t\t * Get the switch attribute for a field with switches\n\t\t * @param obj field field data obj\n\t\t * @return string\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tget_switch_attribute: function( field ) {\n\n\t\t\treturn field.switch_attribute ? field.switch_attribute : field.attribute;\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if a field has a switch\n\t\t * @param string type field type string\n\t\t * @return {Boolean}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\thas_switch: function( type ) {\n\t\t\treturn ( -1 !== type.indexOf( 'switch' ) );\n\t\t},\n\n\t\t/**\n\t\t * Determine if a field is a default (text) field\n\t\t * @param string type field type string\n\t\t * @return {Boolean}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tis_default_field: function( type ) {\n\n\t\t\tvar types = [ 'audio_embed', 'datepicker', 'number', 'text', 'video_embed' ];\n\t\t\treturn ( -1 !== types.indexOf( type.replace( 'switch-', '' ) ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if a field is a WYSIWYG editor field\n\t\t * @param string type field type string\n\t\t * @return {Boolean}\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\tis_editor_field: function( type ) {\n\n\t\t\tvar types = [ 'editor', 'switch-editor' ];\n\t\t\treturn ( -1 !== types.indexOf( type.replace( 'switch-', '' ) ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if a switch is enabled for a field\n\t\t * @param obj field field data object\n\t\t * @return {Boolean}\n\t\t * @since 3.17.0\n\t\t * @version 3.17.6\n\t\t */\n\t\tis_switch_condition_met: function( field ) {\n\n\t\t\treturn ( field.switch_on === this.model.get( field.switch_attribute ) );\n\n\t\t},\n\n\t\t/**\n\t\t * Compiles the template and renders the view\n\t\t * @return self (for chaining)\n\t\t * @since 3.17.0\n\t\t * @version 3.17.1\n\t\t */\n\t\trender: function() {\n\n\t\t\tthis.$el.html( this.template( this ) );\n\n\t\t\t// if editors exist, render them\n\t\t\t_.each( this.get_editor_fields(), function( field ) {\n\t\t\t\tthis.render_editor( field );\n\t\t\t}, this );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Renders an editor field\n\t\t * @param obj field field data object\n\t\t * @return void\n\t\t * @since 3.17.1\n\t\t * @version 3.17.1\n\t\t */\n\t\trender_editor: function( field ) {\n\n\t\t\tvar self = this;\n\n\t\t\twp.editor.remove( field.id );\n\t\t\tfield.settings.tinymce.setup = function( editor ) {\n\n\t\t\t\tvar $ed = $( '#' + editor.id ),\n\t\t\t\t\t$parent = $ed.closest( '.llms-editable-editor' ),\n\t\t\t\t\t$label = $parent.find( '.llms-label' ),\n\t\t\t\t\tprop = $ed.attr( 'data-attribute' )\n\n\t\t\t\tif ( $label.length ) {\n\t\t\t\t\t$label.prependTo( $parent.find( '.wp-editor-tools' ) );\n\t\t\t\t}\n\n\t\t\t\t// save changes to the model via Visual ed\n\t\t\t\teditor.on( 'change', function( event ) {\n\t\t\t\t\tself.model.set( prop, wp.editor.getContent( editor.id ) );\n\t\t\t\t} );\n\n\t\t\t\t// save changes via Text ed\n\t\t\t\t$ed.on( 'input', function( event ) {\n\t\t\t\t\tself.model.set( prop, $ed.val() );\n\t\t\t\t} );\n\n\t\t\t\t// trigger an input on the Text ed when quicktags buttons are clicked\n\t\t\t\t$parent.on( 'click', '.quicktags-toolbar .ed_button', function() {\n\t\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t\t$ed.trigger( 'input' );\n\t\t\t\t\t}, 10 );\n\t\t\t\t} );\n\t\t\t};\n\n\t\t\twp.editor.initialize( field.id, field.settings );\n\n\t\t},\n\n\t\t/**\n\t\t * Get the HTML for a select field\n\t\t * @param obj options flat or multi-dimensional options object\n\t\t * @param string attribute name of the select field's attribute\n\t\t * @return string\n\t\t * @since 3.17.0\n\t\t * @version 3.17.2\n\t\t */\n\t\trender_select_options: function( options, attribute ) {\n\n\t\t\tvar html = '',\n\t\t\t\tselected = this.model.get( attribute );\n\n\t\t\tfunction option_html( label, val ) {\n\n\t\t\t\treturn '';\n\n\t\t\t}\n\n\t\t\t_.each( options, function( option, index ) {\n\n\t\t\t\t// this will be an key:val object\n\t\t\t\tif ( 'string' === typeof option ) {\n\t\t\t\t\thtml += option_html( option, index );\n\t\t\t\t// either option group or array of key,val objects\n\t\t\t\t} else if ( 'object' === typeof option ) {\n\t\t\t\t\t// option group\n\t\t\t\t\tif ( option.label && option.options ) {\n\t\t\t\t\t\thtml += '';\n\t\t\t\t\t\thtml += this.render_select_options( option.options, attribute );\n\t\t\t\t\t} else {\n\t\t\t\t\t\thtml += option_html( option.val, option.key );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}, this );\n\n\t\t\treturn html;\n\n\t\t},\n\n\t\t/**\n\t\t * Setup and fill fields with default data based on field type\n\t\t * @param obj orig_field original field as defined in the settings\n\t\t * @param int field_index index of the field in the current row\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.7\n\t\t */\n\t\tsetup_field: function( orig_field, field_index ) {\n\n\t\t\tvar defaults = {\n\t\t\t\tclasses: [],\n\t\t\t\tid: _.uniqueId( orig_field.attribute + '_' ),\n\t\t\t\tinput_type: 'text',\n\t\t\t\tlabel: '',\n\t\t\t\toptions: {},\n\t\t\t\tplaceholder: '',\n\t\t\t\ttip: '',\n\t\t\t\ttip_position: 'top-right',\n\t\t\t\tsettings: {},\n\t\t\t};\n\n\t\t\t// check the field condition if set\n\t\t\tif ( orig_field.condition && false === _.bind( orig_field.condition, this.model )() ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tswitch ( orig_field.type ) {\n\n\t\t\t\tcase 'audio_embed':\n\t\t\t\t\tdefaults.classes.push( 'llms-editable-audio' );\n\t\t\t\t\tdefaults.placeholder = 'https://';\n\t\t\t\t\tdefaults.tip = LLMS.l10n.translate( 'Use SoundCloud or Spotify audio URLS.' );\n\t\t\t\t\tdefaults.input_type = 'url';\n\t\t\t\tbreak;\n\n\t\t\t\tcase 'datepicker':\n\t\t\t\t\tdefaults.classes.push( 'llms-editable-date' );\n\t\t\t\tbreak;\n\n\t\t\t\tcase 'editor':\n\t\t\t\tcase 'switch-editor':\n\t\t\t\t\tvar orig_settings = orig_field.settings || {};\n\t\t\t\t\tdefaults.settings = $.extend( true, wp.editor.getDefaultSettings(), {\n\t\t\t\t\t\tmediaButtons: true,\n\t\t\t\t\t\ttinymce: {\n\t\t\t\t\t\t\ttoolbar1: 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_adv',\n\t\t\t\t\t\t\ttoolbar2: 'formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',\n\t\t\t\t\t\t}\n\t\t\t\t\t}, orig_settings );\n\t\t\t\tbreak;\n\n\t\t\t\tcase 'number':\n\t\t\t\t\tdefaults.input_type = 'number';\n\t\t\t\tbreak;\n\n\t\t\t\tcase 'permalink':\n\t\t\t\t\tdefaults.label = LLMS.l10n.translate( 'Permalink' );\n\t\t\t\tbreak;\n\n\t\t\t\tcase 'video_embed':\n\t\t\t\t\tdefaults.classes.push( 'llms-editable-video' );\n\t\t\t\t\tdefaults.placeholder = 'https://';\n\t\t\t\t\tdefaults.tip = LLMS.l10n.translate( 'Use YouTube, Vimeo, or Wistia video URLS.' );\n\t\t\t\t\tdefaults.input_type = 'url';\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( this.has_switch( orig_field.type ) ) {\n\t\t\t\tdefaults.switch_on = 'yes';\n\t\t\t\tdefaults.switch_off = 'no';\n\t\t\t}\n\n\t\t\tvar field = _.defaults( _.deepClone( orig_field ), defaults );\n\n\t\t\t// if options is a function run it\n\t\t\tif ( _.isFunction( field.options ) ) {\n\t\t\t\tfield.options = _.bind( field.options, this.model )();\n\t\t\t}\n\n\t\t\t// if it's a radio field options values can be submitted as images\n\t\t\t// this will transform those images into html\n\t\t\tif ( -1 !== [ 'radio', 'switch-radio' ].indexOf( orig_field.type ) ) {\n\n\t\t\t\tvar has_images = false;\n\t\t\t\t_.each( orig_field.options, function( val, key ) {\n\t\t\t\t\tif ( -1 !== val.indexOf( '.png' ) || -1 !== val.indexOf( '.jpg' ) ) {\n\t\t\t\t\t\tfield.options[key] = '';\n\t\t\t\t\t\thas_images = true;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tif ( has_images ) {\n\t\t\t\t\tfield.classes.push( 'has-images' );\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add tooltip position classes\n\t\t\tif ( field.tip ) {\n\t\t\t\tfield.classes.push( 'tip--' + field.tip_position );\n\t\t\t}\n\n\t\t\t// transform classes array to a css class string\n\t\t\tif ( field.classes.length ) {\n\t\t\t\tfield.classes = ' ' + field.classes.join( ' ' );\n\t\t\t}\n\n\t\t\tthis.fields[ field.id ] = field;\n\n\t\t\treturn field;\n\n\t\t},\n\n\t\t/**\n\t\t * Determine if toggling a switch select should rerender the view\n\t\t * @param string field_type field type string\n\t\t * @return boolean\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tshould_rerender_on_toggle: function( field_type ) {\n\n\t\t\treturn ( -1 !== field_type.indexOf( 'switch-' ) ) ? 'yes' : 'no';\n\n\t\t},\n\n\t\t/**\n\t\t * Click event for toggling visibility of settings groups\n\t\t * If localStorage is available, persist state\n\t\t * @param obj event js event object\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\ttoggle_group: function( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t\tvar $el = $( event.currentTarget ),\n\t\t\t\t$group = $el.closest( '.llms-model-settings' );\n\n\t\t\t$group.toggleClass( 'hidden' );\n\n\t\t\tif ( 'undefined' !== window.localStorage ) {\n\n\t\t\t\tvar id = $group.attr( 'id' );\n\t\t\t\tif ( $group.hasClass( 'hidden' ) ) {\n\t\t\t\t\twindow.localStorage.setItem( id, 'hidden' );\n\t\t\t\t} else {\n\t\t\t\t\twindow.localStorage.removeItem( id );\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t} ) );\n\n} );\n\n","/**\n * Lesson Editor (Sidebar) View\n * @since 3.17.0\n * @version 3.17.0\n */\ndefine( 'Views/LessonEditor',[\n\t\t'Views/_Detachable',\n\t\t'Views/_Editable',\n\t\t'Views/_Trashable',\n\t\t'Views/_Subview',\n\t\t'Views/SettingsFields'\n\t], function(\n\t\tDetachable,\n\t\tEditable,\n\t\tTrashable,\n\t\tSubview,\n\t\tSettingsFields\n\t) {\n\n\treturn Backbone.View.extend( _.defaults( {\n\n\t\t/**\n\t\t * Current view state\n\t\t * @type {String}\n\t\t */\n\t\tstate: 'default',\n\n\t\t/**\n\t\t * Current Subviews\n\t\t * @type {Object}\n\t\t */\n\t\tviews: {\n\t\t\tsettings: {\n\t\t\t\tclass: SettingsFields,\n\t\t\t\tinstance: null,\n\t\t\t\tstate: 'default',\n\t\t\t},\n\t\t},\n\n\t\tel: '#llms-editor-lesson',\n\n\t\t/**\n\t\t * Events\n\t\t * @type {Object}\n\t\t */\n\t\tevents: _.defaults( {}, Detachable.events, Editable.events, Trashable.events ),\n\n\t\t/**\n\t\t * Template function\n\t\t * @type {[type]}\n\t\t */\n\t\ttemplate: wp.template( 'llms-lesson-settings-template' ),\n\n\t\t/**\n\t\t * Init\n\t\t * @param obj data parent template data\n\t\t * @return void\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tinitialize: function( data ) {\n\n\t\t\tthis.model = data.lesson;\n\n\t\t\tvar change_events = [\n\t\t\t\t'change:date_available',\n\t\t\t\t'change:drip_method',\n\t\t\t\t'change:time_available',\n\t\t\t];\n\t\t\t_.each( change_events, function( event ) {\n\t\t\t\tthis.listenTo( this.model, event, this.render );\n\t\t\t}, this );\n\n\t\t\t// when the \"has_prerequisite\" attr is toggled ON\n\t\t\t// trigger the prereq select object to set the default (first available) prereq for the lesson\n\t\t\tthis.listenTo( this.model, 'change:has_prerequisite', function( lesson, val ) {\n\t\t\t\tif ( 'yes' === val ) {\n\t\t\t\t\tthis.$el.find( 'select[name=\"prerequisite\"]' ).trigger( 'change' );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * Render the view\n\t\t * @return obj\n\t\t * @since 3.17.0\n\t\t * @version 3.17.0\n\t\t */\n\t\trender: function() {\n\n\t\t\tthis.$el.html( this.template( this.model ) );\n\n\t\t\tthis.remove_subview( 'settings' );\n\n\t\t\tthis.render_subview( 'settings', {\n\t\t\t\tel: '#llms-lesson-settings-fields',\n\t\t\t\tmodel: this.model,\n\t\t\t} );\n\n\t\t\tthis.init_datepickers();\n\t\t\tthis.init_selects();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t}, Detachable, Editable, Trashable, Subview, SettingsFields ) );\n\n} );\n\n","/**\n * Single Quiz View\n * @since 3.16.0\n * @version 3.16.0\n */\ndefine( 'Views/Popover',[], function() {\n\n\treturn Backbone.View.extend( {\n\n\t\tdefaults: {\n\t\t\tplacement: 'auto',\n\t\t\t// container: document.body,\n\t\t\twidth: 'auto',\n\t\t\ttrigger: 'manual',\n\t\t\tstyle: 'light',\n\t\t\tanimation: 'pop',\n\t\t\ttitle: '',\n\t\t\tcontent: '',\n\t\t\tcloseable: false,\n\t\t\tbackdrop: false,\n\t\t\tonShow: function( $el ) {},\n\t\t\tonHide: function( $el ) {},\n\t\t},\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'div',\n\n\t\t/**\n\t\t * Initialization callback func (renders the element on screen)\n\t\t * @return void\n\t\t * @since 3.14.1\n\t\t * @version 3.14.1\n\t\t */\n\t\tinitialize: function( data ) {\n\n\t\t\tif ( this.$el.length ) {\n\t\t\t\tthis.defaults.container = this.$el.parent();\n\t\t\t}\n\n\t\t\tthis.args = _.defaults( data.args, this.defaults );\n\t\t\tthis.render();\n\n\t\t},\n\n\t\t/**\n\t\t * Compiles the template and renders the view\n\t\t * @return self (for chaining)\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\trender: function() {\n\n\t\t\tthis.$el.webuiPopover( this.args );\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Hide the popover\n\t\t * @return self (for chaining)\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\thide: function() {\n\n\t\t\tthis.$el.webuiPopover( 'hide' );\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Show the popover\n\t\t * @return self (for chaining)\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\tshow: function() {\n\n\t\t\tthis.$el.webuiPopover( 'show' );\n\t\t\treturn this;\n\n\t\t},\n\n\t} );\n\n} );\n\n","/**\n * Post Popover Serach content View\n * @since 3.16.0\n * @version 3.17.0\n */\ndefine( 'Views/PostSearch',[], function() {\n\n\treturn Backbone.View.extend( {\n\n\t\t/**\n\t\t * DOM Events\n\t\t * @type obj\n\t\t * @since 3.16.0\n\t\t * @version 3.16.0\n\t\t */\n\t\tevents: {\n\t\t\t'select2:select': 'add_post',\n\t\t},\n\n\t\t/**\n\t\t * Wrapper Tag name\n\t\t * @type {String}\n\t\t */\n\t\ttagName: 'select',\n\n\t\t/**\n\t\t * Initializer\n\t\t * @param obj data customize the search box with data\n\t\t * @return void\n\t\t * @since 3.16.12\n\t\t * @version 3.16.12\n\t\t */\n\t\tinitialize: function( data ) {\n\n\t\t\tthis.post_type = data.post_type;\n\t\t\tthis.searching_message = data.searching_message || LLMS.l10n.translate( 'Searching...' );\n\n\t\t},\n\n\t\t/**\n\t\t * Select event, adds the existing lesson to the course\n\t\t * @param obj event select2:select event object\n\t\t * @since 3.16.0\n\t\t * @version 3.17.0\n\t\t */\n\t\tadd_post: function( event ) {\n\n\t\t\tvar type = this.$el.attr( 'data-post-type' );\n\n\t\t\tBackbone.pubSub.trigger( type.replace( 'llms_', '' ) + '-search-select', event.params.data, event );\n\t\t\tthis.$el.val( null ).trigger( 'change' );\n\n\t\t},\n\n\t\t/**\n\t\t * Render the section\n\t\t * Initalizes a new collection and views for all lessons in the section\n\t\t * @return void\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\trender: function() {\n\t\t\tvar self = this;\n\t\t\tsetTimeout( function () {\n\t\t\t\tself.$el.llmsSelect2( {\n\t\t\t\t\tajax: {\n\t\t\t\t\t\tdataType: 'JSON',\n\t\t\t\t\t\tdelay: 250,\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\turl: window.ajaxurl,\n\t\t\t\t\t\tdata: function( params ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\taction: 'llms_builder',\n\t\t\t\t\t\t\t\taction_type: 'search',\n\t\t\t\t\t\t\t\tcourse_id: window.llms_builder.course.id,\n\t\t\t\t\t\t\t\tpost_type: self.post_type,\n\t\t\t\t\t\t\t\tterm: params.term,\n\t\t\t\t\t\t\t\tpage: params.page,\n\t\t\t\t\t\t\t\t_ajax_nonce: wp_ajax_data.nonce,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// error: function( xhr, status, error ) {\n\t\t\t\t\t\t// \tconsole.log( status, error );\n\t\t\t\t\t\t// },\n\t\t\t\t\t},\n\t\t\t\t\tdropdownParent: $( '.wrap.lifterlms.llms-builder' ),\n\t\t\t\t\t// don't escape html from render_result\n\t\t\t\t\tescapeMarkup: function( markup ) {\n\t\t\t\t\t\treturn markup;\n\t\t\t\t\t},\n\t\t\t\t\tplaceholder: self.searching_message,\n\t\t\t\t\ttemplateResult: self.render_result,\n\t\t\t\t\twidth: '100%',\n\t\t\t\t} );\n\t\t\t\tself.$el.attr( 'data-post-type', self.post_type );\n\t\t\t}, 0 );\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Render a nicer UI for each search result in the in the Select2 search results\n\t\t * @param object res result data\n\t\t * @return string\n\t\t * @since 3.16.0\n\t\t * @version 3.16.12\n\t\t */\n\t\trender_result: function( res ) {\n\n\t\t\tvar $html = $( '
    ' );\n\n\t\t\tif ( res.loading ) {\n\t\t\t\treturn $html.append( res.text );\n\t\t\t}\n\n\t\t\tvar $side = $( '