{"version":3,"file":"application-BLa-gE34.js","sources":["../../../client/app/bundles/Teacher/components/general_components/text_input.jsx","../../../client/app/bundles/Teacher/components/modules/componentGenerators/text_input_generator.jsx","../../../client/app/bundles/Teacher/components/modules/fnl.jsx","../../../client/app/bundles/Teacher/components/modules/indicator_generator.jsx","../../../client/app/bundles/Teacher/components/modules/server/data/file_processor.jsx","../../../client/app/bundles/Teacher/components/modules/server/data/normalizer.jsx","../../../client/app/bundles/Teacher/components/modules/server/data/data.jsx","../../../client/app/bundles/Teacher/components/modules/server/params.jsx","../../../client/app/bundles/Teacher/components/modules/server/saver.jsx","../../../client/app/bundles/Teacher/components/modules/server/server.jsx","../../../client/app/bundles/Teacher/components/activity_classifications/activity_classification.jsx","../../../client/app/bundles/Teacher/components/cms/cms_index_table/cms_index_table_row.jsx","../../../client/app/bundles/Teacher/components/cms/cms_index_table/cms_index_table.jsx","../../../client/app/bundles/Teacher/components/general_components/dropdown_selectors/item_dropdown.jsx","../../../client/app/bundles/Teacher/containers/Cms.jsx","../../../client/app/bundles/Teacher/containers/ActivityClassifications.jsx","../../../client/app/bundles/Teacher/startup/ActivityClassificationsAppClient.jsx","../../../client/app/bundles/Teacher/startup/AdminAccessAppClient.jsx","../../../client/app/bundles/Teacher/components/modules/nested_resource.jsx","../../../client/app/bundles/Teacher/components/cms/resources/newNestedResource.jsx","../../../client/app/bundles/Teacher/components/cms/resources/nestedResource.jsx","../../../client/app/bundles/Teacher/components/cms/resources/resource.jsx","../../../client/app/bundles/Teacher/containers/AdminAccounts.jsx","../../../client/app/bundles/Teacher/startup/AdminAccountsAppClient.jsx","../../../client/app/bundles/Teacher/containers/AdminsEditor.jsx","../../../client/app/bundles/Teacher/startup/AdminsEditorAppClient.jsx","../../../client/app/bundles/Teacher/components/blog_posts/header_section.jsx","../../../client/node_modules/commonmark/lib/node.js","../../../client/node_modules/mdurl/encode.js","../../../client/node_modules/mdurl/decode.js","../../../client/node_modules/entities/lib/encode.js","../../../client/node_modules/entities/lib/decode.js","../../../client/node_modules/entities/index.js","../../../client/node_modules/commonmark/lib/common.js","../../../client/node_modules/commonmark/lib/normalize-reference.js","../../../client/node_modules/commonmark/lib/from-code-point.js","../../../client/node_modules/string.prototype.repeat/repeat.js","../../../client/node_modules/commonmark/lib/inlines.js","../../../client/node_modules/commonmark/lib/blocks.js","../../../client/node_modules/commonmark/lib/html.js","../../../client/node_modules/commonmark/lib/xml.js","../../../client/node_modules/commonmark/lib/index.js","../../../client/node_modules/lodash.assign/index.js","../../../client/node_modules/lodash.isplainobject/index.js","../../../client/node_modules/xss-filters/src/xss-filters.js","../../../client/node_modules/pascalcase/index.js","../../../client/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js","../../../client/node_modules/react-markdown/src/react-markdown.js","../../../client/app/bundles/Teacher/components/shared/preview_card.jsx","../../../client/app/bundles/Teacher/startup/AnnouncementsAppClient.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/admin.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/ap.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/lessons.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/preap.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/premium.jsx","../../../client/app/bundles/Teacher/components/modules/questionsAndAnswers/springboard.jsx","../../../client/app/bundles/Teacher/components/shared/QuestionAndAnswer.jsx","../../../client/app/bundles/Teacher/components/shared/scroll_to_top.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/create_unit/select_activities_container.jsx","../../../client/node_modules/toggle-selection/index.js","../../../client/node_modules/copy-to-clipboard/index.js","../../../client/node_modules/react-copy-to-clipboard/lib/Component.js","../../../client/node_modules/react-copy-to-clipboard/lib/index.js","../../../client/app/bundles/Teacher/components/assignment_flow/create_unit/stage2/name_the_unit.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/create_unit/stage2/review_activities.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/create_unit/stage2/Stage2.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/create_unit/create_unit.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_profile/unit_template_profile_share_buttons.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_template_assigned.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_profile/unit_template_profile_standards.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/category_label.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_first_row.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_second_row.jsx","../../../client/app/bundles/Teacher/components/modules/string.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_mini.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_template_minis.jsx","../../../client/app/bundles/Teacher/components/modules/get_parameter_by_name.js","../../../client/app/bundles/Teacher/components/modules/setter.jsx","../../../client/app/bundles/Teacher/components/modules/updater.jsx","../../../client/app/bundles/Teacher/components/modules/windowPosition.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/unit_templates_manager/unit_templates_manager.jsx","../../../client/app/bundles/Teacher/containers/AssignActivitiesContainer.jsx","../../../client/app/bundles/Teacher/containers/AssignActivitiesRouter.jsx","../../../client/app/bundles/Teacher/startup/AssignActivitiesAppClient.jsx","../../../client/app/bundles/Teacher/components/blog_posts/blog_post_content.jsx","../../../client/app/bundles/Teacher/components/blog_posts/blog_post.jsx","../../../client/node_modules/pluralize/pluralize.js","../../../client/app/bundles/Teacher/components/blog_posts/topic_section.jsx","../../../client/app/bundles/Teacher/components/blog_posts/blog_post_index.jsx","../../../client/app/bundles/Teacher/components/cms/blog_posts/create_or_edit_blog_post.jsx","../../../client/app/bundles/Teacher/containers/BlogPosts.jsx","../../../client/app/bundles/Teacher/startup/BlogPostsAppClient.jsx","../../../client/app/bundles/Teacher/containers/UnitTemplateCategories.jsx","../../../client/app/bundles/Teacher/containers/CmsActivitiesRouter.jsx","../../../client/app/bundles/Teacher/startup/CmsActivitiesAppClient.jsx","../../../client/app/bundles/Teacher/startup/CmsSchoolIndexAppClient.jsx","../../../client/app/bundles/Teacher/startup/CmsUserIndexAppClient.jsx","../../../client/node_modules/react-confetti/dist/react-confetti.min.js","../../../client/node_modules/@gilbarbara/deep-equal/esm/helpers.js","../../../client/node_modules/@gilbarbara/deep-equal/esm/index.js","../../../client/node_modules/is-lite/esm/index.js","../../../client/node_modules/tree-changes/esm/helpers.js","../../../client/node_modules/tree-changes/esm/index.js","../../../client/node_modules/exenv/index.js","../../../client/node_modules/scroll/index.js","../../../client/node_modules/scrollparent/scrollparent.js","../../../client/node_modules/react-joyride/node_modules/deepmerge/dist/cjs.js","../../../client/node_modules/react-proptype-conditional-require/dist/isRequiredIf.js","../../../client/node_modules/popper.js/dist/esm/popper.js","../../../client/node_modules/react-floater/node_modules/deepmerge/dist/cjs.js","../../../client/node_modules/react-floater/es/index.js","../../../client/node_modules/react-joyride/es/index.js","../../../client/app/bundles/Teacher/startup/DashboardAppClient.jsx","../../../client/app/bundles/Teacher/startup/DemoAccountBannerAppClient.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/add_classroom_activity_row.jsx","../../../client/app/bundles/Teacher/components/modules/activity_from_classification_id.js","../../../client/app/modules/activity_classifications.js","../../../client/app/bundles/Teacher/components/shared/preview_or_launch_modal.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/classroom_activity.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/activities_unit.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/activities_units.jsx","../../../client/app/bundles/Teacher/components/shared/EmptyProgressReport.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/activity_packs.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/diagnostics/empty_diagnostic_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/missed_lesson_row.jsx","../../../client/app/bundles/Teacher/components/modules/grade_color.js","../../../client/app/bundles/Teacher/components/modules/score_color.js","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/overview_boxes.jsx","../../../client/node_modules/create-react-class/factory.js","../../../client/node_modules/create-react-class/index.js","../../../client/app/bundles/Teacher/components/general_components/table/sortable_table/sortable_th.jsx","../../../client/app/bundles/Teacher/components/general_components/table/sortable_table/sortable_tr.jsx","../../../client/app/bundles/Teacher/components/general_components/table/sortable_table/sortable_table.jsx","../../../client/app/bundles/Teacher/components/general_components/table/sortable_table/table_filter_mixin.js","../../../client/node_modules/underscore.string/naturalCmp.js","../../../client/app/bundles/Teacher/components/general_components/table/sortable_table/table_sorting_mixin.js","../../../client/app/bundles/Teacher/components/progress_reports/constants.js","../../../client/app/bundles/Teacher/components/progress_reports/export_csv.jsx","../../../client/app/bundles/Teacher/components/progress_reports/faq_link.jsx","../../../client/app/bundles/Teacher/components/progress_reports/progress_report_filters.jsx","../../../client/app/bundles/Teacher/components/progress_reports/progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/class_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/nav_bar.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/question_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/index.jsx","../../../client/app/bundles/Teacher/components/progress_reports/diagnostic_reports/not_completed.jsx","../../../client/app/bundles/Teacher/containers/DiagnosticReports.jsx","../../../client/app/bundles/Teacher/startup/DiagnosticReportsAppClient.jsx","../../../client/app/bundles/Teacher/components/accounts/reset_password/forgot_password.jsx","../../../client/app/bundles/Teacher/startup/ForgotPasswordAppClient.jsx","../../../client/app/bundles/Teacher/containers/EditUnitActivitiesContainer.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/choose_classroom_lesson.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/unit.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/units.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/classroom_lessons.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/manage_units/manage_units.jsx","../../../client/app/bundles/Teacher/components/assignment_flow/my_activities_tabs.jsx","../../../client/app/bundles/Teacher/containers/LessonPlannerContainer.jsx","../../../client/app/bundles/Teacher/containers/LessonPlannerRouter.jsx","../../../client/app/bundles/Teacher/startup/LessonPlannerAppClient.jsx","../../../client/node_modules/crypt/crypt.js","../../../client/node_modules/charenc/charenc.js","../../../client/node_modules/is-buffer/index.js","../../../client/node_modules/md5/md5.js","../../../client/app/actions/district_activity_scores.js","../../../client/app/bundles/Teacher/components/progress_reports/empty_state_for_report.jsx","../../../client/app/bundles/PremiumHub/containers/DistrictActivityScores.jsx","../../../client/app/actions/district_concept_reports.js","../../../client/app/bundles/PremiumHub/components/concept_reports_table.jsx","../../../client/app/bundles/PremiumHub/containers/DistrictConceptReports.jsx","../../../client/app/actions/district_standards_reports.js","../../../client/app/bundles/PremiumHub/containers/DistrictStandardsReports.jsx","../../../client/app/bundles/Teacher/components/subscriptions/constants.jsx","../../../client/app/bundles/Teacher/components/subscriptions/PremiumConfirmationModal.jsx","../../../client/app/bundles/Teacher/components/subscriptions/SubscriptionStatus.jsx","../../../client/app/bundles/Teacher/components/subscriptions/current_subscription_title_and_content.jsx","../../../client/app/bundles/Teacher/components/subscriptions/current_subscription.jsx","../../../client/app/bundles/Teacher/components/subscriptions/subscription_history.jsx","../../../client/app/bundles/Teacher/components/progress_reports/student_overview_table.jsx","../../../client/app/bundles/Teacher/components/progress_reports/student_overview.jsx","../../../client/app/bundles/PremiumHub/containers/PremiumHubContainer.jsx","../../../client/app/bundles/PremiumHub/containers/PremiumHubRouter.jsx","../../../client/app/reducers/district_activity_scores.js","../../../client/app/reducers/district_concept_reports.js","../../../client/app/reducers/district_standards_reports.js","../../../client/app/bundles/Teacher/startup/PremiumHubAppClient.jsx","../../../client/app/bundles/Teacher/startup/PremiumPricingGuideAppClient.jsx","../../../client/app/bundles/Teacher/startup/PressAppClient.jsx","../../../client/app/bundles/Teacher/components/progress_reports/activities_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/activities_scores_by_classroom_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/concepts_concepts_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/concepts_students_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/standards_classroom_standards_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/standards_classroom_students_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/standards_standard_students_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/standards_standards_progress_report.jsx","../../../client/app/bundles/Teacher/components/progress_reports/landing_page.jsx","../../../client/app/bundles/Teacher/containers/LandingPageContainer.jsx","../../../client/app/bundles/Teacher/containers/ProgressReportIndex.jsx","../../../client/app/bundles/Teacher/startup/ProgressReportAppClient.jsx","../../../client/app/bundles/Teacher/containers/PublicActivityPacks.jsx","../../../client/app/bundles/Teacher/startup/PublicActivityPacksAppClient.jsx","../../../client/app/bundles/Teacher/containers/PublicUnitTemplatesRouter.jsx","../../../client/app/bundles/Teacher/startup/PublicUnitTemplatesAppClient.jsx","../../../client/app/bundles/Teacher/components/accounts/reset_password/reset_password.jsx","../../../client/app/bundles/Teacher/startup/ResetPasswordAppClient.jsx","../../../client/app/bundles/Teacher/components/activities/results_page/results_icon.jsx","../../../client/app/bundles/Teacher/containers/ResultsPage.jsx","../../../client/app/bundles/Teacher/startup/ResultsPageAppClient.jsx","../../../client/app/bundles/Teacher/startup/SalesFormAppClient.jsx","../../../client/app/bundles/Teacher/components/modules/scrollify.jsx","../../../client/app/bundles/Teacher/components/scorebook/score_legend.jsx","../../../client/app/bundles/Teacher/components/general_components/date_range_filter_option.jsx","../../../client/app/bundles/Teacher/components/general_components/date_range_filter.jsx","../../../client/app/bundles/Teacher/components/scorebook/scorebook_filters.jsx","../../../client/app/bundles/Teacher/components/general_components/activity_icon_with_tooltip.jsx","../../../client/app/bundles/Teacher/components/scorebook/student_scores.jsx","../../../client/app/bundles/Teacher/containers/Scorebook.jsx","../../../client/app/bundles/Teacher/startup/ScorebookAppClient.jsx","../../../client/app/bundles/Teacher/containers/EditOrCreateSubscription.jsx","../../../client/app/bundles/Teacher/components/subscriptions/available_credits.jsx","../../../client/app/bundles/Teacher/components/subscriptions/premium_credits_table.jsx","../../../client/app/bundles/Teacher/components/subscriptions/refund_policy.jsx","../../../client/app/bundles/Teacher/containers/Subscriptions.jsx","../../../client/app/bundles/Teacher/startup/SubscriptionAppClient.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/delete_account_modal.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/teacher_danger_zone.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/teacher_email_notifications.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/teacher_general.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/unlink_modal.jsx","../../../client/app/bundles/Teacher/components/accounts/edit/teacher_linked_accounts.jsx","../../../client/app/bundles/Teacher/containers/TeacherAccount.jsx","../../../client/app/bundles/Teacher/startup/TeacherAccountAppClient.jsx","../../../client/app/bundles/Teacher/containers/TeacherClassroomsRouter.jsx","../../../client/app/bundles/Teacher/startup/TeacherClassroomsAppClient.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/delete_last_activity_session.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/google_unsync.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/index.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/merge_student_accounts.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/merge_teacher_accounts.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/merge_two_classrooms.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/merge_two_schools.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/move_student.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/recalculate_staggered_release_locks.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/recover_activity_sessions.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/recover_classroom_units.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/recover_unit_activities.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/remove_unsynced_students.jsx","../../../client/app/bundles/Teacher/components/teacher_fix/unarchive_units.jsx","../../../client/app/bundles/Teacher/containers/TeacherFixRouter.jsx","../../../client/app/bundles/Teacher/startup/TeacherFixAppClient.jsx","../../../client/app/bundles/Teacher/components/teacher_guide/checkbox_sections.jsx","../../../client/app/bundles/Teacher/components/teacher_guide/percentage_graph.jsx","../../../client/app/bundles/Teacher/components/teacher_guide/getting_started_mini.jsx","../../../client/app/bundles/Teacher/components/teacher_guide/teacher_guide.jsx","../../../client/app/bundles/Teacher/startup/TeacherGuideClient.jsx","../../../client/app/bundles/Teacher/components/tutorials/LessonsSlides.jsx","../../../client/app/bundles/Teacher/components/tutorials/TutorialIndex.jsx","../../../client/app/bundles/Teacher/containers/TutorialsRouter.jsx","../../../client/app/bundles/Teacher/startup/TutorialsAppClient.jsx","../../../client/app/bundles/Teacher/startup/UnitTemplateCategoriesAppClient.jsx","../../../client/app/bundles/Teacher/startup/clientRegistration.jsx"],"sourcesContent":["import $ from 'jquery';\nimport React from 'react';\nimport _ from 'underscore';\n\nexport default class TextInput extends React.Component {\n componentDidMount() {\n let that = this;\n if (this.determineType() == 'file') {\n $('#' + this.getId()).fileupload({\n dataType: 'json',\n add: function (e, data) {\n let file = data.files[0]\n that.props.update(that.props.name, file);\n }\n });\n }\n }\n\n update = (event) => {\n this.props.update(this.props.name, event.target.value);\n };\n\n titleCase = (string) => {\n let words = string.split(' ')\n let TitleCaseWords = _.map(words, function (word) {\n return this.titleCaseHelper(word)\n }, this);\n let result = _.reduce(TitleCaseWords, function (acc, word) {\n return acc + ' ' + word;\n }, '')\n\n return result;\n };\n\n titleCaseHelper = (word) => {\n return word[0].toUpperCase() + word.substring(1);\n };\n\n determine = (desired, fallback) => {\n return this.props[desired] ? this.props[desired] : fallback;\n };\n\n determineType = () => {\n let type = null;\n if (this.props.type != undefined) {\n type = this.props.type\n } else if (this.props.name === 'password') {\n type = 'password';\n }\n return type;\n };\n\n determineLabel = () => {\n return this.determine('label', this.titleCase(this.removeUnderscore(this.props.name)));\n };\n\n removeUnderscore = (string) => {\n return string.replace(/_/g, ' ');\n };\n\n determinePlaceholder = () => {\n return this.determineLabel();\n };\n\n determineErrorLabel = () => {\n return this.determine('errorLabel', this.determineLabel());\n };\n\n determineErrorKey = () => {\n return this.determine('errorKey', this.props.name);\n };\n\n determineError = () => {\n let errorKey, error;\n errorKey = this.determineErrorKey();\n if ((this.props.errors) && (this.props.errors[errorKey])) {\n error = this.props.errors[errorKey][0];\n } else {\n error = null;\n }\n return error;\n };\n\n displayErrors = () => {\n let error, result;\n error = this.determineError();\n\n if ((error !== null) && (error !== undefined)) {\n result = this.determineErrorLabel() + ' ' + error;\n } else {\n result = null;\n }\n return result;\n };\n\n getId = () => {\n return this.props.name;\n };\n\n getUpdateFn = () => {\n let fn = null\n if (this.determineType() !== 'file') {\n fn = this.update;\n }\n return fn;\n };\n\n determineInputTag = () => {\n let result;\n if (this.props.size == 'medium') {\n result = ()\n\n } else {\n result = ();\n }\n return result;\n };\n\n labelOrNot = () => {\n if (this.props.noLabel) {\n return null;\n } else {\n return (\n
\n
\n
\n {this.determineLabel()}\n
\n
\n
\n );\n }\n };\n\n render() {\n let result;\n if (this.props.isSingleRow) {\n result = this.determineInputTag();\n } else {\n result = (\n
\n
\n {this.labelOrNot()}\n
\n
\n {this.determineInputTag()}\n
\n
\n {this.displayErrors()}\n
\n
\n
\n
\n );\n }\n return result;\n }\n}\n","\nimport _ from 'lodash';\nimport React from 'react';\nimport TextInput from '../../general_components/text_input';\n\nexport default function (component, update, options) {\n\n let config = {\n errors: [],\n update: update\n };\n\n if (options) {\n config = _.merge(config, options)\n }\n\n let _fun1 = function (ele) {\n let default1;\n if (ele.default) {\n default1 = ele.default\n } else if (component.state.model) {\n default1 = component.state.model[ele.name];\n } else {\n default1 = null;\n }\n\n return (\n \n );\n };\n\n this.setErrors = function (errors) {\n config.errors = errors;\n };\n\n this.generate = function (fieldObjs) {\n let inputs;\n if (config.update !== null) {\n inputs = _.map(fieldObjs, _fun1)\n } else {\n inputs = [];\n }\n return inputs;\n };\n}\n","'use strict'\n\nimport _ from 'underscore';\n\nexport default function () {\n\n this.toggle = function (array, item) {\n let newArray, alreadyThere;\n alreadyThere = _.contains(array, item)\n if (alreadyThere) {\n newArray = _.reject(array, function (ele) {return ele == item});\n } else {\n newArray = _.chain(array).push(item).value();\n }\n return newArray;\n };\n\n this.toggleById = function (array, item) {\n let newArray, alreadyThere, existing;\n existing = _.find(array, function (ele) { return ele.id === item.id })\n alreadyThere = (existing != undefined)\n if (alreadyThere) {\n newArray = _.reject(array, function (ele) {return ele == item})\n } else {\n newArray = _.chain(array).push(item).value()\n }\n return newArray;\n }\n}\n","'use strict';\nexport default function (getModelState, setModelState, fnl) {\n\n this.stateItemToggler = function (key) {\n return function (item, boolean) {\n let x = fnl.toggle(getModelState(key), item);\n setModelState(key, x);\n }\n };\n\n this.selector = function (key) {\n return function (value) {\n setModelState(key, value);\n }\n };\n}\n","'use strict'\n\nimport _ from 'lodash';\n\nexport default function () {\n // we have to go through all of this because in order to send files (for example images) over ajax, we have to turn the request data into a FormData object,\n // and adding nested values to FormData objects requires much of the code you see below.\n\n // can probably move this into EC.fnl\n var _getAllValues = function (value) {\n let values;\n let total;\n\n if (value instanceof Object) {\n values = _.values(value);\n let next = _.map(values, function (val) {\n return _getAllValues(val);\n })\n let flattenedNext = _.flattenDeep(next);\n total = _(values).concat(flattenedNext).value();\n } else {\n total = [value];\n }\n return total;\n }\n\n let _isFile = function (item) {\n return item instanceof File;\n }\n\n let _includesFile = function (array) {\n return (_.filter(array, _isFile).length !== 0)\n }\n\n\n var _intoFormData = function (obj, form, namespace) {\n // FROM : (with correction that commenter pointed out aboug passing in namespace to recursive call) : https://gist.github.com/ghinda/8442a57f22099bdb2e34\n // works because of http://stackoverflow.com/questions/12854259/square-brackets-in-name-attribute-of-input-tag\n let fd = form || new FormData();\n let formKey;\n\n for(let property in obj) {\n if(obj.hasOwnProperty(property)) {\n\n if(namespace) {\n formKey = namespace + '[' + property + ']';\n } else {\n formKey = property;\n }\n\n // if the property is an object, but not a File,\n // recur\n if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {\n\n _intoFormData(obj[property], fd, formKey);\n\n } else {\n\n // if it's a string or a File object\n fd.append(formKey, obj[property]);\n }\n\n }\n }\n\n return fd;\n }\n\n\n this.process = function (data) {\n let values, newData;\n\n values = _getAllValues(data);\n if (_includesFile(values)) {\n newData = _intoFormData(data);\n } else {\n newData = data\n }\n return newData;\n }\n\n}\n","'use strict'\n\nimport _ from 'lodash';\n\nexport default function () {\n\n let _replace = function (obj, oldField, newField, newValue) {\n var newObject = {}\n newObject[newField] = newValue;\n var newObject = _.chain(newObject).merge(obj).omit(oldField).value();\n return newObject\n }\n\n let _getValue = function (object, oldField) {\n let oldVal, newVal;\n oldVal = object[oldField]\n if (oldVal instanceof Array) {\n newVal = oldVal.map((el) => el.id)\n } else {\n newVal = oldVal.id;\n }\n return newVal;\n }\n\n let _normalizeField = function (object, fieldData) {\n let fieldName = fieldData.name;\n let fieldIdName = fieldData.idName;\n let value = _getValue(object, fieldName)\n let newObject = _replace(object, fieldName, fieldIdName, value)\n return newObject\n }\n\n\n // PUBLIC\n this.process = function (object, fieldDatas) {\n return _.reduce(fieldDatas, _normalizeField, object);\n }\n\n}\n","'use strict'\n\nimport _ from 'underscore'\nimport FileProcessor from './file_processor'\nimport Normalizer from './normalizer'\n\nexport default function () {\n\n let _modules = {\n fileProcessor: new FileProcessor(),\n normalizer: new Normalizer()\n }\n\n let _constructData = function (resourceNameSingular) {\n return function (data) {\n let hash = {}\n hash[resourceNameSingular] = data\n return hash;\n }\n }\n\n let _normalizer = function (fieldDatas) {\n return function (data) {\n return _modules.normalizer.process(data, fieldDatas);\n }\n }\n\n let _partsPicker = function (savingKeys) {\n return function (data) {\n let result;\n if (savingKeys && savingKeys.length) {\n result = _.pick(data, savingKeys);\n } else {\n result = data;\n }\n return result;\n }\n }\n\n this.process = function (resourceNameSingular, options) {\n return _.compose(\n _modules.fileProcessor.process,\n _constructData(resourceNameSingular),\n _partsPicker(options.savingKeys),\n _normalizer(options.fieldsToNormalize)\n );\n }\n}\n","'use strict'\n\nimport $ from 'jquery'\nimport _ from 'underscore'\n\nexport default function () {\n\n // data -> params\n this.process = function (id, resourceNamePlural, options) {\n return _.compose(\n _paramAdder(_dataType),\n _paramAdder(_callbackParam, options.callback),\n _paramAdder(_urlParam, id, resourceNamePlural, options.urlPrefix),\n _paramAdder(_typeParam, id),\n _paramAdder2(_paramsForFormOrNot),\n _dataIntoParam\n )\n }\n\n var _dataIntoParam = function (data) {\n data.authenticity_token = _authenticity_token()\n return {data: data}\n }\n\n var _paramAdder = function (fn) {\n let hash = fn.apply(null, _.rest(arguments));\n return function (params) {\n let result = _.extend({}, params, hash)\n return result\n }\n }\n\n var _paramAdder2 = function (fn) {\n return function (params) {\n let hash = fn.apply(null, [params]);\n return _.extend({}, params, hash)\n }\n }\n\n let _defaultCallback = function (data) {}\n var _callbackParam = function (callback) {\n var callback = (callback? callback : _defaultCallback)\n return {success: callback}\n }\n\n var _dataType = function () {\n return {dataType: 'json'}\n }\n\n var _urlParam = function (id, resourceNamePlural, urlPrefix) {\n let suffix = id ? ('/' + id) : null;\n let url = [urlPrefix, '/', resourceNamePlural, suffix].join('');\n return {url: url}\n }\n\n var _typeParam = function (id) {\n let type = id ? 'PUT' : 'POST'\n return {type: type}\n }\n\n var _authenticity_token = function() {\n return $('meta[name=csrf-token]').attr('content');\n }\n\n\n var _paramsForFormOrNot = function (params) {\n let extras\n let dataObj = params.data // data is of the form {resourceNameSingular: hash | FormData}\n if (dataObj instanceof FormData) {\n extras = {processData: false, contentType: false}\n } else {\n extras = {contentType: 'application/json',\n data: JSON.stringify(params.data)\n }\n }\n return extras;\n }\n}\n","'use strict'\n\nimport _ from 'underscore'\nimport Data from './data/data'\nimport Params from './params'\n\nexport default function () {\n\n let _modules = {\n data: new Data(),\n params: new Params()\n }\n\n // data, options -> ajaxParams\n this.process = function (data, resourceNameSingular, resourceNamePlural, options) {\n return _.compose(\n _modules.params.process(data.id, resourceNamePlural, options),\n _modules.data.process(resourceNameSingular, options)\n )(data)\n }\n}\n","'use strict'\n\nimport $ from 'jquery';\nimport _ from 'lodash';\nimport Saver from './saver';\n\n\nexport default function (resourceNameSingular, resourceNamePlural, urlPrefix) {\n\n let _urlPrefix = urlPrefix;\n\n let _modules = {\n saver: new Saver()\n }\n\n let _saveCallback = function () {}\n\n let _destroyHelper = function (url, callback) {\n var callback = (callback ? callback : _saveCallback);\n $.ajax({url: url, type: 'DELETE', success: callback})\n }\n\n let _indexCallbackGenerator = function (updater) {\n return function (data) {\n let gold = data[resourceNamePlural];\n updater(gold)\n }\n }\n\n\n\n // // PUBLIC\n\n\n // SAVE\n this.save = function (data, options) {\n var options = _.merge({}, options, {urlPrefix: _urlPrefix});\n let hash = _modules.saver.process(data, resourceNameSingular, resourceNamePlural, options);\n let ajax = options.ajax ? options.ajax : $.ajax // so we can stub out in tests\n return ajax(hash); // return for tests purposes\n }\n\n // GET\n this.getStateFromServer = function (resource, url, callback) {\n var url = (url ? url : ['/', resource].join(''));\n $.get(url, {}, callback(resource), 'json');\n };\n this.getModels = function (updater) {\n let url = [_urlPrefix, '/', resourceNamePlural].join('');\n $.get(url, {}, _indexCallbackGenerator(updater), 'json');\n }\n\n // DESTROY\n this.cmsDestroy = function (id, callback) {\n let url = ['/cms/', resourceNamePlural, '/', id].join('');\n _destroyHelper(url, callback)\n }\n\n}\n","import React from 'react'\nimport _ from 'underscore'\nimport TextInputGenerator from '../modules/componentGenerators/text_input_generator.jsx'\nimport Fnl from '../modules/fnl.jsx'\nimport IndicatorGenerator from '../modules/indicator_generator.jsx'\nimport Server from '../modules/server/server.jsx'\n\nexport default class ActivityClassification extends React.Component {\n constructor(props) {\n super(props);\n\n this.resourceNameSingular = 'activity_classification';\n this.resourceNamePlural = 'activity_classifications';\n\n this.formFields = [\n { name: 'name' },\n { name: 'key' },\n { name: 'form_url' },\n { name: 'module_url' },\n { name: 'order_number' }\n ];\n\n this.initializeModules();\n\n let model = {\n name: null,\n key: null,\n form_url: null,\n module_url: null,\n order_number: this.props.activityClassification.order_number || null\n }\n model = _.extend(model, this.props.activityClassification);\n this.state = { model };\n }\n\n getModelState(key) {\n return this.state.model[key];\n }\n\n initializeModules() {\n let fnl = new Fnl();\n let server = new Server(this.resourceNameSingular, this.resourceNamePlural, '/cms');\n this.modules = {\n textInputGenerator: new TextInputGenerator(this, this.updateModelState),\n server: server,\n indicatorGenerator: new IndicatorGenerator(this.getModelState, this.updateModelState, fnl)\n };\n }\n\n save = () => {\n const model = this.state.model;\n this.modules.server.save(model);\n };\n\n updateModelState = (key, value, context) => {\n let newState = this.state;\n newState.model[key] = value;\n this.setState(newState);\n }\n\n render() {\n let inputs;\n inputs = this.modules.textInputGenerator.generate(this.formFields);\n return(\n
\n {inputs}\n \n
\n )\n }\n}\n","import React from 'react';\nimport _ from 'underscore';\n\nexport default class CmsIndexTableRow extends React.Component {\n edit = () => {\n this.props.actions.edit(this.props.data.resource);\n };\n\n delete = () => {\n let confirm = window.confirm('are you sure you want to delete ' + this.props.data.resource[this.identifier()] + '?');\n if (confirm) {\n this.props.actions.delete(this.props.data.resource);\n }\n };\n\n identifier = () => {\n return this.props.data.identifier || 'name'\n };\n\n activitiesLink = () => {\n if (this.props.resourceNameSingular === 'activity_classification') {\n return
activities
\n }\n };\n\n goToActivities = () => {\n window.location = `/cms/activity_classifications/${this.props.data.resource.id}/activities`\n };\n\n render() {\n let edit_and_delete;\n edit_and_delete = _.reduce(['edit', 'delete'], function (acc, ele) {\n if (this.props.actions[ele]) {\n let el =
{ele}
\n return _.chain(acc).push(el).value();\n } else {\n return acc\n }\n }, [], this);\n\n return (\n \n \n {this.props.data.resource[this.identifier()]}\n \n \n
\n {this.activitiesLink()}\n {edit_and_delete}\n
\n \n \n );\n }\n}\n","import React from 'react';\n\nimport CmsIndexTableRow from './cms_index_table_row.jsx';\n\nimport { SortableList, } from '../../../../Shared/index';\n\nexport default class CmsIndexTable extends React.Component {\n furnishRows = () => {\n let rows = this.props.data.resources.map((resource, index) => this.furnishRow(resource, index) );\n return rows;\n };\n\n furnishRow = (resource, index) => {\n return (\n \n );\n };\n\n identifier = () => {\n return this.props.data.identifier || 'Name'\n };\n\n renderRows = () => {\n if(this.props.isSortable) {\n return (\n
\n
NameActions
\n \n
\n )\n } else {\n return (\n \n \n \n \n \n \n \n \n {this.furnishRows()}\n \n
{this.identifier()}Actions
\n )\n }\n };\n\n render() {\n return this.renderRows();\n }\n}\n","import React from 'react';\n\nimport { DropdownInput } from '../../../../Shared/index';\n\nexport default class ItemDropdown extends React.Component {\n constructor(props) {\n super(props)\n\n const { items, selectedItem } = props;\n const formattedItem = selectedItem ? this.formatItem(selectedItem) : this.formatItem((items[0]));\n\n this.state = { selectedItem: formattedItem }\n }\n\n formatItem = (item) => {\n if(typeof item === 'string') {\n return { label: item, value: { name: item }}\n } else if(typeof item === 'object') {\n return { id: item.id ? item.id : null, label: item.name, value: item }\n }\n }\n\n items = () => {\n const { items } = this.props;\n return items.map(item => {\n return this.formatItem(item);\n });\n };\n\n findItemByIdOrName = (itemObject) => {\n const { items } = this.props;\n const { value } = itemObject;\n const { id, name } = value;\n return items.find((c) => {\n if (!c.id) {\n // then we're matching on name\n return c === name || c.name === name;\n }\n return c.id === id;\n });\n };\n\n onHandleSelect = (itemObject) => {\n const { callback } = this.props;\n const item = this.findItemByIdOrName(itemObject);\n this.setState({ selectedItem: this.formatItem(item)});\n if (callback) {\n callback(item);\n }\n };\n\n render() {\n const { selectedItem, } = this.state\n const { className, isSearchable } = this.props;\n return (\n \n );\n }\n}\n","import React from 'react';\n\nimport { requestPut, } from '../../../modules/request/index';\nimport CmsIndexTable from '../components/cms/cms_index_table/cms_index_table.jsx';\nimport ItemDropdown from '../components/general_components/dropdown_selectors/item_dropdown';\nimport Server from '../components/modules/server/server';\n\nexport default class Cms extends React.Component {\n\n constructor(props, context) {\n super(props, context);\n this.initializeModules()\n let hash1 = {\n crudState: 'index',\n resourceToEdit: null,\n flag: 'All'\n };\n hash1[props.resourceNamePlural] = [];\n this.state = hash1;\n }\n\n componentDidMount() {\n this.getIndexFromServer();\n }\n\n initializeModules = () => {\n let server = new Server(this.props.resourceNameSingular, this.props.resourceNamePlural);\n this.modules = {\n server: server\n }\n };\n\n // TODO: abstract out below method\n updateState = (key, value) => {\n let newState = this.state;\n newState[key] = value;\n this.setState(newState);\n };\n\n indexUrl = () => {\n return ['/cms/', this.props.resourceNamePlural].join('');\n };\n\n getIndexFromServer = () => {\n this.modules.server.getStateFromServer(this.props.resourceNamePlural, this.indexUrl(), this.populateResources);\n };\n\n populateResources = (resource) => {\n // FIXME this fn does not have to be so complicated, need to change server module\n let that = this;\n return function (data) {\n let newState = that.state;\n newState[that.props.resourceNamePlural] = data[that.props.resourceNamePlural];\n that.setState(newState);\n }\n };\n\n indexTable = () => {\n const resourceName = this.props.resourceNamePlural\n let resources\n if (resourceName === 'unit_templates' && this.state.flag !== 'All') {\n if (this.state.flag === 'Not Archived') {\n resources = this.state[resourceName].filter(resource => resource.flag !== 'archived')\n } else {\n resources = this.state[resourceName].filter(resource => resource.flag === this.state.flag.toLowerCase())\n }\n } else {\n resources = this.state[resourceName]\n }\n return (\n \n
\n
\n \n {this.renderSaveButton()}\n {this.renderFlagDropdown()}\n
\n
\n
\n
\n \n
\n
\n
\n );\n };\n\n returnToIndex = () => {\n this.getIndexFromServer();\n this.setState({crudState: 'index'});\n };\n\n individualResourceMode = () => {\n return (this.props.resourceComponentGenerator(this));\n };\n\n edit = (resource) => {\n const { resourceNamePlural } = this.props\n window.open(`/cms/${resourceNamePlural}/${resource.id}/edit`)\n };\n\n delete = (resource) => {\n this.modules.server.cmsDestroy(resource.id);\n this.getIndexFromServer();\n };\n\n crudNew = () => {\n this.setState({crudState: 'new', resourceToEdit: {}});\n };\n\n updateOrder = (sortInfo) => {\n if(this.isSortable()) {\n let originalOrder = this.state[this.props.resourceNamePlural]\n if (this.state.flag === 'Not Archived') {\n originalOrder = originalOrder.filter(resource => resource.flag !== 'archived')\n }\n const newOrder = sortInfo.map(item => item.key);\n const newOrderedResources = newOrder.map((key, i) => {\n const newResource = originalOrder[key];\n newResource.order_number = i;\n return newResource;\n });\n this.setState({[this.props.resourceNamePlural]: newOrderedResources});\n }\n };\n\n saveOrder = () => {\n if(this.isSortable()) {\n const resourceName = this.props.resourceNamePlural;\n const that = this;\n requestPut(\n `${process.env.DEFAULT_URL}/cms/${resourceName}/update_order_numbers`,\n { [resourceName]: that.state[resourceName], },\n (body) => {\n that.setState({[resourceName]: body[resourceName]});\n alert('The updated order has been saved.');\n },\n (body) => {\n alert(`We could not save the updated order. Here is the error: ${body}`);\n },\n )\n }\n };\n\n renderSaveButton = () => {\n return this.isSortable() ? : null\n };\n\n renderFlagDropdown = () => {\n const resourceName = this.props.resourceNamePlural;\n if (resourceName === 'unit_templates') {\n const options = ['All', 'Not Archived', 'Archived', 'Alpha', 'Beta', 'Gamma', 'Production']\n return (\n
\n \n
\n )\n }\n };\n\n switchFlag = (flag) => {\n this.setState({flag: flag})\n };\n\n isSortable = () => {\n if(this.state[this.props.resourceNamePlural].length == 0 || (this.state.flag && !['All', 'Not Archived'].includes(this.state.flag))) { return false }\n const sortableResources = ['activity_classifications', 'unit_templates'];\n return sortableResources.includes(this.props.resourceNamePlural);\n };\n\n render() {\n let result;\n switch (this.state.crudState) {\n case 'index':\n result = this.indexTable();\n break;\n case 'edit':\n result = this.individualResourceMode();\n break;\n case 'new':\n result = this.individualResourceMode();\n break;\n }\n\n return result || null;\n }\n}\n","import React from 'react';\nimport ActivityClassification from '../components/activity_classifications/activity_classification.jsx';\nimport Cms from './Cms.jsx';\n\nexport default class ActivityClassifications extends React.Component {\n constructor(props) {\n super(props)\n }\n\n resourceComponentGenerator(cmsComponent) {\n return (\n \n )\n }\n\n render() {\n //\n return (\n
\n \n
\n );\n }\n}\n","import React from 'react';\nimport ActivityClassifications from '../containers/ActivityClassifications.jsx';\n\nexport default (props) => (\n \n);\n","import React from 'react';\n\nimport AdminAccess from '../containers/AdminAccess';\n\nconst AdminAccessAppClient = (props) => (\n \n);\n\nexport default AdminAccessAppClient\n","import _ from 'underscore';\n\nexport default function (component, kind) {\n // returns a set of data, options\n this.add = function (resource) {\n let newModel = component.state.model\n let newNest = _.chain(newModel[kind]).push(resource).value()\n newModel[kind] = newNest;\n return newModel\n }\n\n\n this.remove = function (resource) {\n let newModel = component.state.model\n let newNest = _.reject(newModel[kind], function (r) { return r.id == resource.id })\n newModel[kind] = newNest;\n return newModel\n }\n}\n","import React from 'react';\nimport TextInputGenerator from '../../modules/componentGenerators/text_input_generator.jsx';\n\nexport default class NewNestedResource extends React.Component {\n constructor(props, context) {\n super(props, context);\n this.modules = {\n textInputGenerator: new TextInputGenerator(this, this.updateModelState)\n }\n\n this.state = {\n model: {id: null}\n };\n }\n\n updateModelState = (key, value) => {\n let model = this.state.model;\n model[key] = value;\n this.setState({model: model});\n };\n\n save = () => {\n this.props.actions.save(this.props.data.name, this.state.model);\n };\n\n render() {\n let inputs = this.modules.textInputGenerator.generate(this.props.data.formFields)\n return (\n
\n
Add New :
\n
\n {inputs}\n \n
\n )\n }\n}\n","import React from 'react';\nimport CmsIndexTable from '../cms_index_table/cms_index_table.jsx';\nimport NewNestedResource from './newNestedResource.jsx';\n\nexport default class NestedResource extends React.Component {\n\n delete = (resource) => {\n this.props.actions.delete(this.props.data.name, resource)\n };\n\n render() {\n\n return (\n
\n
\n

\n
\n
\n

{this.props.data.name}

\n
\n

{this.props.data.message}

\n
\n
\n

\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n );\n }\n}\n","import _ from 'lodash';\nimport React from 'react';\nimport TextInputGenerator from '../../modules/componentGenerators/text_input_generator.jsx';\nimport NestedResource from '../../modules/nested_resource.jsx';\nimport Server from '../../modules/server/server.jsx';\nimport CmsNestedResource from './nestedResource.jsx';\n\nexport default class Resource extends React.Component {\n constructor(props, context) {\n super(props, context);\n this.initializeModules();\n let model1 = _.extend(props.initialModel, props.resource);\n\n let hash = {\n model: model1\n };\n this.state = hash;\n }\n\n initializeModules = () => {\n this.modules = {\n textInputGenerator: new TextInputGenerator(this, this.updateModelState),\n server: new Server(this.props.resourceNameSingular, this.props.resourceNamePlural, '/cms'),\n nestedResources: []\n };\n let that = this;\n if (this.props.nestedResources) {\n this.props.nestedResources.forEach((nr)=>{\n if (nr.name) {\n that.modules.nestedResources[nr.name] = new NestedResource(that, nr.name);\n }\n });\n }\n\n };\n\n updateModelState = (key, value) => {\n let newState = this.state;\n newState.model[key] = value;\n this.setState(newState);\n };\n\n addNestedResource = (kind, resource) => {\n let newModel = this.modules.nestedResources[kind].add(resource)\n this.nestedResourceSaveHelper(newModel)\n };\n\n removeNestedResourceAndSave = (kind, resource) => {\n let newModel = this.modules.nestedResources[kind].remove(resource)\n this.nestedResourceSaveHelper(newModel)\n };\n\n nestedResourceSaveHelper = (newModel) => {\n let data = _.pick(newModel, this.props.savingKeys)\n let options = {\n callback: this.updateModelSaveCallback,\n savingKeys: this.props.savingKeys,\n fieldsToNormalize: this.props.fieldsToNormalize\n }\n this.modules.server.save(data, options)\n };\n\n updateModelSaveCallback = (data) => {\n this.setState({model: data[this.props.resourceNameSingular]})\n };\n\n save = () => {\n let data = _.pick(this.state.model, this.props.savingKeys);\n let options = {\n callback: this.props.returnToIndex,\n savingKeys: this.props.savingKeys,\n fieldsToNormalize: this.props.fieldsToNormalize\n }\n this.modules.server.save(data, options);\n };\n\n render() {\n let inputs = this.modules.textInputGenerator.generate(this.props.formFields);\n let nestedResources\n if (this.props.nestedResources) {\n nestedResources = this.props.nestedResources.map((nr, index)=>{\n let resources = this.state.model[nr.name];\n let data = _.extend(nr, {resources: resources});\n return ;\n });\n }\n return (\n
\n
\n \n

\n
\n
\n
{inputs}
\n
\n
\n
\n
\n {nestedResources}\n
\n
\n
\n
\n \n
\n
\n
\n
\n );\n }\n}\n","'use strict'\nimport React from 'react';\nimport Resource from '../components/cms/resources/resource.jsx';\nimport Cms from './Cms.jsx';\n\nexport default class extends React.Component {\n resourceComponentGenerator = (cmsComponent) => {\n\n let initialModel = {\n id: null,\n name: null,\n admins: []\n };\n\n let savingKeys = ['id', 'name', 'admins', 'teachers'];\n let fieldsToNormalize = [];\n\n let formFields = [\n {\n name: 'name'\n }\n ];\n\n let nestedResources = [\n {\n name: 'admins',\n message: 'must be an existing admin (can create one in the Admin cms)',\n formFields: [{name: 'email'}],\n identifier: 'email',\n findOrCreate: 'find'\n },\n {\n name: 'teachers',\n message: 'must be an existing teacher',\n formFields: [{name: 'email'}],\n identifier: 'email',\n findOrCreate: 'find'\n }\n ]\n\n\n\n return (\n
\n
\n
\n \n
\n
\n
\n );\n };\n\n render() {\n return (\n \n\n );\n }\n}\n","import React from 'react';\nimport AdminAccounts from '../containers/AdminAccounts.jsx';\n\nexport default (props) => (\n \n);\n","'use strict';\nimport React from 'react';\nimport Resource from '../components/cms/resources/resource.jsx';\nimport Cms from './Cms.jsx';\n\nexport default class extends React.Component {\n resourceComponentGenerator = (cmsComponent) => {\n\n let initialModel = {\n id: null,\n name: null,\n email: null,\n password: null\n };\n\n let savingKeys = ['id', 'name', 'email', 'password']\n let fieldsToNormalize = []\n\n let formFields = [\n {name: 'name'},\n {name: 'email'},\n\n {name: 'password',\n type: 'password'}\n ];\n return (\n
\n
\n
\n \n
\n
\n
\n );\n };\n\n render() {\n return (\n \n\n );\n }\n}\n","import React from 'react';\nimport AdminsEditor from '../containers/AdminsEditor.jsx';\n\nexport default (props) => (\n \n);\n","import qs from 'qs'\nimport * as React from 'react'\n\nimport { EVIDENCE_HANDBOOK_LINK, evidenceHandbookIcon } from '../../../Shared'\nimport { TEACHER_CENTER, TEACHER_CENTER_SLUG, WRITING_FOR_LEARNING } from './blog_post_constants'\n\nconst searchTokens = [\n 'getting started',\n 'reading for evidence',\n 'diagnostics',\n 'videos',\n 'best practices',\n 'sentence combining',\n 'assessments',\n 'faq',\n 'pre-ap'\n]\n\nconst SEARCH_LINK = `${process.env.DEFAULT_URL}/${TEACHER_CENTER_SLUG}/search`\n\nconst SearchToken = ({ text }) => {\n return ({text})\n}\n\nexport const HeaderSection = ({ title, subtitle, showCancelSearchButton, query }) => {\n\n function renderEvidenceHandbookBanner() {\n if ([TEACHER_CENTER, WRITING_FOR_LEARNING].includes(title)) {\n return (\n
\n
\n

Quill Reading for Evidence Teacher Handbook

\n

Looking for support integrating Quill Reading for Evidence into your instruction? Our handbook for teachers using our newest literacy tool is packed with best practices and strategies--and it's FREE!

\n Get the Teacher Handbook \n
\n {evidenceHandbookIcon.alt}\n
\n )\n }\n return \n }\n return(\n
\n
\n

{title}

\n

{subtitle}

\n
\n
\n \n \n {showCancelSearchButton ? : null}\n \n
{searchTokens.map(t => )}
\n {renderEvidenceHandbookBanner()}\n
\n )\n}\n\nexport default HeaderSection\n","\"use strict\";\n\nfunction isContainer(node) {\n switch (node._type) {\n case 'Document':\n case 'BlockQuote':\n case 'List':\n case 'Item':\n case 'Paragraph':\n case 'Heading':\n case 'Emph':\n case 'Strong':\n case 'Link':\n case 'Image':\n case 'CustomInline':\n case 'CustomBlock':\n return true;\n default:\n return false;\n }\n}\n\nvar resumeAt = function(node, entering) {\n this.current = node;\n this.entering = (entering === true);\n};\n\nvar next = function(){\n var cur = this.current;\n var entering = this.entering;\n\n if (cur === null) {\n return null;\n }\n\n var container = isContainer(cur);\n\n if (entering && container) {\n if (cur._firstChild) {\n this.current = cur._firstChild;\n this.entering = true;\n } else {\n // stay on node but exit\n this.entering = false;\n }\n\n } else if (cur === this.root) {\n this.current = null;\n\n } else if (cur._next === null) {\n this.current = cur._parent;\n this.entering = false;\n\n } else {\n this.current = cur._next;\n this.entering = true;\n }\n\n return {entering: entering, node: cur};\n};\n\nvar NodeWalker = function(root) {\n return { current: root,\n root: root,\n entering: true,\n next: next,\n resumeAt: resumeAt };\n};\n\nvar Node = function(nodeType, sourcepos) {\n this._type = nodeType;\n this._parent = null;\n this._firstChild = null;\n this._lastChild = null;\n this._prev = null;\n this._next = null;\n this._sourcepos = sourcepos;\n this._lastLineBlank = false;\n this._open = true;\n this._string_content = null;\n this._literal = null;\n this._listData = {};\n this._info = null;\n this._destination = null;\n this._title = null;\n this._isFenced = false;\n this._fenceChar = null;\n this._fenceLength = 0;\n this._fenceOffset = null;\n this._level = null;\n this._onEnter = null;\n this._onExit = null;\n};\n\nvar proto = Node.prototype;\n\nObject.defineProperty(proto, 'isContainer', {\n get: function () { return isContainer(this); }\n});\n\nObject.defineProperty(proto, 'type', {\n get: function() { return this._type; }\n});\n\nObject.defineProperty(proto, 'firstChild', {\n get: function() { return this._firstChild; }\n});\n\nObject.defineProperty(proto, 'lastChild', {\n get: function() { return this._lastChild; }\n});\n\nObject.defineProperty(proto, 'next', {\n get: function() { return this._next; }\n});\n\nObject.defineProperty(proto, 'prev', {\n get: function() { return this._prev; }\n});\n\nObject.defineProperty(proto, 'parent', {\n get: function() { return this._parent; }\n});\n\nObject.defineProperty(proto, 'sourcepos', {\n get: function() { return this._sourcepos; }\n});\n\nObject.defineProperty(proto, 'literal', {\n get: function() { return this._literal; },\n set: function(s) { this._literal = s; }\n});\n\nObject.defineProperty(proto, 'destination', {\n get: function() { return this._destination; },\n set: function(s) { this._destination = s; }\n});\n\nObject.defineProperty(proto, 'title', {\n get: function() { return this._title; },\n set: function(s) { this._title = s; }\n});\n\nObject.defineProperty(proto, 'info', {\n get: function() { return this._info; },\n set: function(s) { this._info = s; }\n});\n\nObject.defineProperty(proto, 'level', {\n get: function() { return this._level; },\n set: function(s) { this._level = s; }\n});\n\nObject.defineProperty(proto, 'listType', {\n get: function() { return this._listData.type; },\n set: function(t) { this._listData.type = t; }\n});\n\nObject.defineProperty(proto, 'listTight', {\n get: function() { return this._listData.tight; },\n set: function(t) { this._listData.tight = t; }\n});\n\nObject.defineProperty(proto, 'listStart', {\n get: function() { return this._listData.start; },\n set: function(n) { this._listData.start = n; }\n});\n\nObject.defineProperty(proto, 'listDelimiter', {\n get: function() { return this._listData.delimiter; },\n set: function(delim) { this._listData.delimiter = delim; }\n});\n\nObject.defineProperty(proto, 'onEnter', {\n get: function() { return this._onEnter; },\n set: function(s) { this._onEnter = s; }\n});\n\nObject.defineProperty(proto, 'onExit', {\n get: function() { return this._onExit; },\n set: function(s) { this._onExit = s; }\n});\n\nNode.prototype.appendChild = function(child) {\n child.unlink();\n child._parent = this;\n if (this._lastChild) {\n this._lastChild._next = child;\n child._prev = this._lastChild;\n this._lastChild = child;\n } else {\n this._firstChild = child;\n this._lastChild = child;\n }\n};\n\nNode.prototype.prependChild = function(child) {\n child.unlink();\n child._parent = this;\n if (this._firstChild) {\n this._firstChild._prev = child;\n child._next = this._firstChild;\n this._firstChild = child;\n } else {\n this._firstChild = child;\n this._lastChild = child;\n }\n};\n\nNode.prototype.unlink = function() {\n if (this._prev) {\n this._prev._next = this._next;\n } else if (this._parent) {\n this._parent._firstChild = this._next;\n }\n if (this._next) {\n this._next._prev = this._prev;\n } else if (this._parent) {\n this._parent._lastChild = this._prev;\n }\n this._parent = null;\n this._next = null;\n this._prev = null;\n};\n\nNode.prototype.insertAfter = function(sibling) {\n sibling.unlink();\n sibling._next = this._next;\n if (sibling._next) {\n sibling._next._prev = sibling;\n }\n sibling._prev = this;\n this._next = sibling;\n sibling._parent = this._parent;\n if (!sibling._next) {\n sibling._parent._lastChild = sibling;\n }\n};\n\nNode.prototype.insertBefore = function(sibling) {\n sibling.unlink();\n sibling._prev = this._prev;\n if (sibling._prev) {\n sibling._prev._next = sibling;\n }\n sibling._next = this;\n this._prev = sibling;\n sibling._parent = this._parent;\n if (!sibling._prev) {\n sibling._parent._firstChild = sibling;\n }\n};\n\nNode.prototype.walker = function() {\n var walker = new NodeWalker(this);\n return walker;\n};\n\nmodule.exports = Node;\n\n\n/* Example of use of walker:\n\n var walker = w.walker();\n var event;\n\n while (event = walker.next()) {\n console.log(event.entering, event.node.type);\n }\n\n */\n","\n'use strict';\n\n\nvar encodeCache = {};\n\n\n// Create a lookup array where anything but characters in `chars` string\n// and alphanumeric chars is percent-encoded.\n//\nfunction getEncodeCache(exclude) {\n var i, ch, cache = encodeCache[exclude];\n if (cache) { return cache; }\n\n cache = encodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n\n if (/^[0-9a-z]$/i.test(ch)) {\n // always allow unencoded alphanumeric characters\n cache.push(ch);\n } else {\n cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));\n }\n }\n\n for (i = 0; i < exclude.length; i++) {\n cache[exclude.charCodeAt(i)] = exclude[i];\n }\n\n return cache;\n}\n\n\n// Encode unsafe characters with percent-encoding, skipping already\n// encoded sequences.\n//\n// - string - string to encode\n// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)\n// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)\n//\nfunction encode(string, exclude, keepEscaped) {\n var i, l, code, nextCode, cache,\n result = '';\n\n if (typeof exclude !== 'string') {\n // encode(string, keepEscaped)\n keepEscaped = exclude;\n exclude = encode.defaultChars;\n }\n\n if (typeof keepEscaped === 'undefined') {\n keepEscaped = true;\n }\n\n cache = getEncodeCache(exclude);\n\n for (i = 0, l = string.length; i < l; i++) {\n code = string.charCodeAt(i);\n\n if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\n result += string.slice(i, i + 3);\n i += 2;\n continue;\n }\n }\n\n if (code < 128) {\n result += cache[code];\n continue;\n }\n\n if (code >= 0xD800 && code <= 0xDFFF) {\n if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {\n nextCode = string.charCodeAt(i + 1);\n if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {\n result += encodeURIComponent(string[i] + string[i + 1]);\n i++;\n continue;\n }\n }\n result += '%EF%BF%BD';\n continue;\n }\n\n result += encodeURIComponent(string[i]);\n }\n\n return result;\n}\n\nencode.defaultChars = \";/?:@&=+$,-_.!~*'()#\";\nencode.componentChars = \"-_.!~*'()\";\n\n\nmodule.exports = encode;\n","\n'use strict';\n\n\n/* eslint-disable no-bitwise */\n\nvar decodeCache = {};\n\nfunction getDecodeCache(exclude) {\n var i, ch, cache = decodeCache[exclude];\n if (cache) { return cache; }\n\n cache = decodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n cache.push(ch);\n }\n\n for (i = 0; i < exclude.length; i++) {\n ch = exclude.charCodeAt(i);\n cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2);\n }\n\n return cache;\n}\n\n\n// Decode percent-encoded string.\n//\nfunction decode(string, exclude) {\n var cache;\n\n if (typeof exclude !== 'string') {\n exclude = decode.defaultChars;\n }\n\n cache = getDecodeCache(exclude);\n\n return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {\n var i, l, b1, b2, b3, b4, chr,\n result = '';\n\n for (i = 0, l = seq.length; i < l; i += 3) {\n b1 = parseInt(seq.slice(i + 1, i + 3), 16);\n\n if (b1 < 0x80) {\n result += cache[b1];\n continue;\n }\n\n if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {\n // 110xxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n\n if ((b2 & 0xC0) === 0x80) {\n chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);\n\n if (chr < 0x80) {\n result += '\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 3;\n continue;\n }\n }\n\n if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\n chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F);\n\n if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {\n result += '\\ufffd\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 6;\n continue;\n }\n }\n\n if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {\n // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n b4 = parseInt(seq.slice(i + 10, i + 12), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {\n chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F);\n\n if (chr < 0x10000 || chr > 0x10FFFF) {\n result += '\\ufffd\\ufffd\\ufffd\\ufffd';\n } else {\n chr -= 0x10000;\n result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF));\n }\n\n i += 9;\n continue;\n }\n }\n\n result += '\\ufffd';\n }\n\n return result;\n });\n}\n\n\ndecode.defaultChars = ';/?:@&=+$,#';\ndecode.componentChars = '';\n\n\nmodule.exports = decode;\n","var inverseXML = getInverseObj(require(\"../maps/xml.json\")),\n xmlReplacer = getInverseReplacer(inverseXML);\n\nexports.XML = getInverse(inverseXML, xmlReplacer);\n\nvar inverseHTML = getInverseObj(require(\"../maps/entities.json\")),\n htmlReplacer = getInverseReplacer(inverseHTML);\n\nexports.HTML = getInverse(inverseHTML, htmlReplacer);\n\nfunction getInverseObj(obj) {\n return Object.keys(obj)\n .sort()\n .reduce(function(inverse, name) {\n inverse[obj[name]] = \"&\" + name + \";\";\n return inverse;\n }, {});\n}\n\nfunction getInverseReplacer(inverse) {\n var single = [],\n multiple = [];\n\n Object.keys(inverse).forEach(function(k) {\n if (k.length === 1) {\n single.push(\"\\\\\" + k);\n } else {\n multiple.push(k);\n }\n });\n\n //TODO add ranges\n multiple.unshift(\"[\" + single.join(\"\") + \"]\");\n\n return new RegExp(multiple.join(\"|\"), \"g\");\n}\n\nvar re_nonASCII = /[^\\0-\\x7F]/g,\n re_astralSymbols = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;\n\nfunction singleCharReplacer(c) {\n return (\n \"&#x\" +\n c\n .charCodeAt(0)\n .toString(16)\n .toUpperCase() +\n \";\"\n );\n}\n\nfunction astralReplacer(c) {\n // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n var high = c.charCodeAt(0);\n var low = c.charCodeAt(1);\n var codePoint = (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;\n return \"&#x\" + codePoint.toString(16).toUpperCase() + \";\";\n}\n\nfunction getInverse(inverse, re) {\n function func(name) {\n return inverse[name];\n }\n\n return function(data) {\n return data\n .replace(re, func)\n .replace(re_astralSymbols, astralReplacer)\n .replace(re_nonASCII, singleCharReplacer);\n };\n}\n\nvar re_xmlChars = getInverseReplacer(inverseXML);\n\nfunction escapeXML(data) {\n return data\n .replace(re_xmlChars, singleCharReplacer)\n .replace(re_astralSymbols, astralReplacer)\n .replace(re_nonASCII, singleCharReplacer);\n}\n\nexports.escape = escapeXML;\n","var entityMap = require(\"../maps/entities.json\"),\n legacyMap = require(\"../maps/legacy.json\"),\n xmlMap = require(\"../maps/xml.json\"),\n decodeCodePoint = require(\"./decode_codepoint.js\");\n\nvar decodeXMLStrict = getStrictDecoder(xmlMap),\n decodeHTMLStrict = getStrictDecoder(entityMap);\n\nfunction getStrictDecoder(map) {\n var keys = Object.keys(map).join(\"|\"),\n replace = getReplacer(map);\n\n keys += \"|#[xX][\\\\da-fA-F]+|#\\\\d+\";\n\n var re = new RegExp(\"&(?:\" + keys + \");\", \"g\");\n\n return function(str) {\n return String(str).replace(re, replace);\n };\n}\n\nvar decodeHTML = (function() {\n var legacy = Object.keys(legacyMap).sort(sorter);\n\n var keys = Object.keys(entityMap).sort(sorter);\n\n for (var i = 0, j = 0; i < keys.length; i++) {\n if (legacy[j] === keys[i]) {\n keys[i] += \";?\";\n j++;\n } else {\n keys[i] += \";\";\n }\n }\n\n var re = new RegExp(\"&(?:\" + keys.join(\"|\") + \"|#[xX][\\\\da-fA-F]+;?|#\\\\d+;?)\", \"g\"),\n replace = getReplacer(entityMap);\n\n function replacer(str) {\n if (str.substr(-1) !== \";\") str += \";\";\n return replace(str);\n }\n\n //TODO consider creating a merged map\n return function(str) {\n return String(str).replace(re, replacer);\n };\n})();\n\nfunction sorter(a, b) {\n return a < b ? 1 : -1;\n}\n\nfunction getReplacer(map) {\n return function replace(str) {\n if (str.charAt(1) === \"#\") {\n if (str.charAt(2) === \"X\" || str.charAt(2) === \"x\") {\n return decodeCodePoint(parseInt(str.substr(3), 16));\n }\n return decodeCodePoint(parseInt(str.substr(2), 10));\n }\n return map[str.slice(1, -1)];\n };\n}\n\nmodule.exports = {\n XML: decodeXMLStrict,\n HTML: decodeHTML,\n HTMLStrict: decodeHTMLStrict\n};\n","var encode = require(\"./lib/encode.js\"),\n decode = require(\"./lib/decode.js\");\n\nexports.decode = function(data, level) {\n return (!level || level <= 0 ? decode.XML : decode.HTML)(data);\n};\n\nexports.decodeStrict = function(data, level) {\n return (!level || level <= 0 ? decode.XML : decode.HTMLStrict)(data);\n};\n\nexports.encode = function(data, level) {\n return (!level || level <= 0 ? encode.XML : encode.HTML)(data);\n};\n\nexports.encodeXML = encode.XML;\n\nexports.encodeHTML4 = exports.encodeHTML5 = exports.encodeHTML = encode.HTML;\n\nexports.decodeXML = exports.decodeXMLStrict = decode.XML;\n\nexports.decodeHTML4 = exports.decodeHTML5 = exports.decodeHTML = decode.HTML;\n\nexports.decodeHTML4Strict = exports.decodeHTML5Strict = exports.decodeHTMLStrict = decode.HTMLStrict;\n\nexports.escape = encode.escape;\n","\"use strict\";\n\nvar encode = require('mdurl/encode');\nvar decode = require('mdurl/decode');\n\nvar C_BACKSLASH = 92;\n\nvar decodeHTML = require('entities').decodeHTML;\n\nvar ENTITY = \"&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});\";\n\nvar TAGNAME = '[A-Za-z][A-Za-z0-9-]*';\nvar ATTRIBUTENAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*';\nvar UNQUOTEDVALUE = \"[^\\\"'=<>`\\\\x00-\\\\x20]+\";\nvar SINGLEQUOTEDVALUE = \"'[^']*'\";\nvar DOUBLEQUOTEDVALUE = '\"[^\"]*\"';\nvar ATTRIBUTEVALUE = \"(?:\" + UNQUOTEDVALUE + \"|\" + SINGLEQUOTEDVALUE + \"|\" + DOUBLEQUOTEDVALUE + \")\";\nvar ATTRIBUTEVALUESPEC = \"(?:\" + \"\\\\s*=\" + \"\\\\s*\" + ATTRIBUTEVALUE + \")\";\nvar ATTRIBUTE = \"(?:\" + \"\\\\s+\" + ATTRIBUTENAME + ATTRIBUTEVALUESPEC + \"?)\";\nvar OPENTAG = \"<\" + TAGNAME + ATTRIBUTE + \"*\" + \"\\\\s*/?>\";\nvar CLOSETAG = \"]\";\nvar HTMLCOMMENT = \"|\";\nvar PROCESSINGINSTRUCTION = \"[<][?].*?[?][>]\";\nvar DECLARATION = \"]*>\";\nvar CDATA = \"\";\nvar HTMLTAG = \"(?:\" + OPENTAG + \"|\" + CLOSETAG + \"|\" + HTMLCOMMENT + \"|\" +\n PROCESSINGINSTRUCTION + \"|\" + DECLARATION + \"|\" + CDATA + \")\";\nvar reHtmlTag = new RegExp('^' + HTMLTAG, 'i');\n\nvar reBackslashOrAmp = /[\\\\&]/;\n\nvar ESCAPABLE = '[!\"#$%&\\'()*+,./:;<=>?@[\\\\\\\\\\\\]^_`{|}~-]';\n\nvar reEntityOrEscapedChar = new RegExp('\\\\\\\\' + ESCAPABLE + '|' + ENTITY, 'gi');\n\nvar XMLSPECIAL = '[&<>\"]';\n\nvar reXmlSpecial = new RegExp(XMLSPECIAL, 'g');\n\nvar reXmlSpecialOrEntity = new RegExp(ENTITY + '|' + XMLSPECIAL, 'gi');\n\nvar unescapeChar = function(s) {\n if (s.charCodeAt(0) === C_BACKSLASH) {\n return s.charAt(1);\n } else {\n return decodeHTML(s);\n }\n};\n\n// Replace entities and backslash escapes with literal characters.\nvar unescapeString = function(s) {\n if (reBackslashOrAmp.test(s)) {\n return s.replace(reEntityOrEscapedChar, unescapeChar);\n } else {\n return s;\n }\n};\n\nvar normalizeURI = function(uri) {\n try {\n return encode(decode(uri));\n }\n catch(err) {\n return uri;\n }\n};\n\nvar replaceUnsafeChar = function(s) {\n switch (s) {\n case '&':\n return '&';\n case '<':\n return '<';\n case '>':\n return '>';\n case '\"':\n return '"';\n default:\n return s;\n }\n};\n\nvar escapeXml = function(s, preserve_entities) {\n if (reXmlSpecial.test(s)) {\n if (preserve_entities) {\n return s.replace(reXmlSpecialOrEntity, replaceUnsafeChar);\n } else {\n return s.replace(reXmlSpecial, replaceUnsafeChar);\n }\n } else {\n return s;\n }\n};\n\nmodule.exports = { unescapeString: unescapeString,\n normalizeURI: normalizeURI,\n escapeXml: escapeXml,\n reHtmlTag: reHtmlTag,\n OPENTAG: OPENTAG,\n CLOSETAG: CLOSETAG,\n ENTITY: ENTITY,\n ESCAPABLE: ESCAPABLE\n };\n","\"use strict\";\n\n/* The bulk of this code derives from https://github.com/dmoscrop/fold-case\nBut in addition to case-folding, we also normalize whitespace.\n\nfold-case is Copyright Mathias Bynens \n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n/*eslint-disable key-spacing, comma-spacing */\n\nvar regex = /[ \\t\\r\\n]+|[A-Z\\xB5\\xC0-\\xD6\\xD8-\\xDF\\u0100\\u0102\\u0104\\u0106\\u0108\\u010A\\u010C\\u010E\\u0110\\u0112\\u0114\\u0116\\u0118\\u011A\\u011C\\u011E\\u0120\\u0122\\u0124\\u0126\\u0128\\u012A\\u012C\\u012E\\u0130\\u0132\\u0134\\u0136\\u0139\\u013B\\u013D\\u013F\\u0141\\u0143\\u0145\\u0147\\u0149\\u014A\\u014C\\u014E\\u0150\\u0152\\u0154\\u0156\\u0158\\u015A\\u015C\\u015E\\u0160\\u0162\\u0164\\u0166\\u0168\\u016A\\u016C\\u016E\\u0170\\u0172\\u0174\\u0176\\u0178\\u0179\\u017B\\u017D\\u017F\\u0181\\u0182\\u0184\\u0186\\u0187\\u0189-\\u018B\\u018E-\\u0191\\u0193\\u0194\\u0196-\\u0198\\u019C\\u019D\\u019F\\u01A0\\u01A2\\u01A4\\u01A6\\u01A7\\u01A9\\u01AC\\u01AE\\u01AF\\u01B1-\\u01B3\\u01B5\\u01B7\\u01B8\\u01BC\\u01C4\\u01C5\\u01C7\\u01C8\\u01CA\\u01CB\\u01CD\\u01CF\\u01D1\\u01D3\\u01D5\\u01D7\\u01D9\\u01DB\\u01DE\\u01E0\\u01E2\\u01E4\\u01E6\\u01E8\\u01EA\\u01EC\\u01EE\\u01F0-\\u01F2\\u01F4\\u01F6-\\u01F8\\u01FA\\u01FC\\u01FE\\u0200\\u0202\\u0204\\u0206\\u0208\\u020A\\u020C\\u020E\\u0210\\u0212\\u0214\\u0216\\u0218\\u021A\\u021C\\u021E\\u0220\\u0222\\u0224\\u0226\\u0228\\u022A\\u022C\\u022E\\u0230\\u0232\\u023A\\u023B\\u023D\\u023E\\u0241\\u0243-\\u0246\\u0248\\u024A\\u024C\\u024E\\u0345\\u0370\\u0372\\u0376\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03AB\\u03B0\\u03C2\\u03CF-\\u03D1\\u03D5\\u03D6\\u03D8\\u03DA\\u03DC\\u03DE\\u03E0\\u03E2\\u03E4\\u03E6\\u03E8\\u03EA\\u03EC\\u03EE\\u03F0\\u03F1\\u03F4\\u03F5\\u03F7\\u03F9\\u03FA\\u03FD-\\u042F\\u0460\\u0462\\u0464\\u0466\\u0468\\u046A\\u046C\\u046E\\u0470\\u0472\\u0474\\u0476\\u0478\\u047A\\u047C\\u047E\\u0480\\u048A\\u048C\\u048E\\u0490\\u0492\\u0494\\u0496\\u0498\\u049A\\u049C\\u049E\\u04A0\\u04A2\\u04A4\\u04A6\\u04A8\\u04AA\\u04AC\\u04AE\\u04B0\\u04B2\\u04B4\\u04B6\\u04B8\\u04BA\\u04BC\\u04BE\\u04C0\\u04C1\\u04C3\\u04C5\\u04C7\\u04C9\\u04CB\\u04CD\\u04D0\\u04D2\\u04D4\\u04D6\\u04D8\\u04DA\\u04DC\\u04DE\\u04E0\\u04E2\\u04E4\\u04E6\\u04E8\\u04EA\\u04EC\\u04EE\\u04F0\\u04F2\\u04F4\\u04F6\\u04F8\\u04FA\\u04FC\\u04FE\\u0500\\u0502\\u0504\\u0506\\u0508\\u050A\\u050C\\u050E\\u0510\\u0512\\u0514\\u0516\\u0518\\u051A\\u051C\\u051E\\u0520\\u0522\\u0524\\u0526\\u0528\\u052A\\u052C\\u052E\\u0531-\\u0556\\u0587\\u10A0-\\u10C5\\u10C7\\u10CD\\u1E00\\u1E02\\u1E04\\u1E06\\u1E08\\u1E0A\\u1E0C\\u1E0E\\u1E10\\u1E12\\u1E14\\u1E16\\u1E18\\u1E1A\\u1E1C\\u1E1E\\u1E20\\u1E22\\u1E24\\u1E26\\u1E28\\u1E2A\\u1E2C\\u1E2E\\u1E30\\u1E32\\u1E34\\u1E36\\u1E38\\u1E3A\\u1E3C\\u1E3E\\u1E40\\u1E42\\u1E44\\u1E46\\u1E48\\u1E4A\\u1E4C\\u1E4E\\u1E50\\u1E52\\u1E54\\u1E56\\u1E58\\u1E5A\\u1E5C\\u1E5E\\u1E60\\u1E62\\u1E64\\u1E66\\u1E68\\u1E6A\\u1E6C\\u1E6E\\u1E70\\u1E72\\u1E74\\u1E76\\u1E78\\u1E7A\\u1E7C\\u1E7E\\u1E80\\u1E82\\u1E84\\u1E86\\u1E88\\u1E8A\\u1E8C\\u1E8E\\u1E90\\u1E92\\u1E94\\u1E96-\\u1E9B\\u1E9E\\u1EA0\\u1EA2\\u1EA4\\u1EA6\\u1EA8\\u1EAA\\u1EAC\\u1EAE\\u1EB0\\u1EB2\\u1EB4\\u1EB6\\u1EB8\\u1EBA\\u1EBC\\u1EBE\\u1EC0\\u1EC2\\u1EC4\\u1EC6\\u1EC8\\u1ECA\\u1ECC\\u1ECE\\u1ED0\\u1ED2\\u1ED4\\u1ED6\\u1ED8\\u1EDA\\u1EDC\\u1EDE\\u1EE0\\u1EE2\\u1EE4\\u1EE6\\u1EE8\\u1EEA\\u1EEC\\u1EEE\\u1EF0\\u1EF2\\u1EF4\\u1EF6\\u1EF8\\u1EFA\\u1EFC\\u1EFE\\u1F08-\\u1F0F\\u1F18-\\u1F1D\\u1F28-\\u1F2F\\u1F38-\\u1F3F\\u1F48-\\u1F4D\\u1F50\\u1F52\\u1F54\\u1F56\\u1F59\\u1F5B\\u1F5D\\u1F5F\\u1F68-\\u1F6F\\u1F80-\\u1FAF\\u1FB2-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD2\\u1FD3\\u1FD6-\\u1FDB\\u1FE2-\\u1FE4\\u1FE6-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2126\\u212A\\u212B\\u2132\\u2160-\\u216F\\u2183\\u24B6-\\u24CF\\u2C00-\\u2C2E\\u2C60\\u2C62-\\u2C64\\u2C67\\u2C69\\u2C6B\\u2C6D-\\u2C70\\u2C72\\u2C75\\u2C7E-\\u2C80\\u2C82\\u2C84\\u2C86\\u2C88\\u2C8A\\u2C8C\\u2C8E\\u2C90\\u2C92\\u2C94\\u2C96\\u2C98\\u2C9A\\u2C9C\\u2C9E\\u2CA0\\u2CA2\\u2CA4\\u2CA6\\u2CA8\\u2CAA\\u2CAC\\u2CAE\\u2CB0\\u2CB2\\u2CB4\\u2CB6\\u2CB8\\u2CBA\\u2CBC\\u2CBE\\u2CC0\\u2CC2\\u2CC4\\u2CC6\\u2CC8\\u2CCA\\u2CCC\\u2CCE\\u2CD0\\u2CD2\\u2CD4\\u2CD6\\u2CD8\\u2CDA\\u2CDC\\u2CDE\\u2CE0\\u2CE2\\u2CEB\\u2CED\\u2CF2\\uA640\\uA642\\uA644\\uA646\\uA648\\uA64A\\uA64C\\uA64E\\uA650\\uA652\\uA654\\uA656\\uA658\\uA65A\\uA65C\\uA65E\\uA660\\uA662\\uA664\\uA666\\uA668\\uA66A\\uA66C\\uA680\\uA682\\uA684\\uA686\\uA688\\uA68A\\uA68C\\uA68E\\uA690\\uA692\\uA694\\uA696\\uA698\\uA69A\\uA722\\uA724\\uA726\\uA728\\uA72A\\uA72C\\uA72E\\uA732\\uA734\\uA736\\uA738\\uA73A\\uA73C\\uA73E\\uA740\\uA742\\uA744\\uA746\\uA748\\uA74A\\uA74C\\uA74E\\uA750\\uA752\\uA754\\uA756\\uA758\\uA75A\\uA75C\\uA75E\\uA760\\uA762\\uA764\\uA766\\uA768\\uA76A\\uA76C\\uA76E\\uA779\\uA77B\\uA77D\\uA77E\\uA780\\uA782\\uA784\\uA786\\uA78B\\uA78D\\uA790\\uA792\\uA796\\uA798\\uA79A\\uA79C\\uA79E\\uA7A0\\uA7A2\\uA7A4\\uA7A6\\uA7A8\\uA7AA-\\uA7AD\\uA7B0\\uA7B1\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFF21-\\uFF3A]|\\uD801[\\uDC00-\\uDC27]|\\uD806[\\uDCA0-\\uDCBF]/g;\n\nvar map = {'A':'a','B':'b','C':'c','D':'d','E':'e','F':'f','G':'g','H':'h','I':'i','J':'j','K':'k','L':'l','M':'m','N':'n','O':'o','P':'p','Q':'q','R':'r','S':'s','T':'t','U':'u','V':'v','W':'w','X':'x','Y':'y','Z':'z','\\xB5':'\\u03BC','\\xC0':'\\xE0','\\xC1':'\\xE1','\\xC2':'\\xE2','\\xC3':'\\xE3','\\xC4':'\\xE4','\\xC5':'\\xE5','\\xC6':'\\xE6','\\xC7':'\\xE7','\\xC8':'\\xE8','\\xC9':'\\xE9','\\xCA':'\\xEA','\\xCB':'\\xEB','\\xCC':'\\xEC','\\xCD':'\\xED','\\xCE':'\\xEE','\\xCF':'\\xEF','\\xD0':'\\xF0','\\xD1':'\\xF1','\\xD2':'\\xF2','\\xD3':'\\xF3','\\xD4':'\\xF4','\\xD5':'\\xF5','\\xD6':'\\xF6','\\xD8':'\\xF8','\\xD9':'\\xF9','\\xDA':'\\xFA','\\xDB':'\\xFB','\\xDC':'\\xFC','\\xDD':'\\xFD','\\xDE':'\\xFE','\\u0100':'\\u0101','\\u0102':'\\u0103','\\u0104':'\\u0105','\\u0106':'\\u0107','\\u0108':'\\u0109','\\u010A':'\\u010B','\\u010C':'\\u010D','\\u010E':'\\u010F','\\u0110':'\\u0111','\\u0112':'\\u0113','\\u0114':'\\u0115','\\u0116':'\\u0117','\\u0118':'\\u0119','\\u011A':'\\u011B','\\u011C':'\\u011D','\\u011E':'\\u011F','\\u0120':'\\u0121','\\u0122':'\\u0123','\\u0124':'\\u0125','\\u0126':'\\u0127','\\u0128':'\\u0129','\\u012A':'\\u012B','\\u012C':'\\u012D','\\u012E':'\\u012F','\\u0132':'\\u0133','\\u0134':'\\u0135','\\u0136':'\\u0137','\\u0139':'\\u013A','\\u013B':'\\u013C','\\u013D':'\\u013E','\\u013F':'\\u0140','\\u0141':'\\u0142','\\u0143':'\\u0144','\\u0145':'\\u0146','\\u0147':'\\u0148','\\u014A':'\\u014B','\\u014C':'\\u014D','\\u014E':'\\u014F','\\u0150':'\\u0151','\\u0152':'\\u0153','\\u0154':'\\u0155','\\u0156':'\\u0157','\\u0158':'\\u0159','\\u015A':'\\u015B','\\u015C':'\\u015D','\\u015E':'\\u015F','\\u0160':'\\u0161','\\u0162':'\\u0163','\\u0164':'\\u0165','\\u0166':'\\u0167','\\u0168':'\\u0169','\\u016A':'\\u016B','\\u016C':'\\u016D','\\u016E':'\\u016F','\\u0170':'\\u0171','\\u0172':'\\u0173','\\u0174':'\\u0175','\\u0176':'\\u0177','\\u0178':'\\xFF','\\u0179':'\\u017A','\\u017B':'\\u017C','\\u017D':'\\u017E','\\u017F':'s','\\u0181':'\\u0253','\\u0182':'\\u0183','\\u0184':'\\u0185','\\u0186':'\\u0254','\\u0187':'\\u0188','\\u0189':'\\u0256','\\u018A':'\\u0257','\\u018B':'\\u018C','\\u018E':'\\u01DD','\\u018F':'\\u0259','\\u0190':'\\u025B','\\u0191':'\\u0192','\\u0193':'\\u0260','\\u0194':'\\u0263','\\u0196':'\\u0269','\\u0197':'\\u0268','\\u0198':'\\u0199','\\u019C':'\\u026F','\\u019D':'\\u0272','\\u019F':'\\u0275','\\u01A0':'\\u01A1','\\u01A2':'\\u01A3','\\u01A4':'\\u01A5','\\u01A6':'\\u0280','\\u01A7':'\\u01A8','\\u01A9':'\\u0283','\\u01AC':'\\u01AD','\\u01AE':'\\u0288','\\u01AF':'\\u01B0','\\u01B1':'\\u028A','\\u01B2':'\\u028B','\\u01B3':'\\u01B4','\\u01B5':'\\u01B6','\\u01B7':'\\u0292','\\u01B8':'\\u01B9','\\u01BC':'\\u01BD','\\u01C4':'\\u01C6','\\u01C5':'\\u01C6','\\u01C7':'\\u01C9','\\u01C8':'\\u01C9','\\u01CA':'\\u01CC','\\u01CB':'\\u01CC','\\u01CD':'\\u01CE','\\u01CF':'\\u01D0','\\u01D1':'\\u01D2','\\u01D3':'\\u01D4','\\u01D5':'\\u01D6','\\u01D7':'\\u01D8','\\u01D9':'\\u01DA','\\u01DB':'\\u01DC','\\u01DE':'\\u01DF','\\u01E0':'\\u01E1','\\u01E2':'\\u01E3','\\u01E4':'\\u01E5','\\u01E6':'\\u01E7','\\u01E8':'\\u01E9','\\u01EA':'\\u01EB','\\u01EC':'\\u01ED','\\u01EE':'\\u01EF','\\u01F1':'\\u01F3','\\u01F2':'\\u01F3','\\u01F4':'\\u01F5','\\u01F6':'\\u0195','\\u01F7':'\\u01BF','\\u01F8':'\\u01F9','\\u01FA':'\\u01FB','\\u01FC':'\\u01FD','\\u01FE':'\\u01FF','\\u0200':'\\u0201','\\u0202':'\\u0203','\\u0204':'\\u0205','\\u0206':'\\u0207','\\u0208':'\\u0209','\\u020A':'\\u020B','\\u020C':'\\u020D','\\u020E':'\\u020F','\\u0210':'\\u0211','\\u0212':'\\u0213','\\u0214':'\\u0215','\\u0216':'\\u0217','\\u0218':'\\u0219','\\u021A':'\\u021B','\\u021C':'\\u021D','\\u021E':'\\u021F','\\u0220':'\\u019E','\\u0222':'\\u0223','\\u0224':'\\u0225','\\u0226':'\\u0227','\\u0228':'\\u0229','\\u022A':'\\u022B','\\u022C':'\\u022D','\\u022E':'\\u022F','\\u0230':'\\u0231','\\u0232':'\\u0233','\\u023A':'\\u2C65','\\u023B':'\\u023C','\\u023D':'\\u019A','\\u023E':'\\u2C66','\\u0241':'\\u0242','\\u0243':'\\u0180','\\u0244':'\\u0289','\\u0245':'\\u028C','\\u0246':'\\u0247','\\u0248':'\\u0249','\\u024A':'\\u024B','\\u024C':'\\u024D','\\u024E':'\\u024F','\\u0345':'\\u03B9','\\u0370':'\\u0371','\\u0372':'\\u0373','\\u0376':'\\u0377','\\u037F':'\\u03F3','\\u0386':'\\u03AC','\\u0388':'\\u03AD','\\u0389':'\\u03AE','\\u038A':'\\u03AF','\\u038C':'\\u03CC','\\u038E':'\\u03CD','\\u038F':'\\u03CE','\\u0391':'\\u03B1','\\u0392':'\\u03B2','\\u0393':'\\u03B3','\\u0394':'\\u03B4','\\u0395':'\\u03B5','\\u0396':'\\u03B6','\\u0397':'\\u03B7','\\u0398':'\\u03B8','\\u0399':'\\u03B9','\\u039A':'\\u03BA','\\u039B':'\\u03BB','\\u039C':'\\u03BC','\\u039D':'\\u03BD','\\u039E':'\\u03BE','\\u039F':'\\u03BF','\\u03A0':'\\u03C0','\\u03A1':'\\u03C1','\\u03A3':'\\u03C3','\\u03A4':'\\u03C4','\\u03A5':'\\u03C5','\\u03A6':'\\u03C6','\\u03A7':'\\u03C7','\\u03A8':'\\u03C8','\\u03A9':'\\u03C9','\\u03AA':'\\u03CA','\\u03AB':'\\u03CB','\\u03C2':'\\u03C3','\\u03CF':'\\u03D7','\\u03D0':'\\u03B2','\\u03D1':'\\u03B8','\\u03D5':'\\u03C6','\\u03D6':'\\u03C0','\\u03D8':'\\u03D9','\\u03DA':'\\u03DB','\\u03DC':'\\u03DD','\\u03DE':'\\u03DF','\\u03E0':'\\u03E1','\\u03E2':'\\u03E3','\\u03E4':'\\u03E5','\\u03E6':'\\u03E7','\\u03E8':'\\u03E9','\\u03EA':'\\u03EB','\\u03EC':'\\u03ED','\\u03EE':'\\u03EF','\\u03F0':'\\u03BA','\\u03F1':'\\u03C1','\\u03F4':'\\u03B8','\\u03F5':'\\u03B5','\\u03F7':'\\u03F8','\\u03F9':'\\u03F2','\\u03FA':'\\u03FB','\\u03FD':'\\u037B','\\u03FE':'\\u037C','\\u03FF':'\\u037D','\\u0400':'\\u0450','\\u0401':'\\u0451','\\u0402':'\\u0452','\\u0403':'\\u0453','\\u0404':'\\u0454','\\u0405':'\\u0455','\\u0406':'\\u0456','\\u0407':'\\u0457','\\u0408':'\\u0458','\\u0409':'\\u0459','\\u040A':'\\u045A','\\u040B':'\\u045B','\\u040C':'\\u045C','\\u040D':'\\u045D','\\u040E':'\\u045E','\\u040F':'\\u045F','\\u0410':'\\u0430','\\u0411':'\\u0431','\\u0412':'\\u0432','\\u0413':'\\u0433','\\u0414':'\\u0434','\\u0415':'\\u0435','\\u0416':'\\u0436','\\u0417':'\\u0437','\\u0418':'\\u0438','\\u0419':'\\u0439','\\u041A':'\\u043A','\\u041B':'\\u043B','\\u041C':'\\u043C','\\u041D':'\\u043D','\\u041E':'\\u043E','\\u041F':'\\u043F','\\u0420':'\\u0440','\\u0421':'\\u0441','\\u0422':'\\u0442','\\u0423':'\\u0443','\\u0424':'\\u0444','\\u0425':'\\u0445','\\u0426':'\\u0446','\\u0427':'\\u0447','\\u0428':'\\u0448','\\u0429':'\\u0449','\\u042A':'\\u044A','\\u042B':'\\u044B','\\u042C':'\\u044C','\\u042D':'\\u044D','\\u042E':'\\u044E','\\u042F':'\\u044F','\\u0460':'\\u0461','\\u0462':'\\u0463','\\u0464':'\\u0465','\\u0466':'\\u0467','\\u0468':'\\u0469','\\u046A':'\\u046B','\\u046C':'\\u046D','\\u046E':'\\u046F','\\u0470':'\\u0471','\\u0472':'\\u0473','\\u0474':'\\u0475','\\u0476':'\\u0477','\\u0478':'\\u0479','\\u047A':'\\u047B','\\u047C':'\\u047D','\\u047E':'\\u047F','\\u0480':'\\u0481','\\u048A':'\\u048B','\\u048C':'\\u048D','\\u048E':'\\u048F','\\u0490':'\\u0491','\\u0492':'\\u0493','\\u0494':'\\u0495','\\u0496':'\\u0497','\\u0498':'\\u0499','\\u049A':'\\u049B','\\u049C':'\\u049D','\\u049E':'\\u049F','\\u04A0':'\\u04A1','\\u04A2':'\\u04A3','\\u04A4':'\\u04A5','\\u04A6':'\\u04A7','\\u04A8':'\\u04A9','\\u04AA':'\\u04AB','\\u04AC':'\\u04AD','\\u04AE':'\\u04AF','\\u04B0':'\\u04B1','\\u04B2':'\\u04B3','\\u04B4':'\\u04B5','\\u04B6':'\\u04B7','\\u04B8':'\\u04B9','\\u04BA':'\\u04BB','\\u04BC':'\\u04BD','\\u04BE':'\\u04BF','\\u04C0':'\\u04CF','\\u04C1':'\\u04C2','\\u04C3':'\\u04C4','\\u04C5':'\\u04C6','\\u04C7':'\\u04C8','\\u04C9':'\\u04CA','\\u04CB':'\\u04CC','\\u04CD':'\\u04CE','\\u04D0':'\\u04D1','\\u04D2':'\\u04D3','\\u04D4':'\\u04D5','\\u04D6':'\\u04D7','\\u04D8':'\\u04D9','\\u04DA':'\\u04DB','\\u04DC':'\\u04DD','\\u04DE':'\\u04DF','\\u04E0':'\\u04E1','\\u04E2':'\\u04E3','\\u04E4':'\\u04E5','\\u04E6':'\\u04E7','\\u04E8':'\\u04E9','\\u04EA':'\\u04EB','\\u04EC':'\\u04ED','\\u04EE':'\\u04EF','\\u04F0':'\\u04F1','\\u04F2':'\\u04F3','\\u04F4':'\\u04F5','\\u04F6':'\\u04F7','\\u04F8':'\\u04F9','\\u04FA':'\\u04FB','\\u04FC':'\\u04FD','\\u04FE':'\\u04FF','\\u0500':'\\u0501','\\u0502':'\\u0503','\\u0504':'\\u0505','\\u0506':'\\u0507','\\u0508':'\\u0509','\\u050A':'\\u050B','\\u050C':'\\u050D','\\u050E':'\\u050F','\\u0510':'\\u0511','\\u0512':'\\u0513','\\u0514':'\\u0515','\\u0516':'\\u0517','\\u0518':'\\u0519','\\u051A':'\\u051B','\\u051C':'\\u051D','\\u051E':'\\u051F','\\u0520':'\\u0521','\\u0522':'\\u0523','\\u0524':'\\u0525','\\u0526':'\\u0527','\\u0528':'\\u0529','\\u052A':'\\u052B','\\u052C':'\\u052D','\\u052E':'\\u052F','\\u0531':'\\u0561','\\u0532':'\\u0562','\\u0533':'\\u0563','\\u0534':'\\u0564','\\u0535':'\\u0565','\\u0536':'\\u0566','\\u0537':'\\u0567','\\u0538':'\\u0568','\\u0539':'\\u0569','\\u053A':'\\u056A','\\u053B':'\\u056B','\\u053C':'\\u056C','\\u053D':'\\u056D','\\u053E':'\\u056E','\\u053F':'\\u056F','\\u0540':'\\u0570','\\u0541':'\\u0571','\\u0542':'\\u0572','\\u0543':'\\u0573','\\u0544':'\\u0574','\\u0545':'\\u0575','\\u0546':'\\u0576','\\u0547':'\\u0577','\\u0548':'\\u0578','\\u0549':'\\u0579','\\u054A':'\\u057A','\\u054B':'\\u057B','\\u054C':'\\u057C','\\u054D':'\\u057D','\\u054E':'\\u057E','\\u054F':'\\u057F','\\u0550':'\\u0580','\\u0551':'\\u0581','\\u0552':'\\u0582','\\u0553':'\\u0583','\\u0554':'\\u0584','\\u0555':'\\u0585','\\u0556':'\\u0586','\\u10A0':'\\u2D00','\\u10A1':'\\u2D01','\\u10A2':'\\u2D02','\\u10A3':'\\u2D03','\\u10A4':'\\u2D04','\\u10A5':'\\u2D05','\\u10A6':'\\u2D06','\\u10A7':'\\u2D07','\\u10A8':'\\u2D08','\\u10A9':'\\u2D09','\\u10AA':'\\u2D0A','\\u10AB':'\\u2D0B','\\u10AC':'\\u2D0C','\\u10AD':'\\u2D0D','\\u10AE':'\\u2D0E','\\u10AF':'\\u2D0F','\\u10B0':'\\u2D10','\\u10B1':'\\u2D11','\\u10B2':'\\u2D12','\\u10B3':'\\u2D13','\\u10B4':'\\u2D14','\\u10B5':'\\u2D15','\\u10B6':'\\u2D16','\\u10B7':'\\u2D17','\\u10B8':'\\u2D18','\\u10B9':'\\u2D19','\\u10BA':'\\u2D1A','\\u10BB':'\\u2D1B','\\u10BC':'\\u2D1C','\\u10BD':'\\u2D1D','\\u10BE':'\\u2D1E','\\u10BF':'\\u2D1F','\\u10C0':'\\u2D20','\\u10C1':'\\u2D21','\\u10C2':'\\u2D22','\\u10C3':'\\u2D23','\\u10C4':'\\u2D24','\\u10C5':'\\u2D25','\\u10C7':'\\u2D27','\\u10CD':'\\u2D2D','\\u1E00':'\\u1E01','\\u1E02':'\\u1E03','\\u1E04':'\\u1E05','\\u1E06':'\\u1E07','\\u1E08':'\\u1E09','\\u1E0A':'\\u1E0B','\\u1E0C':'\\u1E0D','\\u1E0E':'\\u1E0F','\\u1E10':'\\u1E11','\\u1E12':'\\u1E13','\\u1E14':'\\u1E15','\\u1E16':'\\u1E17','\\u1E18':'\\u1E19','\\u1E1A':'\\u1E1B','\\u1E1C':'\\u1E1D','\\u1E1E':'\\u1E1F','\\u1E20':'\\u1E21','\\u1E22':'\\u1E23','\\u1E24':'\\u1E25','\\u1E26':'\\u1E27','\\u1E28':'\\u1E29','\\u1E2A':'\\u1E2B','\\u1E2C':'\\u1E2D','\\u1E2E':'\\u1E2F','\\u1E30':'\\u1E31','\\u1E32':'\\u1E33','\\u1E34':'\\u1E35','\\u1E36':'\\u1E37','\\u1E38':'\\u1E39','\\u1E3A':'\\u1E3B','\\u1E3C':'\\u1E3D','\\u1E3E':'\\u1E3F','\\u1E40':'\\u1E41','\\u1E42':'\\u1E43','\\u1E44':'\\u1E45','\\u1E46':'\\u1E47','\\u1E48':'\\u1E49','\\u1E4A':'\\u1E4B','\\u1E4C':'\\u1E4D','\\u1E4E':'\\u1E4F','\\u1E50':'\\u1E51','\\u1E52':'\\u1E53','\\u1E54':'\\u1E55','\\u1E56':'\\u1E57','\\u1E58':'\\u1E59','\\u1E5A':'\\u1E5B','\\u1E5C':'\\u1E5D','\\u1E5E':'\\u1E5F','\\u1E60':'\\u1E61','\\u1E62':'\\u1E63','\\u1E64':'\\u1E65','\\u1E66':'\\u1E67','\\u1E68':'\\u1E69','\\u1E6A':'\\u1E6B','\\u1E6C':'\\u1E6D','\\u1E6E':'\\u1E6F','\\u1E70':'\\u1E71','\\u1E72':'\\u1E73','\\u1E74':'\\u1E75','\\u1E76':'\\u1E77','\\u1E78':'\\u1E79','\\u1E7A':'\\u1E7B','\\u1E7C':'\\u1E7D','\\u1E7E':'\\u1E7F','\\u1E80':'\\u1E81','\\u1E82':'\\u1E83','\\u1E84':'\\u1E85','\\u1E86':'\\u1E87','\\u1E88':'\\u1E89','\\u1E8A':'\\u1E8B','\\u1E8C':'\\u1E8D','\\u1E8E':'\\u1E8F','\\u1E90':'\\u1E91','\\u1E92':'\\u1E93','\\u1E94':'\\u1E95','\\u1E9B':'\\u1E61','\\u1EA0':'\\u1EA1','\\u1EA2':'\\u1EA3','\\u1EA4':'\\u1EA5','\\u1EA6':'\\u1EA7','\\u1EA8':'\\u1EA9','\\u1EAA':'\\u1EAB','\\u1EAC':'\\u1EAD','\\u1EAE':'\\u1EAF','\\u1EB0':'\\u1EB1','\\u1EB2':'\\u1EB3','\\u1EB4':'\\u1EB5','\\u1EB6':'\\u1EB7','\\u1EB8':'\\u1EB9','\\u1EBA':'\\u1EBB','\\u1EBC':'\\u1EBD','\\u1EBE':'\\u1EBF','\\u1EC0':'\\u1EC1','\\u1EC2':'\\u1EC3','\\u1EC4':'\\u1EC5','\\u1EC6':'\\u1EC7','\\u1EC8':'\\u1EC9','\\u1ECA':'\\u1ECB','\\u1ECC':'\\u1ECD','\\u1ECE':'\\u1ECF','\\u1ED0':'\\u1ED1','\\u1ED2':'\\u1ED3','\\u1ED4':'\\u1ED5','\\u1ED6':'\\u1ED7','\\u1ED8':'\\u1ED9','\\u1EDA':'\\u1EDB','\\u1EDC':'\\u1EDD','\\u1EDE':'\\u1EDF','\\u1EE0':'\\u1EE1','\\u1EE2':'\\u1EE3','\\u1EE4':'\\u1EE5','\\u1EE6':'\\u1EE7','\\u1EE8':'\\u1EE9','\\u1EEA':'\\u1EEB','\\u1EEC':'\\u1EED','\\u1EEE':'\\u1EEF','\\u1EF0':'\\u1EF1','\\u1EF2':'\\u1EF3','\\u1EF4':'\\u1EF5','\\u1EF6':'\\u1EF7','\\u1EF8':'\\u1EF9','\\u1EFA':'\\u1EFB','\\u1EFC':'\\u1EFD','\\u1EFE':'\\u1EFF','\\u1F08':'\\u1F00','\\u1F09':'\\u1F01','\\u1F0A':'\\u1F02','\\u1F0B':'\\u1F03','\\u1F0C':'\\u1F04','\\u1F0D':'\\u1F05','\\u1F0E':'\\u1F06','\\u1F0F':'\\u1F07','\\u1F18':'\\u1F10','\\u1F19':'\\u1F11','\\u1F1A':'\\u1F12','\\u1F1B':'\\u1F13','\\u1F1C':'\\u1F14','\\u1F1D':'\\u1F15','\\u1F28':'\\u1F20','\\u1F29':'\\u1F21','\\u1F2A':'\\u1F22','\\u1F2B':'\\u1F23','\\u1F2C':'\\u1F24','\\u1F2D':'\\u1F25','\\u1F2E':'\\u1F26','\\u1F2F':'\\u1F27','\\u1F38':'\\u1F30','\\u1F39':'\\u1F31','\\u1F3A':'\\u1F32','\\u1F3B':'\\u1F33','\\u1F3C':'\\u1F34','\\u1F3D':'\\u1F35','\\u1F3E':'\\u1F36','\\u1F3F':'\\u1F37','\\u1F48':'\\u1F40','\\u1F49':'\\u1F41','\\u1F4A':'\\u1F42','\\u1F4B':'\\u1F43','\\u1F4C':'\\u1F44','\\u1F4D':'\\u1F45','\\u1F59':'\\u1F51','\\u1F5B':'\\u1F53','\\u1F5D':'\\u1F55','\\u1F5F':'\\u1F57','\\u1F68':'\\u1F60','\\u1F69':'\\u1F61','\\u1F6A':'\\u1F62','\\u1F6B':'\\u1F63','\\u1F6C':'\\u1F64','\\u1F6D':'\\u1F65','\\u1F6E':'\\u1F66','\\u1F6F':'\\u1F67','\\u1FB8':'\\u1FB0','\\u1FB9':'\\u1FB1','\\u1FBA':'\\u1F70','\\u1FBB':'\\u1F71','\\u1FBE':'\\u03B9','\\u1FC8':'\\u1F72','\\u1FC9':'\\u1F73','\\u1FCA':'\\u1F74','\\u1FCB':'\\u1F75','\\u1FD8':'\\u1FD0','\\u1FD9':'\\u1FD1','\\u1FDA':'\\u1F76','\\u1FDB':'\\u1F77','\\u1FE8':'\\u1FE0','\\u1FE9':'\\u1FE1','\\u1FEA':'\\u1F7A','\\u1FEB':'\\u1F7B','\\u1FEC':'\\u1FE5','\\u1FF8':'\\u1F78','\\u1FF9':'\\u1F79','\\u1FFA':'\\u1F7C','\\u1FFB':'\\u1F7D','\\u2126':'\\u03C9','\\u212A':'k','\\u212B':'\\xE5','\\u2132':'\\u214E','\\u2160':'\\u2170','\\u2161':'\\u2171','\\u2162':'\\u2172','\\u2163':'\\u2173','\\u2164':'\\u2174','\\u2165':'\\u2175','\\u2166':'\\u2176','\\u2167':'\\u2177','\\u2168':'\\u2178','\\u2169':'\\u2179','\\u216A':'\\u217A','\\u216B':'\\u217B','\\u216C':'\\u217C','\\u216D':'\\u217D','\\u216E':'\\u217E','\\u216F':'\\u217F','\\u2183':'\\u2184','\\u24B6':'\\u24D0','\\u24B7':'\\u24D1','\\u24B8':'\\u24D2','\\u24B9':'\\u24D3','\\u24BA':'\\u24D4','\\u24BB':'\\u24D5','\\u24BC':'\\u24D6','\\u24BD':'\\u24D7','\\u24BE':'\\u24D8','\\u24BF':'\\u24D9','\\u24C0':'\\u24DA','\\u24C1':'\\u24DB','\\u24C2':'\\u24DC','\\u24C3':'\\u24DD','\\u24C4':'\\u24DE','\\u24C5':'\\u24DF','\\u24C6':'\\u24E0','\\u24C7':'\\u24E1','\\u24C8':'\\u24E2','\\u24C9':'\\u24E3','\\u24CA':'\\u24E4','\\u24CB':'\\u24E5','\\u24CC':'\\u24E6','\\u24CD':'\\u24E7','\\u24CE':'\\u24E8','\\u24CF':'\\u24E9','\\u2C00':'\\u2C30','\\u2C01':'\\u2C31','\\u2C02':'\\u2C32','\\u2C03':'\\u2C33','\\u2C04':'\\u2C34','\\u2C05':'\\u2C35','\\u2C06':'\\u2C36','\\u2C07':'\\u2C37','\\u2C08':'\\u2C38','\\u2C09':'\\u2C39','\\u2C0A':'\\u2C3A','\\u2C0B':'\\u2C3B','\\u2C0C':'\\u2C3C','\\u2C0D':'\\u2C3D','\\u2C0E':'\\u2C3E','\\u2C0F':'\\u2C3F','\\u2C10':'\\u2C40','\\u2C11':'\\u2C41','\\u2C12':'\\u2C42','\\u2C13':'\\u2C43','\\u2C14':'\\u2C44','\\u2C15':'\\u2C45','\\u2C16':'\\u2C46','\\u2C17':'\\u2C47','\\u2C18':'\\u2C48','\\u2C19':'\\u2C49','\\u2C1A':'\\u2C4A','\\u2C1B':'\\u2C4B','\\u2C1C':'\\u2C4C','\\u2C1D':'\\u2C4D','\\u2C1E':'\\u2C4E','\\u2C1F':'\\u2C4F','\\u2C20':'\\u2C50','\\u2C21':'\\u2C51','\\u2C22':'\\u2C52','\\u2C23':'\\u2C53','\\u2C24':'\\u2C54','\\u2C25':'\\u2C55','\\u2C26':'\\u2C56','\\u2C27':'\\u2C57','\\u2C28':'\\u2C58','\\u2C29':'\\u2C59','\\u2C2A':'\\u2C5A','\\u2C2B':'\\u2C5B','\\u2C2C':'\\u2C5C','\\u2C2D':'\\u2C5D','\\u2C2E':'\\u2C5E','\\u2C60':'\\u2C61','\\u2C62':'\\u026B','\\u2C63':'\\u1D7D','\\u2C64':'\\u027D','\\u2C67':'\\u2C68','\\u2C69':'\\u2C6A','\\u2C6B':'\\u2C6C','\\u2C6D':'\\u0251','\\u2C6E':'\\u0271','\\u2C6F':'\\u0250','\\u2C70':'\\u0252','\\u2C72':'\\u2C73','\\u2C75':'\\u2C76','\\u2C7E':'\\u023F','\\u2C7F':'\\u0240','\\u2C80':'\\u2C81','\\u2C82':'\\u2C83','\\u2C84':'\\u2C85','\\u2C86':'\\u2C87','\\u2C88':'\\u2C89','\\u2C8A':'\\u2C8B','\\u2C8C':'\\u2C8D','\\u2C8E':'\\u2C8F','\\u2C90':'\\u2C91','\\u2C92':'\\u2C93','\\u2C94':'\\u2C95','\\u2C96':'\\u2C97','\\u2C98':'\\u2C99','\\u2C9A':'\\u2C9B','\\u2C9C':'\\u2C9D','\\u2C9E':'\\u2C9F','\\u2CA0':'\\u2CA1','\\u2CA2':'\\u2CA3','\\u2CA4':'\\u2CA5','\\u2CA6':'\\u2CA7','\\u2CA8':'\\u2CA9','\\u2CAA':'\\u2CAB','\\u2CAC':'\\u2CAD','\\u2CAE':'\\u2CAF','\\u2CB0':'\\u2CB1','\\u2CB2':'\\u2CB3','\\u2CB4':'\\u2CB5','\\u2CB6':'\\u2CB7','\\u2CB8':'\\u2CB9','\\u2CBA':'\\u2CBB','\\u2CBC':'\\u2CBD','\\u2CBE':'\\u2CBF','\\u2CC0':'\\u2CC1','\\u2CC2':'\\u2CC3','\\u2CC4':'\\u2CC5','\\u2CC6':'\\u2CC7','\\u2CC8':'\\u2CC9','\\u2CCA':'\\u2CCB','\\u2CCC':'\\u2CCD','\\u2CCE':'\\u2CCF','\\u2CD0':'\\u2CD1','\\u2CD2':'\\u2CD3','\\u2CD4':'\\u2CD5','\\u2CD6':'\\u2CD7','\\u2CD8':'\\u2CD9','\\u2CDA':'\\u2CDB','\\u2CDC':'\\u2CDD','\\u2CDE':'\\u2CDF','\\u2CE0':'\\u2CE1','\\u2CE2':'\\u2CE3','\\u2CEB':'\\u2CEC','\\u2CED':'\\u2CEE','\\u2CF2':'\\u2CF3','\\uA640':'\\uA641','\\uA642':'\\uA643','\\uA644':'\\uA645','\\uA646':'\\uA647','\\uA648':'\\uA649','\\uA64A':'\\uA64B','\\uA64C':'\\uA64D','\\uA64E':'\\uA64F','\\uA650':'\\uA651','\\uA652':'\\uA653','\\uA654':'\\uA655','\\uA656':'\\uA657','\\uA658':'\\uA659','\\uA65A':'\\uA65B','\\uA65C':'\\uA65D','\\uA65E':'\\uA65F','\\uA660':'\\uA661','\\uA662':'\\uA663','\\uA664':'\\uA665','\\uA666':'\\uA667','\\uA668':'\\uA669','\\uA66A':'\\uA66B','\\uA66C':'\\uA66D','\\uA680':'\\uA681','\\uA682':'\\uA683','\\uA684':'\\uA685','\\uA686':'\\uA687','\\uA688':'\\uA689','\\uA68A':'\\uA68B','\\uA68C':'\\uA68D','\\uA68E':'\\uA68F','\\uA690':'\\uA691','\\uA692':'\\uA693','\\uA694':'\\uA695','\\uA696':'\\uA697','\\uA698':'\\uA699','\\uA69A':'\\uA69B','\\uA722':'\\uA723','\\uA724':'\\uA725','\\uA726':'\\uA727','\\uA728':'\\uA729','\\uA72A':'\\uA72B','\\uA72C':'\\uA72D','\\uA72E':'\\uA72F','\\uA732':'\\uA733','\\uA734':'\\uA735','\\uA736':'\\uA737','\\uA738':'\\uA739','\\uA73A':'\\uA73B','\\uA73C':'\\uA73D','\\uA73E':'\\uA73F','\\uA740':'\\uA741','\\uA742':'\\uA743','\\uA744':'\\uA745','\\uA746':'\\uA747','\\uA748':'\\uA749','\\uA74A':'\\uA74B','\\uA74C':'\\uA74D','\\uA74E':'\\uA74F','\\uA750':'\\uA751','\\uA752':'\\uA753','\\uA754':'\\uA755','\\uA756':'\\uA757','\\uA758':'\\uA759','\\uA75A':'\\uA75B','\\uA75C':'\\uA75D','\\uA75E':'\\uA75F','\\uA760':'\\uA761','\\uA762':'\\uA763','\\uA764':'\\uA765','\\uA766':'\\uA767','\\uA768':'\\uA769','\\uA76A':'\\uA76B','\\uA76C':'\\uA76D','\\uA76E':'\\uA76F','\\uA779':'\\uA77A','\\uA77B':'\\uA77C','\\uA77D':'\\u1D79','\\uA77E':'\\uA77F','\\uA780':'\\uA781','\\uA782':'\\uA783','\\uA784':'\\uA785','\\uA786':'\\uA787','\\uA78B':'\\uA78C','\\uA78D':'\\u0265','\\uA790':'\\uA791','\\uA792':'\\uA793','\\uA796':'\\uA797','\\uA798':'\\uA799','\\uA79A':'\\uA79B','\\uA79C':'\\uA79D','\\uA79E':'\\uA79F','\\uA7A0':'\\uA7A1','\\uA7A2':'\\uA7A3','\\uA7A4':'\\uA7A5','\\uA7A6':'\\uA7A7','\\uA7A8':'\\uA7A9','\\uA7AA':'\\u0266','\\uA7AB':'\\u025C','\\uA7AC':'\\u0261','\\uA7AD':'\\u026C','\\uA7B0':'\\u029E','\\uA7B1':'\\u0287','\\uFF21':'\\uFF41','\\uFF22':'\\uFF42','\\uFF23':'\\uFF43','\\uFF24':'\\uFF44','\\uFF25':'\\uFF45','\\uFF26':'\\uFF46','\\uFF27':'\\uFF47','\\uFF28':'\\uFF48','\\uFF29':'\\uFF49','\\uFF2A':'\\uFF4A','\\uFF2B':'\\uFF4B','\\uFF2C':'\\uFF4C','\\uFF2D':'\\uFF4D','\\uFF2E':'\\uFF4E','\\uFF2F':'\\uFF4F','\\uFF30':'\\uFF50','\\uFF31':'\\uFF51','\\uFF32':'\\uFF52','\\uFF33':'\\uFF53','\\uFF34':'\\uFF54','\\uFF35':'\\uFF55','\\uFF36':'\\uFF56','\\uFF37':'\\uFF57','\\uFF38':'\\uFF58','\\uFF39':'\\uFF59','\\uFF3A':'\\uFF5A','\\uD801\\uDC00':'\\uD801\\uDC28','\\uD801\\uDC01':'\\uD801\\uDC29','\\uD801\\uDC02':'\\uD801\\uDC2A','\\uD801\\uDC03':'\\uD801\\uDC2B','\\uD801\\uDC04':'\\uD801\\uDC2C','\\uD801\\uDC05':'\\uD801\\uDC2D','\\uD801\\uDC06':'\\uD801\\uDC2E','\\uD801\\uDC07':'\\uD801\\uDC2F','\\uD801\\uDC08':'\\uD801\\uDC30','\\uD801\\uDC09':'\\uD801\\uDC31','\\uD801\\uDC0A':'\\uD801\\uDC32','\\uD801\\uDC0B':'\\uD801\\uDC33','\\uD801\\uDC0C':'\\uD801\\uDC34','\\uD801\\uDC0D':'\\uD801\\uDC35','\\uD801\\uDC0E':'\\uD801\\uDC36','\\uD801\\uDC0F':'\\uD801\\uDC37','\\uD801\\uDC10':'\\uD801\\uDC38','\\uD801\\uDC11':'\\uD801\\uDC39','\\uD801\\uDC12':'\\uD801\\uDC3A','\\uD801\\uDC13':'\\uD801\\uDC3B','\\uD801\\uDC14':'\\uD801\\uDC3C','\\uD801\\uDC15':'\\uD801\\uDC3D','\\uD801\\uDC16':'\\uD801\\uDC3E','\\uD801\\uDC17':'\\uD801\\uDC3F','\\uD801\\uDC18':'\\uD801\\uDC40','\\uD801\\uDC19':'\\uD801\\uDC41','\\uD801\\uDC1A':'\\uD801\\uDC42','\\uD801\\uDC1B':'\\uD801\\uDC43','\\uD801\\uDC1C':'\\uD801\\uDC44','\\uD801\\uDC1D':'\\uD801\\uDC45','\\uD801\\uDC1E':'\\uD801\\uDC46','\\uD801\\uDC1F':'\\uD801\\uDC47','\\uD801\\uDC20':'\\uD801\\uDC48','\\uD801\\uDC21':'\\uD801\\uDC49','\\uD801\\uDC22':'\\uD801\\uDC4A','\\uD801\\uDC23':'\\uD801\\uDC4B','\\uD801\\uDC24':'\\uD801\\uDC4C','\\uD801\\uDC25':'\\uD801\\uDC4D','\\uD801\\uDC26':'\\uD801\\uDC4E','\\uD801\\uDC27':'\\uD801\\uDC4F','\\uD806\\uDCA0':'\\uD806\\uDCC0','\\uD806\\uDCA1':'\\uD806\\uDCC1','\\uD806\\uDCA2':'\\uD806\\uDCC2','\\uD806\\uDCA3':'\\uD806\\uDCC3','\\uD806\\uDCA4':'\\uD806\\uDCC4','\\uD806\\uDCA5':'\\uD806\\uDCC5','\\uD806\\uDCA6':'\\uD806\\uDCC6','\\uD806\\uDCA7':'\\uD806\\uDCC7','\\uD806\\uDCA8':'\\uD806\\uDCC8','\\uD806\\uDCA9':'\\uD806\\uDCC9','\\uD806\\uDCAA':'\\uD806\\uDCCA','\\uD806\\uDCAB':'\\uD806\\uDCCB','\\uD806\\uDCAC':'\\uD806\\uDCCC','\\uD806\\uDCAD':'\\uD806\\uDCCD','\\uD806\\uDCAE':'\\uD806\\uDCCE','\\uD806\\uDCAF':'\\uD806\\uDCCF','\\uD806\\uDCB0':'\\uD806\\uDCD0','\\uD806\\uDCB1':'\\uD806\\uDCD1','\\uD806\\uDCB2':'\\uD806\\uDCD2','\\uD806\\uDCB3':'\\uD806\\uDCD3','\\uD806\\uDCB4':'\\uD806\\uDCD4','\\uD806\\uDCB5':'\\uD806\\uDCD5','\\uD806\\uDCB6':'\\uD806\\uDCD6','\\uD806\\uDCB7':'\\uD806\\uDCD7','\\uD806\\uDCB8':'\\uD806\\uDCD8','\\uD806\\uDCB9':'\\uD806\\uDCD9','\\uD806\\uDCBA':'\\uD806\\uDCDA','\\uD806\\uDCBB':'\\uD806\\uDCDB','\\uD806\\uDCBC':'\\uD806\\uDCDC','\\uD806\\uDCBD':'\\uD806\\uDCDD','\\uD806\\uDCBE':'\\uD806\\uDCDE','\\uD806\\uDCBF':'\\uD806\\uDCDF','\\xDF':'ss','\\u0130':'i\\u0307','\\u0149':'\\u02BCn','\\u01F0':'j\\u030C','\\u0390':'\\u03B9\\u0308\\u0301','\\u03B0':'\\u03C5\\u0308\\u0301','\\u0587':'\\u0565\\u0582','\\u1E96':'h\\u0331','\\u1E97':'t\\u0308','\\u1E98':'w\\u030A','\\u1E99':'y\\u030A','\\u1E9A':'a\\u02BE','\\u1E9E':'ss','\\u1F50':'\\u03C5\\u0313','\\u1F52':'\\u03C5\\u0313\\u0300','\\u1F54':'\\u03C5\\u0313\\u0301','\\u1F56':'\\u03C5\\u0313\\u0342','\\u1F80':'\\u1F00\\u03B9','\\u1F81':'\\u1F01\\u03B9','\\u1F82':'\\u1F02\\u03B9','\\u1F83':'\\u1F03\\u03B9','\\u1F84':'\\u1F04\\u03B9','\\u1F85':'\\u1F05\\u03B9','\\u1F86':'\\u1F06\\u03B9','\\u1F87':'\\u1F07\\u03B9','\\u1F88':'\\u1F00\\u03B9','\\u1F89':'\\u1F01\\u03B9','\\u1F8A':'\\u1F02\\u03B9','\\u1F8B':'\\u1F03\\u03B9','\\u1F8C':'\\u1F04\\u03B9','\\u1F8D':'\\u1F05\\u03B9','\\u1F8E':'\\u1F06\\u03B9','\\u1F8F':'\\u1F07\\u03B9','\\u1F90':'\\u1F20\\u03B9','\\u1F91':'\\u1F21\\u03B9','\\u1F92':'\\u1F22\\u03B9','\\u1F93':'\\u1F23\\u03B9','\\u1F94':'\\u1F24\\u03B9','\\u1F95':'\\u1F25\\u03B9','\\u1F96':'\\u1F26\\u03B9','\\u1F97':'\\u1F27\\u03B9','\\u1F98':'\\u1F20\\u03B9','\\u1F99':'\\u1F21\\u03B9','\\u1F9A':'\\u1F22\\u03B9','\\u1F9B':'\\u1F23\\u03B9','\\u1F9C':'\\u1F24\\u03B9','\\u1F9D':'\\u1F25\\u03B9','\\u1F9E':'\\u1F26\\u03B9','\\u1F9F':'\\u1F27\\u03B9','\\u1FA0':'\\u1F60\\u03B9','\\u1FA1':'\\u1F61\\u03B9','\\u1FA2':'\\u1F62\\u03B9','\\u1FA3':'\\u1F63\\u03B9','\\u1FA4':'\\u1F64\\u03B9','\\u1FA5':'\\u1F65\\u03B9','\\u1FA6':'\\u1F66\\u03B9','\\u1FA7':'\\u1F67\\u03B9','\\u1FA8':'\\u1F60\\u03B9','\\u1FA9':'\\u1F61\\u03B9','\\u1FAA':'\\u1F62\\u03B9','\\u1FAB':'\\u1F63\\u03B9','\\u1FAC':'\\u1F64\\u03B9','\\u1FAD':'\\u1F65\\u03B9','\\u1FAE':'\\u1F66\\u03B9','\\u1FAF':'\\u1F67\\u03B9','\\u1FB2':'\\u1F70\\u03B9','\\u1FB3':'\\u03B1\\u03B9','\\u1FB4':'\\u03AC\\u03B9','\\u1FB6':'\\u03B1\\u0342','\\u1FB7':'\\u03B1\\u0342\\u03B9','\\u1FBC':'\\u03B1\\u03B9','\\u1FC2':'\\u1F74\\u03B9','\\u1FC3':'\\u03B7\\u03B9','\\u1FC4':'\\u03AE\\u03B9','\\u1FC6':'\\u03B7\\u0342','\\u1FC7':'\\u03B7\\u0342\\u03B9','\\u1FCC':'\\u03B7\\u03B9','\\u1FD2':'\\u03B9\\u0308\\u0300','\\u1FD3':'\\u03B9\\u0308\\u0301','\\u1FD6':'\\u03B9\\u0342','\\u1FD7':'\\u03B9\\u0308\\u0342','\\u1FE2':'\\u03C5\\u0308\\u0300','\\u1FE3':'\\u03C5\\u0308\\u0301','\\u1FE4':'\\u03C1\\u0313','\\u1FE6':'\\u03C5\\u0342','\\u1FE7':'\\u03C5\\u0308\\u0342','\\u1FF2':'\\u1F7C\\u03B9','\\u1FF3':'\\u03C9\\u03B9','\\u1FF4':'\\u03CE\\u03B9','\\u1FF6':'\\u03C9\\u0342','\\u1FF7':'\\u03C9\\u0342\\u03B9','\\u1FFC':'\\u03C9\\u03B9','\\uFB00':'ff','\\uFB01':'fi','\\uFB02':'fl','\\uFB03':'ffi','\\uFB04':'ffl','\\uFB05':'st','\\uFB06':'st','\\uFB13':'\\u0574\\u0576','\\uFB14':'\\u0574\\u0565','\\uFB15':'\\u0574\\u056B','\\uFB16':'\\u057E\\u0576','\\uFB17':'\\u0574\\u056D'};\n\n// Normalize reference label: collapse internal whitespace\n// to single space, remove leading/trailing whitespace, case fold.\nmodule.exports = function(string) {\n return string.slice(1, string.length - 1).trim().replace(regex, function($0) {\n // Note: there is no need to check `hasOwnProperty($0)` here.\n // If character not found in lookup table, it must be whitespace.\n return map[$0] || ' ';\n });\n};\n","\"use strict\";\n\n// derived from https://github.com/mathiasbynens/String.fromCodePoint\n/*! http://mths.be/fromcodepoint v0.2.1 by @mathias */\nif (String.fromCodePoint) {\n module.exports = function (_) {\n try {\n return String.fromCodePoint(_);\n } catch (e) {\n if (e instanceof RangeError) {\n return String.fromCharCode(0xFFFD);\n }\n throw e;\n }\n };\n\n} else {\n\n var stringFromCharCode = String.fromCharCode;\n var floor = Math.floor;\n var fromCodePoint = function() {\n var MAX_SIZE = 0x4000;\n var codeUnits = [];\n var highSurrogate;\n var lowSurrogate;\n var index = -1;\n var length = arguments.length;\n if (!length) {\n return '';\n }\n var result = '';\n while (++index < length) {\n var codePoint = Number(arguments[index]);\n if (\n !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`\n codePoint < 0 || // not a valid Unicode code point\n codePoint > 0x10FFFF || // not a valid Unicode code point\n floor(codePoint) !== codePoint // not an integer\n ) {\n return String.fromCharCode(0xFFFD);\n }\n if (codePoint <= 0xFFFF) { // BMP code point\n codeUnits.push(codePoint);\n } else { // Astral code point; split in surrogate halves\n // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n codePoint -= 0x10000;\n highSurrogate = (codePoint >> 10) + 0xD800;\n lowSurrogate = (codePoint % 0x400) + 0xDC00;\n codeUnits.push(highSurrogate, lowSurrogate);\n }\n if (index + 1 === length || codeUnits.length > MAX_SIZE) {\n result += stringFromCharCode.apply(null, codeUnits);\n codeUnits.length = 0;\n }\n }\n return result;\n };\n module.exports = fromCodePoint;\n}\n","/*! http://mths.be/repeat v0.2.0 by @mathias */\nif (!String.prototype.repeat) {\n\t(function() {\n\t\t'use strict'; // needed to support `apply`/`call` with `undefined`/`null`\n\t\tvar defineProperty = (function() {\n\t\t\t// IE 8 only supports `Object.defineProperty` on DOM elements\n\t\t\ttry {\n\t\t\t\tvar object = {};\n\t\t\t\tvar $defineProperty = Object.defineProperty;\n\t\t\t\tvar result = $defineProperty(object, object, object) && $defineProperty;\n\t\t\t} catch(error) {}\n\t\t\treturn result;\n\t\t}());\n\t\tvar repeat = function(count) {\n\t\t\tif (this == null) {\n\t\t\t\tthrow TypeError();\n\t\t\t}\n\t\t\tvar string = String(this);\n\t\t\t// `ToInteger`\n\t\t\tvar n = count ? Number(count) : 0;\n\t\t\tif (n != n) { // better `isNaN`\n\t\t\t\tn = 0;\n\t\t\t}\n\t\t\t// Account for out-of-bounds indices\n\t\t\tif (n < 0 || n == Infinity) {\n\t\t\t\tthrow RangeError();\n\t\t\t}\n\t\t\tvar result = '';\n\t\t\twhile (n) {\n\t\t\t\tif (n % 2 == 1) {\n\t\t\t\t\tresult += string;\n\t\t\t\t}\n\t\t\t\tif (n > 1) {\n\t\t\t\t\tstring += string;\n\t\t\t\t}\n\t\t\t\tn >>= 1;\n\t\t\t}\n\t\t\treturn result;\n\t\t};\n\t\tif (defineProperty) {\n\t\t\tdefineProperty(String.prototype, 'repeat', {\n\t\t\t\t'value': repeat,\n\t\t\t\t'configurable': true,\n\t\t\t\t'writable': true\n\t\t\t});\n\t\t} else {\n\t\t\tString.prototype.repeat = repeat;\n\t\t}\n\t}());\n}\n","\"use strict\";\n\nvar Node = require('./node');\nvar common = require('./common');\nvar normalizeReference = require('./normalize-reference');\n\nvar normalizeURI = common.normalizeURI;\nvar unescapeString = common.unescapeString;\nvar fromCodePoint = require('./from-code-point.js');\nvar decodeHTML = require('entities').decodeHTML;\nrequire('string.prototype.repeat'); // Polyfill for String.prototype.repeat\n\n// Constants for character codes:\n\nvar C_NEWLINE = 10;\nvar C_ASTERISK = 42;\nvar C_UNDERSCORE = 95;\nvar C_BACKTICK = 96;\nvar C_OPEN_BRACKET = 91;\nvar C_CLOSE_BRACKET = 93;\nvar C_LESSTHAN = 60;\nvar C_BANG = 33;\nvar C_BACKSLASH = 92;\nvar C_AMPERSAND = 38;\nvar C_OPEN_PAREN = 40;\nvar C_CLOSE_PAREN = 41;\nvar C_COLON = 58;\nvar C_SINGLEQUOTE = 39;\nvar C_DOUBLEQUOTE = 34;\n\n// Some regexps used in inline parser:\n\nvar ESCAPABLE = common.ESCAPABLE;\nvar ESCAPED_CHAR = '\\\\\\\\' + ESCAPABLE;\nvar REG_CHAR = '[^\\\\\\\\()\\\\x00-\\\\x20]';\nvar IN_PARENS_NOSP = '\\\\((' + REG_CHAR + '|' + ESCAPED_CHAR + '|\\\\\\\\)*\\\\)';\n\nvar ENTITY = common.ENTITY;\nvar reHtmlTag = common.reHtmlTag;\n\nvar rePunctuation = new RegExp(/^[\\u2000-\\u206F\\u2E00-\\u2E7F\\\\'!\"#\\$%&\\(\\)\\*\\+,\\-\\.\\/:;<=>\\?@\\[\\]\\^_`\\{\\|\\}~]/);\n\nvar reLinkTitle = new RegExp(\n '^(?:\"(' + ESCAPED_CHAR + '|[^\"\\\\x00])*\"' +\n '|' +\n '\\'(' + ESCAPED_CHAR + '|[^\\'\\\\x00])*\\'' +\n '|' +\n '\\\\((' + ESCAPED_CHAR + '|[^)\\\\x00])*\\\\))');\n\nvar reLinkDestinationBraces = new RegExp(\n '^(?:[<](?:[^ <>\\\\t\\\\n\\\\\\\\\\\\x00]' + '|' + ESCAPED_CHAR + '|' + '\\\\\\\\)*[>])');\n\nvar reLinkDestination = new RegExp(\n '^(?:' + REG_CHAR + '+|' + ESCAPED_CHAR + '|\\\\\\\\|' + IN_PARENS_NOSP + ')*');\n\nvar reEscapable = new RegExp('^' + ESCAPABLE);\n\nvar reEntityHere = new RegExp('^' + ENTITY, 'i');\n\nvar reTicks = /`+/;\n\nvar reTicksHere = /^`+/;\n\nvar reEllipses = /\\.\\.\\./g;\n\nvar reDash = /--+/g;\n\nvar reEmailAutolink = /^<([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/;\n\nvar reAutolink = /^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\\x00-\\x20]*>/i;\n\nvar reSpnl = /^ *(?:\\n *)?/;\n\nvar reWhitespaceChar = /^\\s/;\n\nvar reWhitespace = /\\s+/g;\n\nvar reFinalSpace = / *$/;\n\nvar reInitialSpace = /^ */;\n\nvar reSpaceAtEndOfLine = /^ *(?:\\n|$)/;\n\nvar reLinkLabel = new RegExp('^\\\\[(?:[^\\\\\\\\\\\\[\\\\]]|' + ESCAPED_CHAR +\n '|\\\\\\\\){0,1000}\\\\]');\n\n// Matches a string of non-special characters.\nvar reMain = /^[^\\n`\\[\\]\\\\!<&*_'\"]+/m;\n\nvar text = function(s) {\n var node = new Node('Text');\n node._literal = s;\n return node;\n};\n\n// INLINE PARSER\n\n// These are methods of an InlineParser object, defined below.\n// An InlineParser keeps track of a subject (a string to be\n// parsed) and a position in that subject.\n\n// If re matches at current position in the subject, advance\n// position in subject and return the match; otherwise return null.\nvar match = function(re) {\n var m = re.exec(this.subject.slice(this.pos));\n if (m === null) {\n return null;\n } else {\n this.pos += m.index + m[0].length;\n return m[0];\n }\n};\n\n// Returns the code for the character at the current subject position, or -1\n// there are no more characters.\nvar peek = function() {\n if (this.pos < this.subject.length) {\n return this.subject.charCodeAt(this.pos);\n } else {\n return -1;\n }\n};\n\n// Parse zero or more space characters, including at most one newline\nvar spnl = function() {\n this.match(reSpnl);\n return true;\n};\n\n// All of the parsers below try to match something at the current position\n// in the subject. If they succeed in matching anything, they\n// return the inline matched, advancing the subject.\n\n// Attempt to parse backticks, adding either a backtick code span or a\n// literal sequence of backticks.\nvar parseBackticks = function(block) {\n var ticks = this.match(reTicksHere);\n if (ticks === null) {\n return false;\n }\n var afterOpenTicks = this.pos;\n var matched;\n var node;\n while ((matched = this.match(reTicks)) !== null) {\n if (matched === ticks) {\n node = new Node('Code');\n node._literal = this.subject.slice(afterOpenTicks,\n this.pos - ticks.length)\n .trim().replace(reWhitespace, ' ');\n block.appendChild(node);\n return true;\n }\n }\n // If we got here, we didn't match a closing backtick sequence.\n this.pos = afterOpenTicks;\n block.appendChild(text(ticks));\n return true;\n};\n\n// Parse a backslash-escaped special character, adding either the escaped\n// character, a hard line break (if the backslash is followed by a newline),\n// or a literal backslash to the block's children. Assumes current character\n// is a backslash.\nvar parseBackslash = function(block) {\n var subj = this.subject;\n var node;\n this.pos += 1;\n if (this.peek() === C_NEWLINE) {\n this.pos += 1;\n node = new Node('Hardbreak');\n block.appendChild(node);\n } else if (reEscapable.test(subj.charAt(this.pos))) {\n block.appendChild(text(subj.charAt(this.pos)));\n this.pos += 1;\n } else {\n block.appendChild(text('\\\\'));\n }\n return true;\n};\n\n// Attempt to parse an autolink (URL or email in pointy brackets).\nvar parseAutolink = function(block) {\n var m;\n var dest;\n var node;\n if ((m = this.match(reEmailAutolink))) {\n dest = m.slice(1, m.length - 1);\n node = new Node('Link');\n node._destination = normalizeURI('mailto:' + dest);\n node._title = '';\n node.appendChild(text(dest));\n block.appendChild(node);\n return true;\n } else if ((m = this.match(reAutolink))) {\n dest = m.slice(1, m.length - 1);\n node = new Node('Link');\n node._destination = normalizeURI(dest);\n node._title = '';\n node.appendChild(text(dest));\n block.appendChild(node);\n return true;\n } else {\n return false;\n }\n};\n\n// Attempt to parse a raw HTML tag.\nvar parseHtmlTag = function(block) {\n var m = this.match(reHtmlTag);\n if (m === null) {\n return false;\n } else {\n var node = new Node('HtmlInline');\n node._literal = m;\n block.appendChild(node);\n return true;\n }\n};\n\n// Scan a sequence of characters with code cc, and return information about\n// the number of delimiters and whether they are positioned such that\n// they can open and/or close emphasis or strong emphasis. A utility\n// function for strong/emph parsing.\nvar scanDelims = function(cc) {\n var numdelims = 0;\n var char_before, char_after, cc_after;\n var startpos = this.pos;\n var left_flanking, right_flanking, can_open, can_close;\n var after_is_whitespace, after_is_punctuation, before_is_whitespace, before_is_punctuation;\n\n if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) {\n numdelims++;\n this.pos++;\n } else {\n while (this.peek() === cc) {\n numdelims++;\n this.pos++;\n }\n }\n\n if (numdelims === 0) {\n return null;\n }\n\n char_before = startpos === 0 ? '\\n' : this.subject.charAt(startpos - 1);\n\n cc_after = this.peek();\n if (cc_after === -1) {\n char_after = '\\n';\n } else {\n char_after = fromCodePoint(cc_after);\n }\n\n after_is_whitespace = reWhitespaceChar.test(char_after);\n after_is_punctuation = rePunctuation.test(char_after);\n before_is_whitespace = reWhitespaceChar.test(char_before);\n before_is_punctuation = rePunctuation.test(char_before);\n\n left_flanking = !after_is_whitespace &&\n !(after_is_punctuation && !before_is_whitespace && !before_is_punctuation);\n right_flanking = !before_is_whitespace &&\n !(before_is_punctuation && !after_is_whitespace && !after_is_punctuation);\n if (cc === C_UNDERSCORE) {\n can_open = left_flanking &&\n (!right_flanking || before_is_punctuation);\n can_close = right_flanking &&\n (!left_flanking || after_is_punctuation);\n } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) {\n can_open = left_flanking && !right_flanking;\n can_close = right_flanking;\n } else {\n can_open = left_flanking;\n can_close = right_flanking;\n }\n this.pos = startpos;\n return { numdelims: numdelims,\n can_open: can_open,\n can_close: can_close };\n};\n\n// Handle a delimiter marker for emphasis or a quote.\nvar handleDelim = function(cc, block) {\n var res = this.scanDelims(cc);\n if (!res) {\n return false;\n }\n var numdelims = res.numdelims;\n var startpos = this.pos;\n var contents;\n\n this.pos += numdelims;\n if (cc === C_SINGLEQUOTE) {\n contents = \"\\u2019\";\n } else if (cc === C_DOUBLEQUOTE) {\n contents = \"\\u201C\";\n } else {\n contents = this.subject.slice(startpos, this.pos);\n }\n var node = text(contents);\n block.appendChild(node);\n\n // Add entry to stack for this opener\n this.delimiters = { cc: cc,\n numdelims: numdelims,\n node: node,\n previous: this.delimiters,\n next: null,\n can_open: res.can_open,\n can_close: res.can_close,\n active: true };\n if (this.delimiters.previous !== null) {\n this.delimiters.previous.next = this.delimiters;\n }\n\n return true;\n\n};\n\nvar removeDelimiter = function(delim) {\n if (delim.previous !== null) {\n delim.previous.next = delim.next;\n }\n if (delim.next === null) {\n // top of stack\n this.delimiters = delim.previous;\n } else {\n delim.next.previous = delim.previous;\n }\n};\n\nvar removeDelimitersBetween = function(bottom, top) {\n if (bottom.next !== top) {\n bottom.next = top;\n top.previous = bottom;\n }\n};\n\nvar processEmphasis = function(stack_bottom) {\n var opener, closer, old_closer;\n var opener_inl, closer_inl;\n var tempstack;\n var use_delims;\n var tmp, next;\n var opener_found;\n var openers_bottom = [];\n\n openers_bottom[C_UNDERSCORE] = stack_bottom;\n openers_bottom[C_ASTERISK] = stack_bottom;\n openers_bottom[C_SINGLEQUOTE] = stack_bottom;\n openers_bottom[C_DOUBLEQUOTE] = stack_bottom;\n\n // find first closer above stack_bottom:\n closer = this.delimiters;\n while (closer !== null && closer.previous !== stack_bottom) {\n closer = closer.previous;\n }\n // move forward, looking for closers, and handling each\n while (closer !== null) {\n var closercc = closer.cc;\n if (!(closer.can_close && (closercc === C_UNDERSCORE ||\n closercc === C_ASTERISK ||\n closercc === C_SINGLEQUOTE ||\n closercc === C_DOUBLEQUOTE))) {\n closer = closer.next;\n } else {\n // found emphasis closer. now look back for first matching opener:\n opener = closer.previous;\n opener_found = false;\n while (opener !== null && opener !== stack_bottom &&\n opener !== openers_bottom[closercc]) {\n if (opener.cc === closer.cc && opener.can_open) {\n opener_found = true;\n break;\n }\n opener = opener.previous;\n }\n old_closer = closer;\n\n if (closercc === C_ASTERISK || closercc === C_UNDERSCORE) {\n if (!opener_found) {\n closer = closer.next;\n } else {\n // calculate actual number of delimiters used from closer\n if (closer.numdelims < 3 || opener.numdelims < 3) {\n use_delims = closer.numdelims <= opener.numdelims ?\n closer.numdelims : opener.numdelims;\n } else {\n use_delims = closer.numdelims % 2 === 0 ? 2 : 1;\n }\n\n opener_inl = opener.node;\n closer_inl = closer.node;\n\n // remove used delimiters from stack elts and inlines\n opener.numdelims -= use_delims;\n closer.numdelims -= use_delims;\n opener_inl._literal =\n opener_inl._literal.slice(0,\n opener_inl._literal.length - use_delims);\n closer_inl._literal =\n closer_inl._literal.slice(0,\n closer_inl._literal.length - use_delims);\n\n // build contents for new emph element\n var emph = new Node(use_delims === 1 ? 'Emph' : 'Strong');\n\n tmp = opener_inl._next;\n while (tmp && tmp !== closer_inl) {\n next = tmp._next;\n tmp.unlink();\n emph.appendChild(tmp);\n tmp = next;\n }\n\n opener_inl.insertAfter(emph);\n\n // remove elts between opener and closer in delimiters stack\n removeDelimitersBetween(opener, closer);\n\n // if opener has 0 delims, remove it and the inline\n if (opener.numdelims === 0) {\n opener_inl.unlink();\n this.removeDelimiter(opener);\n }\n\n if (closer.numdelims === 0) {\n closer_inl.unlink();\n tempstack = closer.next;\n this.removeDelimiter(closer);\n closer = tempstack;\n }\n\n }\n\n } else if (closercc === C_SINGLEQUOTE) {\n closer.node._literal = \"\\u2019\";\n if (opener_found) {\n opener.node._literal = \"\\u2018\";\n }\n closer = closer.next;\n\n } else if (closercc === C_DOUBLEQUOTE) {\n closer.node._literal = \"\\u201D\";\n if (opener_found) {\n opener.node.literal = \"\\u201C\";\n }\n closer = closer.next;\n\n }\n if (!opener_found) {\n // Set lower bound for future searches for openers:\n openers_bottom[closercc] = old_closer.previous;\n if (!old_closer.can_open) {\n // We can remove a closer that can't be an opener,\n // once we've seen there's no matching opener:\n this.removeDelimiter(old_closer);\n }\n }\n }\n\n }\n\n // remove all delimiters\n while (this.delimiters !== null && this.delimiters !== stack_bottom) {\n this.removeDelimiter(this.delimiters);\n }\n};\n\n// Attempt to parse link title (sans quotes), returning the string\n// or null if no match.\nvar parseLinkTitle = function() {\n var title = this.match(reLinkTitle);\n if (title === null) {\n return null;\n } else {\n // chop off quotes from title and unescape:\n return unescapeString(title.substr(1, title.length - 2));\n }\n};\n\n// Attempt to parse link destination, returning the string or\n// null if no match.\nvar parseLinkDestination = function() {\n var res = this.match(reLinkDestinationBraces);\n if (res === null) {\n res = this.match(reLinkDestination);\n if (res === null) {\n return null;\n } else {\n return normalizeURI(unescapeString(res));\n }\n } else { // chop off surrounding <..>:\n return normalizeURI(unescapeString(res.substr(1, res.length - 2)));\n }\n};\n\n// Attempt to parse a link label, returning number of characters parsed.\nvar parseLinkLabel = function() {\n var m = this.match(reLinkLabel);\n if (m === null || m.length > 1001) {\n return 0;\n } else {\n return m.length;\n }\n};\n\n// Add open bracket to delimiter stack and add a text node to block's children.\nvar parseOpenBracket = function(block) {\n var startpos = this.pos;\n this.pos += 1;\n\n var node = text('[');\n block.appendChild(node);\n\n // Add entry to stack for this opener\n this.delimiters = { cc: C_OPEN_BRACKET,\n numdelims: 1,\n node: node,\n previous: this.delimiters,\n next: null,\n can_open: true,\n can_close: false,\n index: startpos,\n active: true };\n if (this.delimiters.previous !== null) {\n this.delimiters.previous.next = this.delimiters;\n }\n\n return true;\n\n};\n\n// IF next character is [, and ! delimiter to delimiter stack and\n// add a text node to block's children. Otherwise just add a text node.\nvar parseBang = function(block) {\n var startpos = this.pos;\n this.pos += 1;\n if (this.peek() === C_OPEN_BRACKET) {\n this.pos += 1;\n\n var node = text('![');\n block.appendChild(node);\n\n // Add entry to stack for this opener\n this.delimiters = { cc: C_BANG,\n numdelims: 1,\n node: node,\n previous: this.delimiters,\n next: null,\n can_open: true,\n can_close: false,\n index: startpos + 1,\n active: true };\n if (this.delimiters.previous !== null) {\n this.delimiters.previous.next = this.delimiters;\n }\n } else {\n block.appendChild(text('!'));\n }\n return true;\n};\n\n// Try to match close bracket against an opening in the delimiter\n// stack. Add either a link or image, or a plain [ character,\n// to block's children. If there is a matching delimiter,\n// remove it from the delimiter stack.\nvar parseCloseBracket = function(block) {\n var startpos;\n var is_image;\n var dest;\n var title;\n var matched = false;\n var reflabel;\n var opener;\n\n this.pos += 1;\n startpos = this.pos;\n\n // look through stack of delimiters for a [ or ![\n opener = this.delimiters;\n\n while (opener !== null) {\n if (opener.cc === C_OPEN_BRACKET || opener.cc === C_BANG) {\n break;\n }\n opener = opener.previous;\n }\n\n if (opener === null) {\n // no matched opener, just return a literal\n block.appendChild(text(']'));\n return true;\n }\n\n if (!opener.active) {\n // no matched opener, just return a literal\n block.appendChild(text(']'));\n // take opener off emphasis stack\n this.removeDelimiter(opener);\n return true;\n }\n\n // If we got here, open is a potential opener\n is_image = opener.cc === C_BANG;\n\n // Check to see if we have a link/image\n\n // Inline link?\n if (this.peek() === C_OPEN_PAREN) {\n this.pos++;\n if (this.spnl() &&\n ((dest = this.parseLinkDestination()) !== null) &&\n this.spnl() &&\n // make sure there's a space before the title:\n (reWhitespaceChar.test(this.subject.charAt(this.pos - 1)) &&\n (title = this.parseLinkTitle()) || true) &&\n this.spnl() &&\n this.peek() === C_CLOSE_PAREN) {\n this.pos += 1;\n matched = true;\n }\n } else {\n\n // Next, see if there's a link label\n var savepos = this.pos;\n var beforelabel = this.pos;\n var n = this.parseLinkLabel();\n if (n === 0 || n === 2) {\n // empty or missing second label\n reflabel = this.subject.slice(opener.index, startpos);\n } else {\n reflabel = this.subject.slice(beforelabel, beforelabel + n);\n }\n if (n === 0) {\n // If shortcut reference link, rewind before spaces we skipped.\n this.pos = savepos;\n }\n\n // lookup rawlabel in refmap\n var link = this.refmap[normalizeReference(reflabel)];\n if (link) {\n dest = link.destination;\n title = link.title;\n matched = true;\n }\n }\n\n if (matched) {\n var node = new Node(is_image ? 'Image' : 'Link');\n node._destination = dest;\n node._title = title || '';\n\n var tmp, next;\n tmp = opener.node._next;\n while (tmp) {\n next = tmp._next;\n tmp.unlink();\n node.appendChild(tmp);\n tmp = next;\n }\n block.appendChild(node);\n this.processEmphasis(opener.previous);\n\n opener.node.unlink();\n\n // processEmphasis will remove this and later delimiters.\n // Now, for a link, we also deactivate earlier link openers.\n // (no links in links)\n if (!is_image) {\n opener = this.delimiters;\n while (opener !== null) {\n if (opener.cc === C_OPEN_BRACKET) {\n opener.active = false; // deactivate this opener\n }\n opener = opener.previous;\n }\n }\n\n return true;\n\n } else { // no match\n\n this.removeDelimiter(opener); // remove this opener from stack\n this.pos = startpos;\n block.appendChild(text(']'));\n return true;\n }\n\n};\n\n// Attempt to parse an entity.\nvar parseEntity = function(block) {\n var m;\n if ((m = this.match(reEntityHere))) {\n block.appendChild(text(decodeHTML(m)));\n return true;\n } else {\n return false;\n }\n};\n\n// Parse a run of ordinary characters, or a single character with\n// a special meaning in markdown, as a plain string.\nvar parseString = function(block) {\n var m;\n if ((m = this.match(reMain))) {\n if (this.options.smart) {\n block.appendChild(text(\n m.replace(reEllipses, \"\\u2026\")\n .replace(reDash, function(chars) {\n var enCount = 0;\n var emCount = 0;\n if (chars.length % 3 === 0) { // If divisible by 3, use all em dashes\n emCount = chars.length / 3;\n } else if (chars.length % 2 === 0) { // If divisible by 2, use all en dashes\n enCount = chars.length / 2;\n } else if (chars.length % 3 === 2) { // If 2 extra dashes, use en dash for last 2; em dashes for rest\n enCount = 1;\n emCount = (chars.length - 2) / 3;\n } else { // Use en dashes for last 4 hyphens; em dashes for rest\n enCount = 2;\n emCount = (chars.length - 4) / 3;\n }\n return \"\\u2014\".repeat(emCount) + \"\\u2013\".repeat(enCount);\n })));\n } else {\n block.appendChild(text(m));\n }\n return true;\n } else {\n return false;\n }\n};\n\n// Parse a newline. If it was preceded by two spaces, return a hard\n// line break; otherwise a soft line break.\nvar parseNewline = function(block) {\n this.pos += 1; // assume we're at a \\n\n // check previous node for trailing spaces\n var lastc = block._lastChild;\n if (lastc && lastc.type === 'Text' && lastc._literal[lastc._literal.length - 1] === ' ') {\n var hardbreak = lastc._literal[lastc._literal.length - 2] === ' ';\n lastc._literal = lastc._literal.replace(reFinalSpace, '');\n block.appendChild(new Node(hardbreak ? 'Hardbreak' : 'Softbreak'));\n } else {\n block.appendChild(new Node('Softbreak'));\n }\n this.match(reInitialSpace); // gobble leading spaces in next line\n return true;\n};\n\n// Attempt to parse a link reference, modifying refmap.\nvar parseReference = function(s, refmap) {\n this.subject = s;\n this.pos = 0;\n var rawlabel;\n var dest;\n var title;\n var matchChars;\n var startpos = this.pos;\n\n // label:\n matchChars = this.parseLinkLabel();\n if (matchChars === 0) {\n return 0;\n } else {\n rawlabel = this.subject.substr(0, matchChars);\n }\n\n // colon:\n if (this.peek() === C_COLON) {\n this.pos++;\n } else {\n this.pos = startpos;\n return 0;\n }\n\n // link url\n this.spnl();\n\n dest = this.parseLinkDestination();\n if (dest === null || dest.length === 0) {\n this.pos = startpos;\n return 0;\n }\n\n var beforetitle = this.pos;\n this.spnl();\n title = this.parseLinkTitle();\n if (title === null) {\n title = '';\n // rewind before spaces\n this.pos = beforetitle;\n }\n\n // make sure we're at line end:\n var atLineEnd = true;\n if (this.match(reSpaceAtEndOfLine) === null) {\n if (title === '') {\n atLineEnd = false;\n } else {\n // the potential title we found is not at the line end,\n // but it could still be a legal link reference if we\n // discard the title\n title = '';\n // rewind before spaces\n this.pos = beforetitle;\n // and instead check if the link URL is at the line end\n atLineEnd = this.match(reSpaceAtEndOfLine) !== null;\n }\n }\n\n if (!atLineEnd) {\n this.pos = startpos;\n return 0;\n }\n\n var normlabel = normalizeReference(rawlabel);\n if (normlabel === '') {\n // label must contain non-whitespace characters\n this.pos = startpos;\n return 0;\n }\n\n if (!refmap[normlabel]) {\n refmap[normlabel] = { destination: dest, title: title };\n }\n return this.pos - startpos;\n};\n\n// Parse the next inline element in subject, advancing subject position.\n// On success, add the result to block's children and return true.\n// On failure, return false.\nvar parseInline = function(block) {\n var res = false;\n var c = this.peek();\n if (c === -1) {\n return false;\n }\n switch(c) {\n case C_NEWLINE:\n res = this.parseNewline(block);\n break;\n case C_BACKSLASH:\n res = this.parseBackslash(block);\n break;\n case C_BACKTICK:\n res = this.parseBackticks(block);\n break;\n case C_ASTERISK:\n case C_UNDERSCORE:\n res = this.handleDelim(c, block);\n break;\n case C_SINGLEQUOTE:\n case C_DOUBLEQUOTE:\n res = this.options.smart && this.handleDelim(c, block);\n break;\n case C_OPEN_BRACKET:\n res = this.parseOpenBracket(block);\n break;\n case C_BANG:\n res = this.parseBang(block);\n break;\n case C_CLOSE_BRACKET:\n res = this.parseCloseBracket(block);\n break;\n case C_LESSTHAN:\n res = this.parseAutolink(block) || this.parseHtmlTag(block);\n break;\n case C_AMPERSAND:\n res = this.parseEntity(block);\n break;\n default:\n res = this.parseString(block);\n break;\n }\n if (!res) {\n this.pos += 1;\n block.appendChild(text(fromCodePoint(c)));\n }\n\n return true;\n};\n\n// Parse string content in block into inline children,\n// using refmap to resolve references.\nvar parseInlines = function(block) {\n this.subject = block._string_content.trim();\n this.pos = 0;\n this.delimiters = null;\n while (this.parseInline(block)) {\n }\n block._string_content = null; // allow raw string to be garbage collected\n this.processEmphasis(null);\n};\n\n// The InlineParser object.\nfunction InlineParser(options){\n return {\n subject: '',\n delimiters: null, // used by handleDelim method\n pos: 0,\n refmap: {},\n match: match,\n peek: peek,\n spnl: spnl,\n parseBackticks: parseBackticks,\n parseBackslash: parseBackslash,\n parseAutolink: parseAutolink,\n parseHtmlTag: parseHtmlTag,\n scanDelims: scanDelims,\n handleDelim: handleDelim,\n parseLinkTitle: parseLinkTitle,\n parseLinkDestination: parseLinkDestination,\n parseLinkLabel: parseLinkLabel,\n parseOpenBracket: parseOpenBracket,\n parseCloseBracket: parseCloseBracket,\n parseBang: parseBang,\n parseEntity: parseEntity,\n parseString: parseString,\n parseNewline: parseNewline,\n parseReference: parseReference,\n parseInline: parseInline,\n processEmphasis: processEmphasis,\n removeDelimiter: removeDelimiter,\n options: options || {},\n parse: parseInlines\n };\n}\n\nmodule.exports = InlineParser;\n","\"use strict\";\n\nvar Node = require('./node');\nvar unescapeString = require('./common').unescapeString;\nvar OPENTAG = require('./common').OPENTAG;\nvar CLOSETAG = require('./common').CLOSETAG;\n\nvar CODE_INDENT = 4;\n\nvar C_TAB = 9;\nvar C_NEWLINE = 10;\nvar C_GREATERTHAN = 62;\nvar C_LESSTHAN = 60;\nvar C_SPACE = 32;\nvar C_OPEN_BRACKET = 91;\n\nvar InlineParser = require('./inlines');\n\nvar reHtmlBlockOpen = [\n /./, // dummy for 0\n /^<(?:script|pre|style)(?:\\s|>|$)/i,\n /^/,\n /\\?>/,\n />/,\n /\\]\\]>/\n];\n\nvar reThematicBreak = /^(?:(?:\\* *){3,}|(?:_ *){3,}|(?:- *){3,}) *$/;\n\nvar reMaybeSpecial = /^[#`~*+_=<>0-9-]/;\n\nvar reNonSpace = /[^ \\t\\f\\v\\r\\n]/;\n\nvar reBulletListMarker = /^[*+-]/;\n\nvar reOrderedListMarker = /^(\\d{1,9})([.)])/;\n\nvar reATXHeadingMarker = /^#{1,6}(?: +|$)/;\n\nvar reCodeFence = /^`{3,}(?!.*`)|^~{3,}(?!.*~)/;\n\nvar reClosingCodeFence = /^(?:`{3,}|~{3,})(?= *$)/;\n\nvar reSetextHeadingLine = /^(?:=+|-+) *$/;\n\nvar reLineEnding = /\\r\\n|\\n|\\r/;\n\n// Returns true if string contains only space characters.\nvar isBlank = function(s) {\n return !(reNonSpace.test(s));\n};\n\nvar peek = function(ln, pos) {\n if (pos < ln.length) {\n return ln.charCodeAt(pos);\n } else {\n return -1;\n }\n};\n\n// DOC PARSER\n\n// These are methods of a Parser object, defined below.\n\n// Returns true if block ends with a blank line, descending if needed\n// into lists and sublists.\nvar endsWithBlankLine = function(block) {\n while (block) {\n if (block._lastLineBlank) {\n return true;\n }\n var t = block.type;\n if (t === 'List' || t === 'Item') {\n block = block._lastChild;\n } else {\n break;\n }\n }\n return false;\n};\n\n// Break out of all containing lists, resetting the tip of the\n// document to the parent of the highest list, and finalizing\n// all the lists. (This is used to implement the \"two blank lines\n// break out of all lists\" feature.)\nvar breakOutOfLists = function(block) {\n var b = block;\n var last_list = null;\n do {\n if (b.type === 'List') {\n last_list = b;\n }\n b = b._parent;\n } while (b);\n\n if (last_list) {\n while (block !== last_list) {\n this.finalize(block, this.lineNumber);\n block = block._parent;\n }\n this.finalize(last_list, this.lineNumber);\n this.tip = last_list._parent;\n }\n};\n\n// Add a line to the block at the tip. We assume the tip\n// can accept lines -- that check should be done before calling this.\nvar addLine = function() {\n this.tip._string_content += this.currentLine.slice(this.offset) + '\\n';\n};\n\n// Add block of type tag as a child of the tip. If the tip can't\n// accept children, close and finalize it and try its parent,\n// and so on til we find a block that can accept children.\nvar addChild = function(tag, offset) {\n while (!this.blocks[this.tip.type].canContain(tag)) {\n this.finalize(this.tip, this.lineNumber - 1);\n }\n\n var column_number = offset + 1; // offset 0 = column 1\n var newBlock = new Node(tag, [[this.lineNumber, column_number], [0, 0]]);\n newBlock._string_content = '';\n this.tip.appendChild(newBlock);\n this.tip = newBlock;\n return newBlock;\n};\n\n// Parse a list marker and return data on the marker (type,\n// start, delimiter, bullet character, padding) or null.\nvar parseListMarker = function(parser) {\n var rest = parser.currentLine.slice(parser.nextNonspace);\n var match;\n var nextc;\n var spacesStartCol;\n var spacesStartOffset;\n var data = { type: null,\n tight: true, // lists are tight by default\n bulletChar: null,\n start: null,\n delimiter: null,\n padding: null,\n markerOffset: parser.indent };\n if ((match = rest.match(reBulletListMarker))) {\n data.type = 'Bullet';\n data.bulletChar = match[0][0];\n\n } else if ((match = rest.match(reOrderedListMarker))) {\n data.type = 'Ordered';\n data.start = parseInt(match[1]);\n data.delimiter = match[2];\n } else {\n return null;\n }\n // make sure we have spaces after\n nextc = peek(parser.currentLine, parser.nextNonspace + match[0].length);\n if (!(nextc === -1 || nextc === C_TAB || nextc === C_SPACE)) {\n return null;\n }\n\n // we've got a match! advance offset and calculate padding\n parser.advanceNextNonspace(); // to start of marker\n parser.advanceOffset(match[0].length, true); // to end of marker\n spacesStartCol = parser.column;\n spacesStartOffset = parser.offset;\n do {\n parser.advanceOffset(1, true);\n nextc = peek(parser.currentLine, parser.offset);\n } while (parser.column - spacesStartCol < 5 &&\n (nextc === C_SPACE || nextc === C_TAB));\n var blank_item = peek(parser.currentLine, parser.offset) === -1;\n var spaces_after_marker = parser.column - spacesStartCol;\n if (spaces_after_marker >= 5 ||\n spaces_after_marker < 1 ||\n blank_item) {\n data.padding = match[0].length + 1;\n parser.column = spacesStartCol;\n parser.offset = spacesStartOffset;\n if (peek(parser.currentLine, parser.offset) === C_SPACE) {\n parser.advanceOffset(1, true);\n }\n } else {\n data.padding = match[0].length + spaces_after_marker;\n }\n return data;\n};\n\n// Returns true if the two list items are of the same type,\n// with the same delimiter and bullet character. This is used\n// in agglomerating list items into lists.\nvar listsMatch = function(list_data, item_data) {\n return (list_data.type === item_data.type &&\n list_data.delimiter === item_data.delimiter &&\n list_data.bulletChar === item_data.bulletChar);\n};\n\n// Finalize and close any unmatched blocks.\nvar closeUnmatchedBlocks = function() {\n if (!this.allClosed) {\n // finalize any blocks not matched\n while (this.oldtip !== this.lastMatchedContainer) {\n var parent = this.oldtip._parent;\n this.finalize(this.oldtip, this.lineNumber - 1);\n this.oldtip = parent;\n }\n this.allClosed = true;\n }\n};\n\n// 'finalize' is run when the block is closed.\n// 'continue' is run to check whether the block is continuing\n// at a certain line and offset (e.g. whether a block quote\n// contains a `>`. It returns 0 for matched, 1 for not matched,\n// and 2 for \"we've dealt with this line completely, go to next.\"\nvar blocks = {\n Document: {\n continue: function() { return 0; },\n finalize: function() { return; },\n canContain: function(t) { return (t !== 'Item'); },\n acceptsLines: false\n },\n List: {\n continue: function() { return 0; },\n finalize: function(parser, block) {\n var item = block._firstChild;\n while (item) {\n // check for non-final list item ending with blank line:\n if (endsWithBlankLine(item) && item._next) {\n block._listData.tight = false;\n break;\n }\n // recurse into children of list item, to see if there are\n // spaces between any of them:\n var subitem = item._firstChild;\n while (subitem) {\n if (endsWithBlankLine(subitem) &&\n (item._next || subitem._next)) {\n block._listData.tight = false;\n break;\n }\n subitem = subitem._next;\n }\n item = item._next;\n }\n },\n canContain: function(t) { return (t === 'Item'); },\n acceptsLines: false\n },\n BlockQuote: {\n continue: function(parser) {\n var ln = parser.currentLine;\n if (!parser.indented &&\n peek(ln, parser.nextNonspace) === C_GREATERTHAN) {\n parser.advanceNextNonspace();\n parser.advanceOffset(1, false);\n if (peek(ln, parser.offset) === C_SPACE) {\n parser.offset++;\n }\n } else {\n return 1;\n }\n return 0;\n },\n finalize: function() { return; },\n canContain: function(t) { return (t !== 'Item'); },\n acceptsLines: false\n },\n Item: {\n continue: function(parser, container) {\n if (parser.blank && container._firstChild !== null) {\n parser.advanceNextNonspace();\n } else if (parser.indent >=\n container._listData.markerOffset +\n container._listData.padding) {\n parser.advanceOffset(container._listData.markerOffset +\n container._listData.padding, true);\n } else {\n return 1;\n }\n return 0;\n },\n finalize: function() { return; },\n canContain: function(t) { return (t !== 'Item'); },\n acceptsLines: false\n },\n Heading: {\n continue: function() {\n // a heading can never container > 1 line, so fail to match:\n return 1;\n },\n finalize: function() { return; },\n canContain: function() { return false; },\n acceptsLines: false\n },\n ThematicBreak: {\n continue: function() {\n // a thematic break can never container > 1 line, so fail to match:\n return 1;\n },\n finalize: function() { return; },\n canContain: function() { return false; },\n acceptsLines: false\n },\n CodeBlock: {\n continue: function(parser, container) {\n var ln = parser.currentLine;\n var indent = parser.indent;\n if (container._isFenced) { // fenced\n var match = (indent <= 3 &&\n ln.charAt(parser.nextNonspace) === container._fenceChar &&\n ln.slice(parser.nextNonspace).match(reClosingCodeFence));\n if (match && match[0].length >= container._fenceLength) {\n // closing fence - we're at end of line, so we can return\n parser.finalize(container, parser.lineNumber);\n return 2;\n } else {\n // skip optional spaces of fence offset\n var i = container._fenceOffset;\n while (i > 0 && peek(ln, parser.offset) === C_SPACE) {\n parser.advanceOffset(1, false);\n i--;\n }\n }\n } else { // indented\n if (indent >= CODE_INDENT) {\n parser.advanceOffset(CODE_INDENT, true);\n } else if (parser.blank) {\n parser.advanceNextNonspace();\n } else {\n return 1;\n }\n }\n return 0;\n },\n finalize: function(parser, block) {\n if (block._isFenced) { // fenced\n // first line becomes info string\n var content = block._string_content;\n var newlinePos = content.indexOf('\\n');\n var firstLine = content.slice(0, newlinePos);\n var rest = content.slice(newlinePos + 1);\n block.info = unescapeString(firstLine.trim());\n block._literal = rest;\n } else { // indented\n block._literal = block._string_content.replace(/(\\n *)+$/, '\\n');\n }\n block._string_content = null; // allow GC\n },\n canContain: function() { return false; },\n acceptsLines: true\n },\n HtmlBlock: {\n continue: function(parser, container) {\n return ((parser.blank &&\n (container._htmlBlockType === 6 ||\n container._htmlBlockType === 7)) ? 1 : 0);\n },\n finalize: function(parser, block) {\n block._literal = block._string_content.replace(/(\\n *)+$/, '');\n block._string_content = null; // allow GC\n },\n canContain: function() { return false; },\n acceptsLines: true\n },\n Paragraph: {\n continue: function(parser) {\n return (parser.blank ? 1 : 0);\n },\n finalize: function(parser, block) {\n var pos;\n var hasReferenceDefs = false;\n\n // try parsing the beginning as link reference definitions:\n while (peek(block._string_content, 0) === C_OPEN_BRACKET &&\n (pos =\n parser.inlineParser.parseReference(block._string_content,\n parser.refmap))) {\n block._string_content = block._string_content.slice(pos);\n hasReferenceDefs = true;\n }\n if (hasReferenceDefs && isBlank(block._string_content)) {\n block.unlink();\n }\n },\n canContain: function() { return false; },\n acceptsLines: true\n }\n};\n\n// block start functions. Return values:\n// 0 = no match\n// 1 = matched container, keep going\n// 2 = matched leaf, no more block starts\nvar blockStarts = [\n // block quote\n function(parser) {\n if (!parser.indented &&\n peek(parser.currentLine, parser.nextNonspace) === C_GREATERTHAN) {\n parser.advanceNextNonspace();\n parser.advanceOffset(1, false);\n // optional following space\n if (peek(parser.currentLine, parser.offset) === C_SPACE) {\n parser.advanceOffset(1, false);\n }\n parser.closeUnmatchedBlocks();\n parser.addChild('BlockQuote', parser.nextNonspace);\n return 1;\n } else {\n return 0;\n }\n },\n\n // ATX heading\n function(parser) {\n var match;\n if (!parser.indented &&\n (match = parser.currentLine.slice(parser.nextNonspace).match(reATXHeadingMarker))) {\n parser.advanceNextNonspace();\n parser.advanceOffset(match[0].length, false);\n parser.closeUnmatchedBlocks();\n var container = parser.addChild('Heading', parser.nextNonspace);\n container.level = match[0].trim().length; // number of #s\n // remove trailing ###s:\n container._string_content =\n parser.currentLine.slice(parser.offset).replace(/^ *#+ *$/, '').replace(/ +#+ *$/, '');\n parser.advanceOffset(parser.currentLine.length - parser.offset);\n return 2;\n } else {\n return 0;\n }\n },\n\n // Fenced code block\n function(parser) {\n var match;\n if (!parser.indented &&\n (match = parser.currentLine.slice(parser.nextNonspace).match(reCodeFence))) {\n var fenceLength = match[0].length;\n parser.closeUnmatchedBlocks();\n var container = parser.addChild('CodeBlock', parser.nextNonspace);\n container._isFenced = true;\n container._fenceLength = fenceLength;\n container._fenceChar = match[0][0];\n container._fenceOffset = parser.indent;\n parser.advanceNextNonspace();\n parser.advanceOffset(fenceLength, false);\n return 2;\n } else {\n return 0;\n }\n },\n\n // HTML block\n function(parser, container) {\n if (!parser.indented &&\n peek(parser.currentLine, parser.nextNonspace) === C_LESSTHAN) {\n var s = parser.currentLine.slice(parser.nextNonspace);\n var blockType;\n\n for (blockType = 1; blockType <= 7; blockType++) {\n if (reHtmlBlockOpen[blockType].test(s) &&\n (blockType < 7 ||\n container.type !== 'Paragraph')) {\n parser.closeUnmatchedBlocks();\n // We don't adjust parser.offset;\n // spaces are part of the HTML block:\n var b = parser.addChild('HtmlBlock',\n parser.offset);\n b._htmlBlockType = blockType;\n return 2;\n }\n }\n }\n\n return 0;\n\n },\n\n // Setext heading\n function(parser, container) {\n var match;\n if (!parser.indented &&\n container.type === 'Paragraph' &&\n ((match = parser.currentLine.slice(parser.nextNonspace).match(reSetextHeadingLine)))) {\n parser.closeUnmatchedBlocks();\n var heading = new Node('Heading', container.sourcepos);\n heading.level = match[0][0] === '=' ? 1 : 2;\n heading._string_content = container._string_content;\n container.insertAfter(heading);\n container.unlink();\n parser.tip = heading;\n parser.advanceOffset(parser.currentLine.length - parser.offset, false);\n return 2;\n } else {\n return 0;\n }\n },\n\n // thematic break\n function(parser) {\n if (!parser.indented &&\n reThematicBreak.test(parser.currentLine.slice(parser.nextNonspace))) {\n parser.closeUnmatchedBlocks();\n parser.addChild('ThematicBreak', parser.nextNonspace);\n parser.advanceOffset(parser.currentLine.length - parser.offset, false);\n return 2;\n } else {\n return 0;\n }\n },\n\n // list item\n function(parser, container) {\n var data;\n\n if ((!parser.indented || container.type === 'List')\n && (data = parseListMarker(parser))) {\n parser.closeUnmatchedBlocks();\n\n // add the list if needed\n if (parser.tip.type !== 'List' ||\n !(listsMatch(container._listData, data))) {\n container = parser.addChild('List', parser.nextNonspace);\n container._listData = data;\n }\n\n // add the list item\n container = parser.addChild('Item', parser.nextNonspace);\n container._listData = data;\n return 1;\n } else {\n return 0;\n }\n },\n\n // indented code block\n function(parser) {\n if (parser.indented &&\n parser.tip.type !== 'Paragraph' &&\n !parser.blank) {\n // indented code\n parser.advanceOffset(CODE_INDENT, true);\n parser.closeUnmatchedBlocks();\n parser.addChild('CodeBlock', parser.offset);\n return 2;\n } else {\n return 0;\n }\n }\n\n];\n\nvar advanceOffset = function(count, columns) {\n var cols = 0;\n var currentLine = this.currentLine;\n var charsToTab;\n var c;\n while (count > 0 && (c = currentLine[this.offset])) {\n if (c === '\\t') {\n charsToTab = 4 - (this.column % 4);\n this.column += charsToTab;\n this.offset += 1;\n count -= (columns ? charsToTab : 1);\n } else {\n cols += 1;\n this.offset += 1;\n this.column += 1; // assume ascii; block starts are ascii\n count -= 1;\n }\n }\n};\n\nvar advanceNextNonspace = function() {\n this.offset = this.nextNonspace;\n this.column = this.nextNonspaceColumn;\n};\n\nvar findNextNonspace = function() {\n var currentLine = this.currentLine;\n var i = this.offset;\n var cols = this.column;\n var c;\n\n while ((c = currentLine.charAt(i)) !== '') {\n if (c === ' ') {\n i++;\n cols++;\n } else if (c === '\\t') {\n i++;\n cols += (4 - (cols % 4));\n } else {\n break;\n }\n }\n this.blank = (c === '\\n' || c === '\\r' || c === '');\n this.nextNonspace = i;\n this.nextNonspaceColumn = cols;\n this.indent = this.nextNonspaceColumn - this.column;\n this.indented = this.indent >= CODE_INDENT;\n};\n\n// Analyze a line of text and update the document appropriately.\n// We parse markdown text by calling this on each line of input,\n// then finalizing the document.\nvar incorporateLine = function(ln) {\n var all_matched = true;\n var t;\n\n var container = this.doc;\n this.oldtip = this.tip;\n this.offset = 0;\n this.column = 0;\n this.lineNumber += 1;\n\n // replace NUL characters for security\n if (ln.indexOf('\\u0000') !== -1) {\n ln = ln.replace(/\\0/g, '\\uFFFD');\n }\n\n this.currentLine = ln;\n\n // For each containing block, try to parse the associated line start.\n // Bail out on failure: container will point to the last matching block.\n // Set all_matched to false if not all containers match.\n var lastChild;\n while ((lastChild = container._lastChild) && lastChild._open) {\n container = lastChild;\n\n this.findNextNonspace();\n\n switch (this.blocks[container.type].continue(this, container)) {\n case 0: // we've matched, keep going\n break;\n case 1: // we've failed to match a block\n all_matched = false;\n break;\n case 2: // we've hit end of line for fenced code close and can return\n this.lastLineLength = ln.length;\n return;\n default:\n throw 'continue returned illegal value, must be 0, 1, or 2';\n }\n if (!all_matched) {\n container = container._parent; // back up to last matching block\n break;\n }\n }\n\n this.allClosed = (container === this.oldtip);\n this.lastMatchedContainer = container;\n\n // Check to see if we've hit 2nd blank line; if so break out of list:\n if (this.blank && container._lastLineBlank) {\n this.breakOutOfLists(container);\n container = this.tip;\n }\n\n var matchedLeaf = container.type !== 'Paragraph' &&\n blocks[container.type].acceptsLines;\n var starts = this.blockStarts;\n var startsLen = starts.length;\n // Unless last matched container is a code block, try new container starts,\n // adding children to the last matched container:\n while (!matchedLeaf) {\n\n this.findNextNonspace();\n\n // this is a little performance optimization:\n if (!this.indented &&\n !reMaybeSpecial.test(ln.slice(this.nextNonspace))) {\n this.advanceNextNonspace();\n break;\n }\n\n var i = 0;\n while (i < startsLen) {\n var res = starts[i](this, container);\n if (res === 1) {\n container = this.tip;\n break;\n } else if (res === 2) {\n container = this.tip;\n matchedLeaf = true;\n break;\n } else {\n i++;\n }\n }\n\n if (i === startsLen) { // nothing matched\n this.advanceNextNonspace();\n break;\n }\n }\n\n // What remains at the offset is a text line. Add the text to the\n // appropriate container.\n\n // First check for a lazy paragraph continuation:\n if (!this.allClosed && !this.blank &&\n this.tip.type === 'Paragraph') {\n // lazy paragraph continuation\n this.addLine();\n\n } else { // not a lazy continuation\n\n // finalize any blocks not matched\n this.closeUnmatchedBlocks();\n if (this.blank && container.lastChild) {\n container.lastChild._lastLineBlank = true;\n }\n\n t = container.type;\n\n // Block quote lines are never blank as they start with >\n // and we don't count blanks in fenced code for purposes of tight/loose\n // lists or breaking out of lists. We also don't set _lastLineBlank\n // on an empty list item, or if we just closed a fenced block.\n var lastLineBlank = this.blank &&\n !(t === 'BlockQuote' ||\n (t === 'CodeBlock' && container._isFenced) ||\n (t === 'Item' &&\n !container._firstChild &&\n container.sourcepos[0][0] === this.lineNumber));\n\n // propagate lastLineBlank up through parents:\n var cont = container;\n while (cont) {\n cont._lastLineBlank = lastLineBlank;\n cont = cont._parent;\n }\n\n if (this.blocks[t].acceptsLines) {\n this.addLine();\n // if HtmlBlock, check for end condition\n if (t === 'HtmlBlock' &&\n container._htmlBlockType >= 1 &&\n container._htmlBlockType <= 5 &&\n reHtmlBlockClose[container._htmlBlockType].test(this.currentLine.slice(this.offset))) {\n this.finalize(container, this.lineNumber);\n }\n\n } else if (this.offset < ln.length && !this.blank) {\n // create paragraph container for line\n container = this.addChild('Paragraph', this.offset);\n this.advanceNextNonspace();\n this.addLine();\n }\n }\n this.lastLineLength = ln.length;\n};\n\n// Finalize a block. Close it and do any necessary postprocessing,\n// e.g. creating string_content from strings, setting the 'tight'\n// or 'loose' status of a list, and parsing the beginnings\n// of paragraphs for reference definitions. Reset the tip to the\n// parent of the closed block.\nvar finalize = function(block, lineNumber) {\n var above = block._parent;\n block._open = false;\n block.sourcepos[1] = [lineNumber, this.lastLineLength];\n\n this.blocks[block.type].finalize(this, block);\n\n this.tip = above;\n};\n\n// Walk through a block & children recursively, parsing string content\n// into inline content where appropriate.\nvar processInlines = function(block) {\n var node, event, t;\n var walker = block.walker();\n this.inlineParser.refmap = this.refmap;\n this.inlineParser.options = this.options;\n while ((event = walker.next())) {\n node = event.node;\n t = node.type;\n if (!event.entering && (t === 'Paragraph' || t === 'Heading')) {\n this.inlineParser.parse(node);\n }\n }\n};\n\nvar Document = function() {\n var doc = new Node('Document', [[1, 1], [0, 0]]);\n return doc;\n};\n\n// The main parsing function. Returns a parsed document AST.\nvar parse = function(input) {\n this.doc = new Document();\n this.tip = this.doc;\n this.refmap = {};\n this.lineNumber = 0;\n this.lastLineLength = 0;\n this.offset = 0;\n this.column = 0;\n this.lastMatchedContainer = this.doc;\n this.currentLine = \"\";\n if (this.options.time) { console.time(\"preparing input\"); }\n var lines = input.split(reLineEnding);\n var len = lines.length;\n if (input.charCodeAt(input.length - 1) === C_NEWLINE) {\n // ignore last blank line created by final newline\n len -= 1;\n }\n if (this.options.time) { console.timeEnd(\"preparing input\"); }\n if (this.options.time) { console.time(\"block parsing\"); }\n for (var i = 0; i < len; i++) {\n this.incorporateLine(lines[i]);\n }\n while (this.tip) {\n this.finalize(this.tip, len);\n }\n if (this.options.time) { console.timeEnd(\"block parsing\"); }\n if (this.options.time) { console.time(\"inline parsing\"); }\n this.processInlines(this.doc);\n if (this.options.time) { console.timeEnd(\"inline parsing\"); }\n return this.doc;\n};\n\n\n// The Parser object.\nfunction Parser(options){\n return {\n doc: new Document(),\n blocks: blocks,\n blockStarts: blockStarts,\n tip: this.doc,\n oldtip: this.doc,\n currentLine: \"\",\n lineNumber: 0,\n offset: 0,\n column: 0,\n nextNonspace: 0,\n nextNonspaceColumn: 0,\n indent: 0,\n indented: false,\n blank: false,\n allClosed: true,\n lastMatchedContainer: this.doc,\n refmap: {},\n lastLineLength: 0,\n inlineParser: new InlineParser(options),\n findNextNonspace: findNextNonspace,\n advanceOffset: advanceOffset,\n advanceNextNonspace: advanceNextNonspace,\n breakOutOfLists: breakOutOfLists,\n addLine: addLine,\n addChild: addChild,\n incorporateLine: incorporateLine,\n finalize: finalize,\n processInlines: processInlines,\n closeUnmatchedBlocks: closeUnmatchedBlocks,\n parse: parse,\n options: options || {}\n };\n}\n\nmodule.exports = Parser;\n","\"use strict\";\n\nvar escapeXml = require('./common').escapeXml;\n\n// Helper function to produce an HTML tag.\nvar tag = function(name, attrs, selfclosing) {\n var result = '<' + name;\n if (attrs && attrs.length > 0) {\n var i = 0;\n var attrib;\n while ((attrib = attrs[i]) !== undefined) {\n result += ' ' + attrib[0] + '=\"' + attrib[1] + '\"';\n i++;\n }\n }\n if (selfclosing) {\n result += ' /';\n }\n\n result += '>';\n return result;\n};\n\nvar reHtmlTag = /\\<[^>]*\\>/;\nvar reUnsafeProtocol = /^javascript:|vbscript:|file:|data:/i;\nvar reSafeDataProtocol = /^data:image\\/(?:png|gif|jpeg|webp)/i;\n\nvar potentiallyUnsafe = function(url) {\n return reUnsafeProtocol.test(url) &&\n !reSafeDataProtocol.test(url);\n};\n\nvar renderNodes = function(block) {\n\n var attrs;\n var info_words;\n var tagname;\n var walker = block.walker();\n var event, node, entering;\n var buffer = \"\";\n var lastOut = \"\\n\";\n var disableTags = 0;\n var grandparent;\n var out = function(s) {\n if (disableTags > 0) {\n buffer += s.replace(reHtmlTag, '');\n } else {\n buffer += s;\n }\n lastOut = s;\n };\n var esc = this.escape;\n var cr = function() {\n if (lastOut !== '\\n') {\n buffer += '\\n';\n lastOut = '\\n';\n }\n };\n\n var options = this.options;\n\n if (options.time) { console.time(\"rendering\"); }\n\n while ((event = walker.next())) {\n entering = event.entering;\n node = event.node;\n\n attrs = [];\n if (options.sourcepos) {\n var pos = node.sourcepos;\n if (pos) {\n attrs.push(['data-sourcepos', String(pos[0][0]) + ':' +\n String(pos[0][1]) + '-' + String(pos[1][0]) + ':' +\n String(pos[1][1])]);\n }\n }\n\n switch (node.type) {\n case 'Text':\n out(esc(node.literal, false));\n break;\n\n case 'Softbreak':\n out(this.softbreak);\n break;\n\n case 'Hardbreak':\n out(tag('br', [], true));\n cr();\n break;\n\n case 'Emph':\n out(tag(entering ? 'em' : '/em'));\n break;\n\n case 'Strong':\n out(tag(entering ? 'strong' : '/strong'));\n break;\n\n case 'HtmlInline':\n if (options.safe) {\n out('');\n } else {\n out(node.literal);\n }\n break;\n\n case 'CustomInline':\n if (entering && node.onEnter) {\n out(node.onEnter);\n } else if (!entering && node.onExit) {\n out(node.onExit);\n }\n break;\n\n case 'Link':\n if (entering) {\n if (!(options.safe && potentiallyUnsafe(node.destination))) {\n attrs.push(['href', esc(node.destination, true)]);\n }\n if (node.title) {\n attrs.push(['title', esc(node.title, true)]);\n }\n out(tag('a', attrs));\n } else {\n out(tag('/a'));\n }\n break;\n\n case 'Image':\n if (entering) {\n if (disableTags === 0) {\n if (options.safe &&\n potentiallyUnsafe(node.destination)) {\n out('\"');\n');\n }\n }\n break;\n\n case 'Code':\n out(tag('code') + esc(node.literal, false) + tag('/code'));\n break;\n\n case 'Document':\n break;\n\n case 'Paragraph':\n grandparent = node.parent.parent;\n if (grandparent !== null &&\n grandparent.type === 'List') {\n if (grandparent.listTight) {\n break;\n }\n }\n if (entering) {\n cr();\n out(tag('p', attrs));\n } else {\n out(tag('/p'));\n cr();\n }\n break;\n\n case 'BlockQuote':\n if (entering) {\n cr();\n out(tag('blockquote', attrs));\n cr();\n } else {\n cr();\n out(tag('/blockquote'));\n cr();\n }\n break;\n\n case 'Item':\n if (entering) {\n out(tag('li', attrs));\n } else {\n out(tag('/li'));\n cr();\n }\n break;\n\n case 'List':\n tagname = node.listType === 'Bullet' ? 'ul' : 'ol';\n if (entering) {\n var start = node.listStart;\n if (start !== null && start !== 1) {\n attrs.push(['start', start.toString()]);\n }\n cr();\n out(tag(tagname, attrs));\n cr();\n } else {\n cr();\n out(tag('/' + tagname));\n cr();\n }\n break;\n\n case 'Heading':\n tagname = 'h' + node.level;\n if (entering) {\n cr();\n out(tag(tagname, attrs));\n } else {\n out(tag('/' + tagname));\n cr();\n }\n break;\n\n case 'CodeBlock':\n info_words = node.info ? node.info.split(/\\s+/) : [];\n if (info_words.length > 0 && info_words[0].length > 0) {\n attrs.push(['class', 'language-' + esc(info_words[0], true)]);\n }\n cr();\n out(tag('pre') + tag('code', attrs));\n out(esc(node.literal, false));\n out(tag('/code') + tag('/pre'));\n cr();\n break;\n\n case 'HtmlBlock':\n cr();\n if (options.safe) {\n out('');\n } else {\n out(node.literal);\n }\n cr();\n break;\n\n case 'CustomBlock':\n cr();\n if (entering && node.onEnter) {\n out(node.onEnter);\n } else if (!entering && node.onExit) {\n out(node.onExit);\n }\n cr();\n break;\n\n case 'ThematicBreak':\n cr();\n out(tag('hr', attrs, true));\n cr();\n break;\n\n default:\n throw \"Unknown node type \" + node.type;\n }\n\n }\n if (options.time) { console.timeEnd(\"rendering\"); }\n return buffer;\n};\n\n// The HtmlRenderer object.\nfunction HtmlRenderer(options){\n return {\n // default options:\n softbreak: '\\n', // by default, soft breaks are rendered as newlines in HTML\n // set to \"
\" to make them hard breaks\n // set to \" \" if you want to ignore line wrapping in source\n escape: escapeXml,\n options: options || {},\n render: renderNodes\n };\n}\n\nmodule.exports = HtmlRenderer;\n","\"use strict\";\n\nvar escapeXml = require('./common').escapeXml;\n\n// Helper function to produce an XML tag.\nvar tag = function(name, attrs, selfclosing) {\n var result = '<' + name;\n if (attrs && attrs.length > 0) {\n var i = 0;\n var attrib;\n while ((attrib = attrs[i]) !== undefined) {\n result += ' ' + attrib[0] + '=\"' + attrib[1] + '\"';\n i++;\n }\n }\n if (selfclosing) {\n result += ' /';\n }\n\n result += '>';\n return result;\n};\n\nvar reXMLTag = /\\<[^>]*\\>/;\n\nvar toTagName = function(s) {\n return s.replace(/([a-z])([A-Z])/g, \"$1_$2\").toLowerCase();\n};\n\nvar renderNodes = function(block) {\n\n var attrs;\n var tagname;\n var walker = block.walker();\n var event, node, entering;\n var buffer = \"\";\n var lastOut = \"\\n\";\n var disableTags = 0;\n var indentLevel = 0;\n var indent = ' ';\n var container;\n var selfClosing;\n var nodetype;\n\n var out = function(s) {\n if (disableTags > 0) {\n buffer += s.replace(reXMLTag, '');\n } else {\n buffer += s;\n }\n lastOut = s;\n };\n var esc = this.escape;\n var cr = function() {\n if (lastOut !== '\\n') {\n buffer += '\\n';\n lastOut = '\\n';\n for (var i = indentLevel; i > 0; i--) {\n buffer += indent;\n }\n }\n };\n\n var options = this.options;\n\n if (options.time) { console.time(\"rendering\"); }\n\n buffer += '\\n';\n buffer += '\\n';\n\n while ((event = walker.next())) {\n entering = event.entering;\n node = event.node;\n nodetype = node.type;\n\n container = node.isContainer;\n selfClosing = nodetype === 'ThematicBreak' || nodetype === 'Hardbreak' ||\n nodetype === 'Softbreak';\n tagname = toTagName(nodetype);\n\n if (entering) {\n\n attrs = [];\n\n switch (nodetype) {\n case 'Document':\n attrs.push(['xmlns', 'http://commonmark.org/xml/1.0']);\n break;\n case 'List':\n if (node.listType !== null) {\n attrs.push(['type', node.listType.toLowerCase()]);\n }\n if (node.listStart !== null) {\n attrs.push(['start', String(node.listStart)]);\n }\n if (node.listTight !== null) {\n attrs.push(['tight', (node.listTight ? 'true' : 'false')]);\n }\n var delim = node.listDelimiter;\n if (delim !== null) {\n var delimword = '';\n if (delim === '.') {\n delimword = 'period';\n } else {\n delimword = 'paren';\n }\n attrs.push(['delimiter', delimword]);\n }\n break;\n case 'CodeBlock':\n if (node.info) {\n attrs.push(['info', node.info]);\n }\n break;\n case 'Heading':\n attrs.push(['level', String(node.level)]);\n break;\n case 'Link':\n case 'Image':\n attrs.push(['destination', node.destination]);\n attrs.push(['title', node.title]);\n break;\n case 'CustomInline':\n case 'CustomBlock':\n attrs.push(['on_enter', node.onEnter]);\n attrs.push(['on_exit', node.onExit]);\n break;\n default:\n break;\n }\n if (options.sourcepos) {\n var pos = node.sourcepos;\n if (pos) {\n attrs.push(['sourcepos', String(pos[0][0]) + ':' +\n String(pos[0][1]) + '-' + String(pos[1][0]) + ':' +\n String(pos[1][1])]);\n }\n }\n\n cr();\n out(tag(tagname, attrs, selfClosing));\n if (container) {\n indentLevel += 1;\n } else if (!container && !selfClosing) {\n var lit = node.literal;\n if (lit) {\n out(esc(lit));\n }\n out(tag('/' + tagname));\n }\n } else {\n indentLevel -= 1;\n cr();\n out(tag('/' + tagname));\n }\n\n\n }\n if (options.time) { console.timeEnd(\"rendering\"); }\n buffer += '\\n';\n return buffer;\n};\n\n// The XmlRenderer object.\nfunction XmlRenderer(options){\n return {\n // default options:\n softbreak: '\\n', // by default, soft breaks are rendered as newlines in HTML\n // set to \"
\" to make them hard breaks\n // set to \" \" if you want to ignore line wrapping in source\n escape: escapeXml,\n options: options || {},\n render: renderNodes\n };\n}\n\nmodule.exports = XmlRenderer;\n","\"use strict\";\n\n// commonmark.js - CommomMark in JavaScript\n// Copyright (C) 2014 John MacFarlane\n// License: BSD3.\n\n// Basic usage:\n//\n// var commonmark = require('commonmark');\n// var parser = new commonmark.Parser();\n// var renderer = new commonmark.HtmlRenderer();\n// console.log(renderer.render(parser.parse('Hello *world*')));\n\nmodule.exports.version = '0.24.0'\nmodule.exports.Node = require('./node');\nmodule.exports.Parser = require('./blocks');\nmodule.exports.HtmlRenderer = require('./html');\nmodule.exports.XmlRenderer = require('./xml');\n","/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]';\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object),\n nativeMax = Math.max;\n\n/** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */\nvar nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n // Safari 9 makes `arguments.length` enumerable in strict mode.\n var result = (isArray(value) || isArguments(value))\n ? baseTimes(value.length, String)\n : [];\n\n var length = result.length,\n skipIndexes = !!length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (key == 'length' || isIndex(key, length)))) {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n object[key] = value;\n }\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = array;\n return apply(func, this, otherArgs);\n };\n}\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n assignValue(object, key, newValue === undefined ? source[key] : newValue);\n }\n return object;\n}\n\n/**\n * Creates a function like `_.assign`.\n *\n * @private\n * @param {Function} assigner The function to assign values.\n * @returns {Function} Returns the new assigner function.\n */\nfunction createAssigner(assigner) {\n return baseRest(function(object, sources) {\n var index = -1,\n length = sources.length,\n customizer = length > 1 ? sources[length - 1] : undefined,\n guard = length > 2 ? sources[2] : undefined;\n\n customizer = (assigner.length > 3 && typeof customizer == 'function')\n ? (length--, customizer)\n : undefined;\n\n if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n customizer = length < 3 ? undefined : customizer;\n length = 1;\n }\n object = Object(object);\n while (++index < length) {\n var source = sources[index];\n if (source) {\n assigner(object, source, index, customizer);\n }\n }\n return object;\n });\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n length = length == null ? MAX_SAFE_INTEGER : length;\n return !!length &&\n (typeof value == 'number' || reIsUint.test(value)) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `true` if the arguments are from an iteratee call,\n * else `false`.\n */\nfunction isIterateeCall(value, index, object) {\n if (!isObject(object)) {\n return false;\n }\n var type = typeof index;\n if (type == 'number'\n ? (isArrayLike(object) && isIndex(index, object.length))\n : (type == 'string' && index in object)\n ) {\n return eq(object[index], value);\n }\n return false;\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nfunction isArguments(value) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&\n (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);\n}\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 8-9 which returns 'object' for typed array and other constructors.\n var tag = isObject(value) ? objectToString.call(value) : '';\n return tag == funcTag || tag == genTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Assigns own enumerable string keyed properties of source objects to the\n * destination object. Source objects are applied from left to right.\n * Subsequent sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object` and is loosely based on\n * [`Object.assign`](https://mdn.io/Object/assign).\n *\n * @static\n * @memberOf _\n * @since 0.10.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assignIn\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assign({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'c': 3 }\n */\nvar assign = createAssigner(function(object, source) {\n if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {\n copyObject(source, keys(source), object);\n return;\n }\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n assignValue(object, key, source[key]);\n }\n }\n});\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nmodule.exports = assign;\n","/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/**\n * Checks if `value` is a host object in IE < 9.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n */\nfunction isHostObject(value) {\n // Many host objects are `Object` objects that can coerce to strings\n // despite having improperly defined `toString` methods.\n var result = false;\n if (value != null && typeof value.toString != 'function') {\n try {\n result = !!(value + '');\n } catch (e) {}\n }\n return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) ||\n objectToString.call(value) != objectTag || isHostObject(value)) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return (typeof Ctor == 'function' &&\n Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);\n}\n\nmodule.exports = isPlainObject;\n","/*\nCopyright (c) 2015, Yahoo! Inc. All rights reserved.\nCopyrights licensed under the New BSD License.\nSee the accompanying LICENSE file for terms.\n\nAuthors: Nera Liu \n Adonis Fung \n Albert Yu \n*/\n/*jshint node: true */\n\nexports._getPrivFilters = function () {\n\n var LT = /])/g,\n SPECIAL_HTML_CHARS = /[&<>\"'`]/g, \n SPECIAL_COMMENT_CHARS = /(?:\\x00|^-*!?>|--!?>|--?!?$|\\]>|\\]$)/g;\n\n // CSS sensitive chars: ()\"'/,!*@{}:;\n // By CSS: (Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast);|(quot|QUOT)\n // By URI_PROTOCOL: (Tab|NewLine);\n var SENSITIVE_HTML_ENTITIES = /&(?:#([xX][0-9A-Fa-f]+|\\d+);?|(Tab|NewLine|colon|semi|lpar|rpar|apos|sol|comma|excl|ast|midast|ensp|emsp|thinsp);|(nbsp|amp|AMP|lt|LT|gt|GT|quot|QUOT);?)/g,\n SENSITIVE_NAMED_REF_MAP = {Tab: '\\t', NewLine: '\\n', colon: ':', semi: ';', lpar: '(', rpar: ')', apos: '\\'', sol: '/', comma: ',', excl: '!', ast: '*', midast: '*', ensp: '\\u2002', emsp: '\\u2003', thinsp: '\\u2009', nbsp: '\\xA0', amp: '&', lt: '<', gt: '>', quot: '\"', QUOT: '\"'};\n\n // var CSS_VALID_VALUE = \n // /^(?:\n // (?!-*expression)#?[-\\w]+\n // |[+-]?(?:\\d+|\\d*\\.\\d+)(?:em|ex|ch|rem|px|mm|cm|in|pt|pc|%|vh|vw|vmin|vmax)?\n // |!important\n // | //empty\n // )$/i;\n var CSS_VALID_VALUE = /^(?:(?!-*expression)#?[-\\w]+|[+-]?(?:\\d+|\\d*\\.\\d+)(?:r?em|ex|ch|cm|mm|in|px|pt|pc|%|vh|vw|vmin|vmax)?|!important|)$/i,\n // TODO: prevent double css escaping by not encoding \\ again, but this may require CSS decoding\n // \\x7F and \\x01-\\x1F less \\x09 are for Safari 5.0, added []{}/* for unbalanced quote\n CSS_DOUBLE_QUOTED_CHARS = /[\\x00-\\x1F\\x7F\\[\\]{}\\\\\"]/g,\n CSS_SINGLE_QUOTED_CHARS = /[\\x00-\\x1F\\x7F\\[\\]{}\\\\']/g,\n // (, \\u207D and \\u208D can be used in background: 'url(...)' in IE, assumed all \\ chars are encoded by QUOTED_CHARS, and null is already replaced with \\uFFFD\n // otherwise, use this CSS_BLACKLIST instead (enhance it with url matching): /(?:\\\\?\\(|[\\u207D\\u208D]|\\\\0{0,4}28 ?|\\\\0{0,2}20[78][Dd] ?)+/g\n CSS_BLACKLIST = /url[\\(\\u207D\\u208D]+/g,\n // this assumes encodeURI() and encodeURIComponent() has escaped 1-32, 127 for IE8\n CSS_UNQUOTED_URL = /['\\(\\)]/g; // \" \\ treated by encodeURI()\n\n // Given a full URI, need to support \"[\" ( IPv6address ) \"]\" in URI as per RFC3986\n // Reference: https://tools.ietf.org/html/rfc3986\n var URL_IPV6 = /\\/\\/%5[Bb]([A-Fa-f0-9:]+)%5[Dd]/;\n\n\n // Reference: http://shazzer.co.uk/database/All/characters-allowd-in-html-entities\n // Reference: http://shazzer.co.uk/vector/Characters-allowed-after-ampersand-in-named-character-references\n // Reference: http://shazzer.co.uk/database/All/Characters-before-javascript-uri\n // Reference: http://shazzer.co.uk/database/All/Characters-after-javascript-uri\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference\n // Reference for named characters: https://html.spec.whatwg.org/multipage/entities.json\n var URI_BLACKLIST_PROTOCOLS = {'javascript':1, 'data':1, 'vbscript':1, 'mhtml':1, 'x-schema':1},\n URI_PROTOCOL_COLON = /(?::|&#[xX]0*3[aA];?|�*58;?|:)/,\n URI_PROTOCOL_WHITESPACES = /(?:^[\\x00-\\x20]+|[\\t\\n\\r\\x00]+)/g,\n URI_PROTOCOL_NAMED_REF_MAP = {Tab: '\\t', NewLine: '\\n'};\n\n var x, \n strReplace = function (s, regexp, callback) {\n return s === undefined ? 'undefined'\n : s === null ? 'null'\n : s.toString().replace(regexp, callback);\n },\n fromCodePoint = String.fromCodePoint || function(codePoint) {\n if (arguments.length === 0) {\n return '';\n }\n if (codePoint <= 0xFFFF) { // BMP code point\n return String.fromCharCode(codePoint);\n }\n\n // Astral code point; split in surrogate halves\n // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n codePoint -= 0x10000;\n return String.fromCharCode((codePoint >> 10) + 0xD800, (codePoint % 0x400) + 0xDC00);\n };\n\n\n function getProtocol(str) {\n var s = str.split(URI_PROTOCOL_COLON, 2);\n // str.length !== s[0].length is for older IE (e.g., v8), where delimeter residing at last will result in length equals 1, but not 2\n return (s[0] && (s.length === 2 || str.length !== s[0].length)) ? s[0] : null;\n }\n\n function htmlDecode(s, namedRefMap, reNamedRef, skipReplacement) {\n \n namedRefMap = namedRefMap || SENSITIVE_NAMED_REF_MAP;\n reNamedRef = reNamedRef || SENSITIVE_HTML_ENTITIES;\n\n function regExpFunction(m, num, named, named1) {\n if (num) {\n num = Number(num[0] <= '9' ? num : '0' + num);\n // switch(num) {\n // case 0x80: return '\\u20AC'; // EURO SIGN (€)\n // case 0x82: return '\\u201A'; // SINGLE LOW-9 QUOTATION MARK (‚)\n // case 0x83: return '\\u0192'; // LATIN SMALL LETTER F WITH HOOK (ƒ)\n // case 0x84: return '\\u201E'; // DOUBLE LOW-9 QUOTATION MARK („)\n // case 0x85: return '\\u2026'; // HORIZONTAL ELLIPSIS (…)\n // case 0x86: return '\\u2020'; // DAGGER (†)\n // case 0x87: return '\\u2021'; // DOUBLE DAGGER (‡)\n // case 0x88: return '\\u02C6'; // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ)\n // case 0x89: return '\\u2030'; // PER MILLE SIGN (‰)\n // case 0x8A: return '\\u0160'; // LATIN CAPITAL LETTER S WITH CARON (Š)\n // case 0x8B: return '\\u2039'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹)\n // case 0x8C: return '\\u0152'; // LATIN CAPITAL LIGATURE OE (Œ)\n // case 0x8E: return '\\u017D'; // LATIN CAPITAL LETTER Z WITH CARON (Ž)\n // case 0x91: return '\\u2018'; // LEFT SINGLE QUOTATION MARK (‘)\n // case 0x92: return '\\u2019'; // RIGHT SINGLE QUOTATION MARK (’)\n // case 0x93: return '\\u201C'; // LEFT DOUBLE QUOTATION MARK (“)\n // case 0x94: return '\\u201D'; // RIGHT DOUBLE QUOTATION MARK (”)\n // case 0x95: return '\\u2022'; // BULLET (•)\n // case 0x96: return '\\u2013'; // EN DASH (–)\n // case 0x97: return '\\u2014'; // EM DASH (—)\n // case 0x98: return '\\u02DC'; // SMALL TILDE (˜)\n // case 0x99: return '\\u2122'; // TRADE MARK SIGN (™)\n // case 0x9A: return '\\u0161'; // LATIN SMALL LETTER S WITH CARON (š)\n // case 0x9B: return '\\u203A'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›)\n // case 0x9C: return '\\u0153'; // LATIN SMALL LIGATURE OE (œ)\n // case 0x9E: return '\\u017E'; // LATIN SMALL LETTER Z WITH CARON (ž)\n // case 0x9F: return '\\u0178'; // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ)\n // }\n // // num >= 0xD800 && num <= 0xDFFF, and 0x0D is separately handled, as it doesn't fall into the range of x.pec()\n // return (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\\uFFFD' : x.frCoPt(num);\n\n return skipReplacement ? fromCodePoint(num)\n : num === 0x80 ? '\\u20AC' // EURO SIGN (€)\n : num === 0x82 ? '\\u201A' // SINGLE LOW-9 QUOTATION MARK (‚)\n : num === 0x83 ? '\\u0192' // LATIN SMALL LETTER F WITH HOOK (ƒ)\n : num === 0x84 ? '\\u201E' // DOUBLE LOW-9 QUOTATION MARK („)\n : num === 0x85 ? '\\u2026' // HORIZONTAL ELLIPSIS (…)\n : num === 0x86 ? '\\u2020' // DAGGER (†)\n : num === 0x87 ? '\\u2021' // DOUBLE DAGGER (‡)\n : num === 0x88 ? '\\u02C6' // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ)\n : num === 0x89 ? '\\u2030' // PER MILLE SIGN (‰)\n : num === 0x8A ? '\\u0160' // LATIN CAPITAL LETTER S WITH CARON (Š)\n : num === 0x8B ? '\\u2039' // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹)\n : num === 0x8C ? '\\u0152' // LATIN CAPITAL LIGATURE OE (Œ)\n : num === 0x8E ? '\\u017D' // LATIN CAPITAL LETTER Z WITH CARON (Ž)\n : num === 0x91 ? '\\u2018' // LEFT SINGLE QUOTATION MARK (‘)\n : num === 0x92 ? '\\u2019' // RIGHT SINGLE QUOTATION MARK (’)\n : num === 0x93 ? '\\u201C' // LEFT DOUBLE QUOTATION MARK (“)\n : num === 0x94 ? '\\u201D' // RIGHT DOUBLE QUOTATION MARK (”)\n : num === 0x95 ? '\\u2022' // BULLET (•)\n : num === 0x96 ? '\\u2013' // EN DASH (–)\n : num === 0x97 ? '\\u2014' // EM DASH (—)\n : num === 0x98 ? '\\u02DC' // SMALL TILDE (˜)\n : num === 0x99 ? '\\u2122' // TRADE MARK SIGN (™)\n : num === 0x9A ? '\\u0161' // LATIN SMALL LETTER S WITH CARON (š)\n : num === 0x9B ? '\\u203A' // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›)\n : num === 0x9C ? '\\u0153' // LATIN SMALL LIGATURE OE (œ)\n : num === 0x9E ? '\\u017E' // LATIN SMALL LETTER Z WITH CARON (ž)\n : num === 0x9F ? '\\u0178' // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ)\n : (num >= 0xD800 && num <= 0xDFFF) || num === 0x0D ? '\\uFFFD'\n : x.frCoPt(num);\n }\n return namedRefMap[named || named1] || m;\n }\n\n return s === undefined ? 'undefined'\n : s === null ? 'null'\n : s.toString().replace(NULL, '\\uFFFD').replace(reNamedRef, regExpFunction);\n }\n\n function cssEncode(chr) {\n // space after \\\\HEX is needed by spec\n return '\\\\' + chr.charCodeAt(0).toString(16).toLowerCase() + ' ';\n }\n function cssBlacklist(s) {\n return s.replace(CSS_BLACKLIST, function(m){ return '-x-' + m; });\n }\n function cssUrl(s) {\n // encodeURI() in yufull() will throw error for use of the CSS_UNSUPPORTED_CODE_POINT (i.e., [\\uD800-\\uDFFF])\n s = x.yufull(htmlDecode(s));\n var protocol = getProtocol(s);\n\n // prefix ## for blacklisted protocols\n // here .replace(URI_PROTOCOL_WHITESPACES, '') is not needed since yufull has already percent-encoded the whitespaces\n return (protocol && URI_BLACKLIST_PROTOCOLS[protocol.toLowerCase()]) ? '##' + s : s;\n }\n\n return (x = {\n // turn invalid codePoints and that of non-characters to \\uFFFD, and then fromCodePoint()\n frCoPt: function(num) {\n return num === undefined || num === null ? '' :\n !isFinite(num = Number(num)) || // `NaN`, `+Infinity`, or `-Infinity`\n num <= 0 || // not a valid Unicode code point\n num > 0x10FFFF || // not a valid Unicode code point\n // Math.floor(num) != num || \n\n (num >= 0x01 && num <= 0x08) ||\n (num >= 0x0E && num <= 0x1F) ||\n (num >= 0x7F && num <= 0x9F) ||\n (num >= 0xFDD0 && num <= 0xFDEF) ||\n \n num === 0x0B || \n (num & 0xFFFF) === 0xFFFF || \n (num & 0xFFFF) === 0xFFFE ? '\\uFFFD' : fromCodePoint(num);\n },\n d: htmlDecode,\n /*\n * @param {string} s - An untrusted uri input\n * @returns {string} s - null if relative url, otherwise the protocol with whitespaces stripped and lower-cased\n */\n yup: function(s) {\n s = getProtocol(s.replace(NULL, ''));\n // URI_PROTOCOL_WHITESPACES is required for left trim and remove interim whitespaces\n return s ? htmlDecode(s, URI_PROTOCOL_NAMED_REF_MAP, null, true).replace(URI_PROTOCOL_WHITESPACES, '').toLowerCase() : null;\n },\n\n /*\n * @deprecated\n * @param {string} s - An untrusted user input\n * @returns {string} s - The original user input with & < > \" ' ` encoded respectively as & < > " ' and `.\n *\n */\n y: function(s) {\n return strReplace(s, SPECIAL_HTML_CHARS, function (m) {\n return m === '&' ? '&'\n : m === '<' ? '<'\n : m === '>' ? '>'\n : m === '\"' ? '"'\n : m === \"'\" ? '''\n : /*m === '`'*/ '`'; // in hex: 60\n });\n },\n\n // This filter is meant to introduce double-encoding, and should be used with extra care.\n ya: function(s) {\n return strReplace(s, AMP, '&');\n },\n\n // FOR DETAILS, refer to inHTMLData()\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#data-state\n yd: function (s) {\n return strReplace(s, LT, '<');\n },\n\n // FOR DETAILS, refer to inHTMLComment()\n // All NULL characters in s are first replaced with \\uFFFD.\n // If s contains -->, --!>, or starts with -*>, insert a space right before > to stop state breaking at \n // If s ends with --!, --, or -, append a space to stop collaborative state breaking at {{{yc s}}}>, {{{yc s}}}!>, {{{yc s}}}-!>, {{{yc s}}}->\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#comment-state\n // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment-3\n // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment\n // Reference: http://shazzer.co.uk/vector/Characters-that-close-a-HTML-comment-0021\n // If s contains ]> or ends with ], append a space after ] is verified in IE to stop IE conditional comments.\n // Reference: http://msdn.microsoft.com/en-us/library/ms537512%28v=vs.85%29.aspx\n // We do not care --\\s>, which can possibly be intepreted as a valid close comment tag in very old browsers (e.g., firefox 3.6), as specified in the html4 spec\n // Reference: http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.2.4\n yc: function (s) {\n return strReplace(s, SPECIAL_COMMENT_CHARS, function(m){\n return m === '\\x00' ? '\\uFFFD'\n : m === '--!' || m === '--' || m === '-' || m === ']' ? m + ' '\n :/*\n : m === ']>' ? '] >'\n : m === '-->' ? '-- >'\n : m === '--!>' ? '--! >'\n : /-*!?>/.test(m) ? */ m.slice(0, -1) + ' >';\n });\n },\n\n // FOR DETAILS, refer to inDoubleQuotedAttr()\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(double-quoted)-state\n yavd: function (s) {\n return strReplace(s, QUOT, '"');\n },\n\n // FOR DETAILS, refer to inSingleQuotedAttr()\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(single-quoted)-state\n yavs: function (s) {\n return strReplace(s, SQUOT, ''');\n },\n\n // FOR DETAILS, refer to inUnQuotedAttr()\n // PART A.\n // if s contains any state breaking chars (\\t, \\n, \\v, \\f, \\r, space, and >),\n // they are escaped and encoded into their equivalent HTML entity representations. \n // Reference: http://shazzer.co.uk/database/All/Characters-which-break-attributes-without-quotes\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state\n //\n // PART B. \n // if s starts with ', \" or `, encode it resp. as ', ", or ` to \n // enforce the attr value (unquoted) state\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#before-attribute-value-state\n // Reference: http://shazzer.co.uk/vector/Characters-allowed-attribute-quote\n // \n // PART C.\n // Inject a \\uFFFD character if an empty or all null string is encountered in \n // unquoted attribute value state.\n // \n // Rationale 1: our belief is that developers wouldn't expect an \n // empty string would result in ' name=\"passwd\"' rendered as \n // attribute value, even though this is how HTML5 is specified.\n // Rationale 2: an empty or all null string (for IE) can \n // effectively alter its immediate subsequent state, we choose\n // \\uFFFD to end the unquoted attr \n // state, which therefore will not mess up later contexts.\n // Rationale 3: Since IE 6, it is verified that NULL chars are stripped.\n // Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state\n // \n // Example:\n // \n yavu: function (s) {\n return strReplace(s, SPECIAL_ATTR_VALUE_UNQUOTED_CHARS, function (m) {\n return m === '\\t' ? ' ' // in hex: 09\n : m === '\\n' ? ' ' // in hex: 0A\n : m === '\\x0B' ? ' ' // in hex: 0B for IE. IE<9 \\v equals v, so use \\x0B instead\n : m === '\\f' ? ' ' // in hex: 0C\n : m === '\\r' ? ' ' // in hex: 0D\n : m === ' ' ? ' ' // in hex: 20\n : m === '=' ? '=' // in hex: 3D\n : m === '<' ? '<'\n : m === '>' ? '>'\n : m === '\"' ? '"'\n : m === \"'\" ? '''\n : m === '`' ? '`'\n : /*empty or null*/ '\\uFFFD';\n });\n },\n\n yu: encodeURI,\n yuc: encodeURIComponent,\n\n // Notice that yubl MUST BE APPLIED LAST, and will not be used independently (expected output from encodeURI/encodeURIComponent and yavd/yavs/yavu)\n // This is used to disable JS execution capabilities by prefixing x- to ^javascript:, ^vbscript: or ^data: that possibly could trigger script execution in URI attribute context\n yubl: function (s) {\n return URI_BLACKLIST_PROTOCOLS[x.yup(s)] ? 'x-' + s : s;\n },\n\n // This is NOT a security-critical filter.\n // Reference: https://tools.ietf.org/html/rfc3986\n yufull: function (s) {\n return x.yu(s).replace(URL_IPV6, function(m, p) {\n return '//[' + p + ']';\n });\n },\n\n // chain yufull() with yubl()\n yublf: function (s) {\n return x.yubl(x.yufull(s));\n },\n\n // The design principle of the CSS filter MUST meet the following goal(s).\n // (1) The input cannot break out of the context (expr) and this is to fulfill the just sufficient encoding principle.\n // (2) The input cannot introduce CSS parsing error and this is to address the concern of UI redressing.\n //\n // term\n // : unary_operator?\n // [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |\n // TIME S* | FREQ S* ]\n // | STRING S* | IDENT S* | URI S* | hexcolor | function\n // \n // Reference:\n // * http://www.w3.org/TR/CSS21/grammar.html \n // * http://www.w3.org/TR/css-syntax-3/\n // \n // NOTE: delimiter in CSS - \\ _ : ; ( ) \" ' / , % # ! * @ . { }\n // 2d 5c 5f 3a 3b 28 29 22 27 2f 2c 25 23 21 2a 40 2e 7b 7d\n\n yceu: function(s) {\n s = htmlDecode(s);\n return CSS_VALID_VALUE.test(s) ? s : \";-x:'\" + cssBlacklist(s.replace(CSS_SINGLE_QUOTED_CHARS, cssEncode)) + \"';-v:\";\n },\n\n // string1 = \\\"([^\\n\\r\\f\\\\\"]|\\\\{nl}|\\\\[^\\n\\r\\f0-9a-f]|\\\\[0-9a-f]{1,6}(\\r\\n|[ \\n\\r\\t\\f])?)*\\\"\n yced: function(s) {\n return cssBlacklist(htmlDecode(s).replace(CSS_DOUBLE_QUOTED_CHARS, cssEncode));\n },\n\n // string2 = \\'([^\\n\\r\\f\\\\']|\\\\{nl}|\\\\[^\\n\\r\\f0-9a-f]|\\\\[0-9a-f]{1,6}(\\r\\n|[ \\n\\r\\t\\f])?)*\\'\n yces: function(s) {\n return cssBlacklist(htmlDecode(s).replace(CSS_SINGLE_QUOTED_CHARS, cssEncode));\n },\n\n // for url({{{yceuu url}}}\n // unquoted_url = ([!#$%&*-~]|\\\\{h}{1,6}(\\r\\n|[ \\t\\r\\n\\f])?|\\\\[^\\r\\n\\f0-9a-f])* (CSS 2.1 definition)\n // unquoted_url = ([^\"'()\\\\ \\t\\n\\r\\f\\v\\u0000\\u0008\\u000b\\u000e-\\u001f\\u007f]|\\\\{h}{1,6}(\\r\\n|[ \\t\\r\\n\\f])?|\\\\[^\\r\\n\\f0-9a-f])* (CSS 3.0 definition)\n // The state machine in CSS 3.0 is more well defined - http://www.w3.org/TR/css-syntax-3/#consume-a-url-token0\n // CSS_UNQUOTED_URL = /['\\(\\)]/g; // \" \\ treated by encodeURI() \n yceuu: function(s) {\n return cssUrl(s).replace(CSS_UNQUOTED_URL, function (chr) {\n return chr === '\\'' ? '\\\\27 ' :\n chr === '(' ? '%28' :\n /* chr === ')' ? */ '%29';\n });\n },\n\n // for url(\"{{{yceud url}}}\n yceud: function(s) { \n return cssUrl(s);\n },\n\n // for url('{{{yceus url}}}\n yceus: function(s) { \n return cssUrl(s).replace(SQUOT, '\\\\27 ');\n }\n });\n};\n\n// exposing privFilters\n// this is an undocumented feature, and please use it with extra care\nvar privFilters = exports._privFilters = exports._getPrivFilters();\n\n\n/* chaining filters */\n\n// uriInAttr and literally uriPathInAttr\n// yubl is always used \n// Rationale: given pattern like this: \n// developer may expect s is always prefixed with ? or /, but an attacker can abuse it with 'javascript:alert(1)'\nfunction uriInAttr (s, yav, yu) {\n return privFilters.yubl(yav((yu || privFilters.yufull)(s)));\n}\n\n/** \n* Yahoo Secure XSS Filters - just sufficient output filtering to prevent XSS!\n* @module xss-filters \n*/\n\n/**\n* @function module:xss-filters#inHTMLData\n*\n* @param {string} s - An untrusted user input\n* @returns {string} The string s with '<' encoded as '&lt;'\n*\n* @description\n* This filter is to be placed in HTML Data context to encode all '<' characters into '&lt;'\n* \n*\n* @example\n* // output context to be applied by this filter.\n*
{{{inHTMLData htmlData}}}
\n*\n*/\nexports.inHTMLData = privFilters.yd;\n\n/**\n* @function module:xss-filters#inHTMLComment\n*\n* @param {string} s - An untrusted user input\n* @returns {string} All NULL characters in s are first replaced with \\uFFFD. If s contains -->, --!>, or starts with -*>, insert a space right before > to stop state breaking at . If s ends with --!, --, or -, append a space to stop collaborative state breaking at {{{yc s}}}>, {{{yc s}}}!>, {{{yc s}}}-!>, {{{yc s}}}->. If s contains ]> or ends with ], append a space after ] is verified in IE to stop IE conditional comments.\n*\n* @description\n* This filter is to be placed in HTML Comment context\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n*\n*/\nexports.inHTMLComment = privFilters.yc;\n\n/**\n* @function module:xss-filters#inSingleQuotedAttr\n*\n* @param {string} s - An untrusted user input\n* @returns {string} The string s with any single-quote characters encoded into '&''.\n*\n* @description\n*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

\n*

Warning: If you're working on URI/components, use the more specific uri___InSingleQuotedAttr filter

\n* This filter is to be placed in HTML Attribute Value (single-quoted) state to encode all single-quote characters into '&''\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n*\n*/\nexports.inSingleQuotedAttr = privFilters.yavs;\n\n/**\n* @function module:xss-filters#inDoubleQuotedAttr\n*\n* @param {string} s - An untrusted user input\n* @returns {string} The string s with any single-quote characters encoded into '&"'.\n*\n* @description\n*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

\n*

Warning: If you're working on URI/components, use the more specific uri___InDoubleQuotedAttr filter

\n* This filter is to be placed in HTML Attribute Value (double-quoted) state to encode all single-quote characters into '&"'\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n*\n*/\nexports.inDoubleQuotedAttr = privFilters.yavd;\n\n/**\n* @function module:xss-filters#inUnQuotedAttr\n*\n* @param {string} s - An untrusted user input\n* @returns {string} If s contains any state breaking chars (\\t, \\n, \\v, \\f, \\r, space, null, ', \", `, <, >, and =), they are escaped and encoded into their equivalent HTML entity representations. If the string is empty, inject a \\uFFFD character.\n*\n* @description\n*

Warning: This is NOT designed for any onX (e.g., onclick) attributes!

\n*

Warning: If you're working on URI/components, use the more specific uri___InUnQuotedAttr filter

\n*

Regarding \\uFFFD injection, given ,
\n* Rationale 1: our belief is that developers wouldn't expect when id equals an\n* empty string would result in ' name=\"passwd\"' rendered as \n* attribute value, even though this is how HTML5 is specified.
\n* Rationale 2: an empty or all null string (for IE) can \n* effectively alter its immediate subsequent state, we choose\n* \\uFFFD to end the unquoted attr \n* state, which therefore will not mess up later contexts.
\n* Rationale 3: Since IE 6, it is verified that NULL chars are stripped.
\n* Reference: https://html.spec.whatwg.org/multipage/syntax.html#attribute-value-(unquoted)-state

\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n*\n*/\nexports.inUnQuotedAttr = privFilters.yavu;\n\n\n/**\n* @function module:xss-filters#uriInSingleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly an absolute URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (single-quoted) state for an absolute URI.
\n* The correct order of encoders is thus: first window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriInSingleQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavs);\n};\n\n/**\n* @function module:xss-filters#uriInDoubleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly an absolute URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (double-quoted) state for an absolute URI.
\n* The correct order of encoders is thus: first window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriInDoubleQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavd);\n};\n\n\n/**\n* @function module:xss-filters#uriInUnQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly an absolute URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (unquoted) state for an absolute URI.
\n* The correct order of encoders is thus: first the built-in encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriInUnQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavu);\n};\n\n/**\n* @function module:xss-filters#uriInHTMLData\n*\n* @param {string} s - An untrusted user input, supposedly an absolute URI\n* @returns {string} The string s encoded by window.encodeURI() and then inHTMLData()\n*\n* @description\n* This filter is to be placed in HTML Data state for an absolute URI.\n*\n*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURI().

\n*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* {{{uriInHTMLData full_uri}}}\n* \n*/\nexports.uriInHTMLData = privFilters.yufull;\n\n\n/**\n* @function module:xss-filters#uriInHTMLComment\n*\n* @param {string} s - An untrusted user input, supposedly an absolute URI\n* @returns {string} The string s encoded by window.encodeURI(), and finally inHTMLComment()\n*\n* @description\n* This filter is to be placed in HTML Comment state for an absolute URI.\n*\n*

Notice: This filter is IPv6 friendly by not encoding '[' and ']'.

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n* \n*/\nexports.uriInHTMLComment = function (s) {\n return privFilters.yc(privFilters.yufull(s));\n};\n\n\n\n\n/**\n* @function module:xss-filters#uriPathInSingleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Path/Query or relative URI.
\n* The correct order of encoders is thus: first window.encodeURI(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* link\n* \n*/\nexports.uriPathInSingleQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavs, privFilters.yu);\n};\n\n/**\n* @function module:xss-filters#uriPathInDoubleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Path/Query or relative URI.
\n* The correct order of encoders is thus: first window.encodeURI(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* link\n* \n*/\nexports.uriPathInDoubleQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavd, privFilters.yu);\n};\n\n\n/**\n* @function module:xss-filters#uriPathInUnQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI\n* @returns {string} The string s encoded first by window.encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Path/Query or relative URI.
\n* The correct order of encoders is thus: first the built-in encodeURI(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* link\n* \n*/\nexports.uriPathInUnQuotedAttr = function (s) {\n return uriInAttr(s, privFilters.yavu, privFilters.yu);\n};\n\n/**\n* @function module:xss-filters#uriPathInHTMLData\n*\n* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI\n* @returns {string} The string s encoded by window.encodeURI() and then inHTMLData()\n*\n* @description\n* This filter is to be placed in HTML Data state for a URI Path/Query or relative URI.\n*\n*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURI().

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* http://example.com/{{{uriPathInHTMLData uri_path}}}\n* http://example.com/?{{{uriQueryInHTMLData uri_query}}}\n* \n*/\nexports.uriPathInHTMLData = privFilters.yu;\n\n\n/**\n* @function module:xss-filters#uriPathInHTMLComment\n*\n* @param {string} s - An untrusted user input, supposedly a URI Path/Query or relative URI\n* @returns {string} The string s encoded by window.encodeURI(), and finally inHTMLComment()\n*\n* @description\n* This filter is to be placed in HTML Comment state for a URI Path/Query or relative URI.\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n* \n*/\nexports.uriPathInHTMLComment = function (s) {\n return privFilters.yc(privFilters.yu(s));\n};\n\n\n/**\n* @function module:xss-filters#uriQueryInSingleQuotedAttr\n* @description This is an alias of {@link module:xss-filters#uriPathInSingleQuotedAttr}\n* \n* @alias module:xss-filters#uriPathInSingleQuotedAttr\n*/\nexports.uriQueryInSingleQuotedAttr = exports.uriPathInSingleQuotedAttr;\n\n/**\n* @function module:xss-filters#uriQueryInDoubleQuotedAttr\n* @description This is an alias of {@link module:xss-filters#uriPathInDoubleQuotedAttr}\n* \n* @alias module:xss-filters#uriPathInDoubleQuotedAttr\n*/\nexports.uriQueryInDoubleQuotedAttr = exports.uriPathInDoubleQuotedAttr;\n\n/**\n* @function module:xss-filters#uriQueryInUnQuotedAttr\n* @description This is an alias of {@link module:xss-filters#uriPathInUnQuotedAttr}\n* \n* @alias module:xss-filters#uriPathInUnQuotedAttr\n*/\nexports.uriQueryInUnQuotedAttr = exports.uriPathInUnQuotedAttr;\n\n/**\n* @function module:xss-filters#uriQueryInHTMLData\n* @description This is an alias of {@link module:xss-filters#uriPathInHTMLData}\n* \n* @alias module:xss-filters#uriPathInHTMLData\n*/\nexports.uriQueryInHTMLData = exports.uriPathInHTMLData;\n\n/**\n* @function module:xss-filters#uriQueryInHTMLComment\n* @description This is an alias of {@link module:xss-filters#uriPathInHTMLComment}\n* \n* @alias module:xss-filters#uriPathInHTMLComment\n*/\nexports.uriQueryInHTMLComment = exports.uriPathInHTMLComment;\n\n\n\n/**\n* @function module:xss-filters#uriComponentInSingleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Component\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inSingleQuotedAttr()\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Component.
\n* The correct order of encoders is thus: first window.encodeURIComponent(), then inSingleQuotedAttr()\n*\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriComponentInSingleQuotedAttr = function (s) {\n return privFilters.yavs(privFilters.yuc(s));\n};\n\n/**\n* @function module:xss-filters#uriComponentInDoubleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Component\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inDoubleQuotedAttr()\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Component.
\n* The correct order of encoders is thus: first window.encodeURIComponent(), then inDoubleQuotedAttr()\n*\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriComponentInDoubleQuotedAttr = function (s) {\n return privFilters.yavd(privFilters.yuc(s));\n};\n\n\n/**\n* @function module:xss-filters#uriComponentInUnQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Component\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inUnQuotedAttr()\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Component.
\n* The correct order of encoders is thus: first the built-in encodeURIComponent(), then inUnQuotedAttr()\n*\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriComponentInUnQuotedAttr = function (s) {\n return privFilters.yavu(privFilters.yuc(s));\n};\n\n/**\n* @function module:xss-filters#uriComponentInHTMLData\n*\n* @param {string} s - An untrusted user input, supposedly a URI Component\n* @returns {string} The string s encoded by window.encodeURIComponent() and then inHTMLData()\n*\n* @description\n* This filter is to be placed in HTML Data state for a URI Component.\n*\n*

Notice: The actual implementation skips inHTMLData(), since '<' is already encoded as '%3C' by encodeURIComponent().

\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* http://example.com/?q={{{uriComponentInHTMLData uri_component}}}\n* http://example.com/#{{{uriComponentInHTMLData uri_fragment}}}\n* \n*/\nexports.uriComponentInHTMLData = privFilters.yuc;\n\n\n/**\n* @function module:xss-filters#uriComponentInHTMLComment\n*\n* @param {string} s - An untrusted user input, supposedly a URI Component\n* @returns {string} The string s encoded by window.encodeURIComponent(), and finally inHTMLComment()\n*\n* @description\n* This filter is to be placed in HTML Comment state for a URI Component.\n*\n* \n*\n* @example\n* // output context to be applied by this filter.\n* \n* \n*/\nexports.uriComponentInHTMLComment = function (s) {\n return privFilters.yc(privFilters.yuc(s));\n};\n\n\n// uriFragmentInSingleQuotedAttr\n// added yubl on top of uriComponentInAttr \n// Rationale: given pattern like this: \n// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)'\n\n/**\n* @function module:xss-filters#uriFragmentInSingleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Fragment\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (single-quoted) state for a URI Fragment.
\n* The correct order of encoders is thus: first window.encodeURIComponent(), then inSingleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*\n*
\n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriFragmentInSingleQuotedAttr = function (s) {\n return privFilters.yubl(privFilters.yavs(privFilters.yuc(s)));\n};\n\n// uriFragmentInDoubleQuotedAttr\n// added yubl on top of uriComponentInAttr \n// Rationale: given pattern like this: \n// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)'\n\n/**\n* @function module:xss-filters#uriFragmentInDoubleQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Fragment\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (double-quoted) state for a URI Fragment.
\n* The correct order of encoders is thus: first window.encodeURIComponent(), then inDoubleQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*\n*
\n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriFragmentInDoubleQuotedAttr = function (s) {\n return privFilters.yubl(privFilters.yavd(privFilters.yuc(s)));\n};\n\n// uriFragmentInUnQuotedAttr\n// added yubl on top of uriComponentInAttr \n// Rationale: given pattern like this: \n// developer may expect s is always prefixed with #, but an attacker can abuse it with 'javascript:alert(1)'\n\n/**\n* @function module:xss-filters#uriFragmentInUnQuotedAttr\n*\n* @param {string} s - An untrusted user input, supposedly a URI Fragment\n* @returns {string} The string s encoded first by window.encodeURIComponent(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n* @description\n* This filter is to be placed in HTML Attribute Value (unquoted) state for a URI Fragment.
\n* The correct order of encoders is thus: first the built-in encodeURIComponent(), then inUnQuotedAttr(), and finally prefix the resulted string with 'x-' if it begins with 'javascript:' or 'vbscript:' that could possibly lead to script execution\n*\n*
\n*\n* @example\n* // output context to be applied by this filter.\n* link\n* \n*/\nexports.uriFragmentInUnQuotedAttr = function (s) {\n return privFilters.yubl(privFilters.yavu(privFilters.yuc(s)));\n};\n\n\n/**\n* @function module:xss-filters#uriFragmentInHTMLData\n* @description This is an alias of {@link module:xss-filters#uriComponentInHTMLData}\n* \n* @alias module:xss-filters#uriComponentInHTMLData\n*/\nexports.uriFragmentInHTMLData = exports.uriComponentInHTMLData;\n\n/**\n* @function module:xss-filters#uriFragmentInHTMLComment\n* @description This is an alias of {@link module:xss-filters#uriComponentInHTMLComment}\n* \n* @alias module:xss-filters#uriComponentInHTMLComment\n*/\nexports.uriFragmentInHTMLComment = exports.uriComponentInHTMLComment;\n","/*!\n * pascalcase \n *\n * Copyright (c) 2015, Jon Schlinkert.\n * Licensed under the MIT License.\n */\n\nfunction pascalcase(str) {\n if (typeof str !== 'string') {\n throw new TypeError('expected a string.');\n }\n str = str.replace(/([A-Z])/g, ' $1');\n if (str.length === 1) { return str.toUpperCase(); }\n str = str.replace(/^[\\W_]+|[\\W_]+$/g, '').toLowerCase();\n str = str.charAt(0).toUpperCase() + str.slice(1);\n return str.replace(/[\\W_]+(\\w|$)/g, function (_, ch) {\n return ch.toUpperCase();\n });\n}\n\nmodule.exports = pascalcase;\n","'use strict';\n\nvar React = require('react');\nvar assign = require('lodash.assign');\nvar isPlainObject = require('lodash.isplainobject');\nvar xssFilters = require('xss-filters');\nvar pascalCase = require('pascalcase');\n\nvar typeAliases = {\n blockquote: 'block_quote',\n thematicbreak: 'thematic_break',\n htmlblock: 'html_block',\n htmlinline: 'html_inline',\n codeblock: 'code_block',\n hardbreak: 'linebreak'\n};\n\nvar defaultRenderers = {\n block_quote: 'blockquote', // eslint-disable-line camelcase\n emph: 'em',\n linebreak: 'br',\n image: 'img',\n item: 'li',\n link: 'a',\n paragraph: 'p',\n strong: 'strong',\n thematic_break: 'hr', // eslint-disable-line camelcase\n\n html_block: HtmlRenderer, // eslint-disable-line camelcase\n html_inline: HtmlRenderer, // eslint-disable-line camelcase\n\n list: function List(props) {\n var tag = props.type.toLowerCase() === 'bullet' ? 'ul' : 'ol';\n var attrs = getCoreProps(props);\n\n if (props.start !== null && props.start !== 1) {\n attrs.start = props.start.toString();\n }\n\n return createElement(tag, attrs, props.children);\n },\n code_block: function CodeBlock(props) { // eslint-disable-line camelcase\n var className = props.language && 'language-' + props.language;\n var code = createElement('code', { className: className }, props.literal);\n return createElement('pre', getCoreProps(props), code);\n },\n code: function Code(props) {\n return createElement('code', getCoreProps(props), props.children);\n },\n heading: function Heading(props) {\n return createElement('h' + props.level, getCoreProps(props), props.children);\n },\n\n text: null,\n softbreak: null\n};\n\nvar coreTypes = Object.keys(defaultRenderers);\n\nfunction getCoreProps(props) {\n var propKeys = Object.keys(props);\n\n var dataPropKeys = propKeys.filter(function(propKey) {\n return propKey.match(/data-.*/g);\n });\n\n var base = {\n key: props.nodeKey,\n className: props.className\n };\n\n var dataAttributes = dataPropKeys.reduce(function(prev, dataPropKey) {\n var attributes = {};\n attributes[dataPropKey] = props[dataPropKey];\n\n return assign(attributes, prev);\n }, {});\n\n return assign(dataAttributes, base);\n}\n\nfunction normalizeTypeName(typeName) {\n var norm = typeName.toLowerCase();\n var type = typeAliases[norm] || norm;\n return typeof defaultRenderers[type] !== 'undefined' ? type : typeName;\n}\n\nfunction normalizeRenderers(renderers) {\n return Object.keys(renderers || {}).reduce(function(normalized, type) {\n var norm = normalizeTypeName(type);\n normalized[norm] = renderers[type];\n return normalized;\n }, {});\n}\n\nfunction HtmlRenderer(props) {\n var coreProps = getCoreProps(props);\n var nodeProps = props.escapeHtml ? {} : { dangerouslySetInnerHTML: { __html: props.literal } };\n var children = props.escapeHtml ? [props.literal] : null;\n\n if (props.escapeHtml || !props.skipHtml) {\n var actualProps = assign(coreProps, nodeProps);\n return createElement(props.isBlock ? 'div' : 'span', actualProps, children);\n }\n}\n\nfunction isGrandChildOfList(node) {\n var grandparent = node.parent.parent;\n return (\n grandparent &&\n grandparent.type.toLowerCase() === 'list' &&\n grandparent.listTight\n );\n}\n\nfunction addChild(node, child) {\n var parent = node;\n do {\n parent = parent.parent;\n } while (!parent.react);\n\n parent.react.children.push(child);\n}\n\nfunction createElement(tagName, props, children) {\n var nodeChildren = Array.isArray(children) && children.reduce(reduceChildren, []);\n var args = [tagName, props].concat(nodeChildren || children);\n return React.createElement.apply(React, args);\n}\n\nfunction reduceChildren(children, child) {\n var lastIndex = children.length - 1;\n if (typeof child === 'string' && typeof children[lastIndex] === 'string') {\n children[lastIndex] += child;\n } else {\n children.push(child);\n }\n\n return children;\n}\n\nfunction flattenPosition(pos) {\n return [\n pos[0][0], ':', pos[0][1], '-',\n pos[1][0], ':', pos[1][1]\n ].map(String).join('');\n}\n\n// For some nodes, we want to include more props than for others\nfunction getNodeProps(node, key, opts, renderer) {\n var props = { key: key }, undef;\n\n // `sourcePos` is true if the user wants source information (line/column info from markdown source)\n if (opts.sourcePos && node.sourcepos) {\n props['data-sourcepos'] = flattenPosition(node.sourcepos);\n }\n\n var type = normalizeTypeName(node.type);\n\n switch (type) {\n case 'html_inline':\n case 'html_block':\n props.isBlock = type === 'html_block';\n props.escapeHtml = opts.escapeHtml;\n props.skipHtml = opts.skipHtml;\n break;\n case 'code_block':\n var codeInfo = node.info ? node.info.split(/ +/) : [];\n if (codeInfo.length > 0 && codeInfo[0].length > 0) {\n props.language = codeInfo[0];\n props.codeinfo = codeInfo;\n }\n break;\n case 'code':\n props.children = node.literal;\n props.inline = true;\n break;\n case 'heading':\n props.level = node.level;\n break;\n case 'softbreak':\n props.softBreak = opts.softBreak;\n break;\n case 'link':\n props.href = opts.transformLinkUri ? opts.transformLinkUri(node.destination) : node.destination;\n props.title = node.title || undef;\n if (opts.linkTarget) {\n props.target = opts.linkTarget;\n }\n break;\n case 'image':\n props.src = opts.transformImageUri ? opts.transformImageUri(node.destination) : node.destination;\n props.title = node.title || undef;\n\n // Commonmark treats image description as children. We just want the text\n props.alt = node.react.children.join('');\n node.react.children = undef;\n break;\n case 'list':\n props.start = node.listStart;\n props.type = node.listType;\n props.tight = node.listTight;\n break;\n default:\n }\n\n if (typeof renderer !== 'string') {\n props.literal = node.literal;\n }\n\n var children = props.children || (node.react && node.react.children);\n if (Array.isArray(children)) {\n props.children = children.reduce(reduceChildren, []) || null;\n }\n\n return props;\n}\n\nfunction getPosition(node) {\n if (!node) {\n return null;\n }\n\n if (node.sourcepos) {\n return flattenPosition(node.sourcepos);\n }\n\n return getPosition(node.parent);\n}\n\nfunction renderNodes(block) {\n var walker = block.walker();\n\n var propOptions = {\n sourcePos: this.sourcePos,\n escapeHtml: this.escapeHtml,\n skipHtml: this.skipHtml,\n transformLinkUri: this.transformLinkUri,\n transformImageUri: this.transformImageUri,\n softBreak: this.softBreak,\n linkTarget: this.linkTarget\n };\n\n var e, node, entering, leaving, type, doc, key, nodeProps, prevPos, prevIndex = 0;\n while ((e = walker.next())) {\n var pos = getPosition(e.node.sourcepos ? e.node : e.node.parent);\n if (prevPos === pos) {\n key = pos + prevIndex;\n prevIndex++;\n } else {\n key = pos;\n prevIndex = 0;\n }\n\n prevPos = pos;\n entering = e.entering;\n leaving = !entering;\n node = e.node;\n type = normalizeTypeName(node.type);\n nodeProps = null;\n\n // If we have not assigned a document yet, assume the current node is just that\n if (!doc) {\n doc = node;\n node.react = { children: [] };\n continue;\n } else if (node === doc) {\n // When we're leaving...\n continue;\n }\n\n // In HTML, we don't want paragraphs inside of list items\n if (type === 'paragraph' && isGrandChildOfList(node)) {\n continue;\n }\n\n // If we're skipping HTML nodes, don't keep processing\n if (this.skipHtml && (type === 'html_block' || type === 'html_inline')) {\n continue;\n }\n\n var isDocument = node === doc;\n var disallowedByConfig = this.allowedTypes.indexOf(type) === -1;\n var disallowedByUser = false;\n\n // Do we have a user-defined function?\n var isCompleteParent = node.isContainer && leaving;\n var renderer = this.renderers[type];\n if (this.allowNode && (isCompleteParent || !node.isContainer)) {\n var nodeChildren = isCompleteParent ? node.react.children : [];\n\n nodeProps = getNodeProps(node, key, propOptions, renderer);\n disallowedByUser = !this.allowNode({\n type: pascalCase(type),\n renderer: this.renderers[type],\n props: nodeProps,\n children: nodeChildren\n });\n }\n\n if (!isDocument && (disallowedByUser || disallowedByConfig)) {\n if (!this.unwrapDisallowed && entering && node.isContainer) {\n walker.resumeAt(node, false);\n }\n\n continue;\n }\n\n var isSimpleNode = type === 'text' || type === 'softbreak';\n if (typeof renderer !== 'function' && !isSimpleNode && typeof renderer !== 'string') {\n throw new Error(\n 'Renderer for type `' + pascalCase(node.type) + '` not defined or is not renderable'\n );\n }\n\n if (node.isContainer && entering) {\n node.react = {\n component: renderer,\n props: {},\n children: []\n };\n } else {\n var childProps = nodeProps || getNodeProps(node, key, propOptions, renderer);\n if (renderer) {\n childProps = typeof renderer === 'string'\n ? childProps\n : assign(childProps, {nodeKey: childProps.key});\n\n addChild(node, React.createElement(renderer, childProps));\n } else if (type === 'text') {\n addChild(node, node.literal);\n } else if (type === 'softbreak') {\n // Softbreaks are usually treated as newlines, but in HTML we might want explicit linebreaks\n var softBreak = (\n this.softBreak === 'br' ?\n React.createElement('br', {key: key}) :\n this.softBreak\n );\n addChild(node, softBreak);\n }\n }\n }\n\n return doc.react.children;\n}\n\nfunction defaultLinkUriFilter(uri) {\n var url = uri.replace(/file:\\/\\//g, 'x-file://');\n\n // React does a pretty swell job of escaping attributes,\n // so to prevent double-escaping, we need to decode\n return decodeURI(xssFilters.uriInDoubleQuotedAttr(url));\n}\n\nfunction ReactRenderer(options) {\n var opts = options || {};\n\n if (opts.allowedTypes && opts.disallowedTypes) {\n throw new Error('Only one of `allowedTypes` and `disallowedTypes` should be defined');\n }\n\n if (opts.allowedTypes && !Array.isArray(opts.allowedTypes)) {\n throw new Error('`allowedTypes` must be an array');\n }\n\n if (opts.disallowedTypes && !Array.isArray(opts.disallowedTypes)) {\n throw new Error('`disallowedTypes` must be an array');\n }\n\n if (opts.allowNode && typeof opts.allowNode !== 'function') {\n throw new Error('`allowNode` must be a function');\n }\n\n var linkFilter = opts.transformLinkUri;\n if (typeof linkFilter === 'undefined') {\n linkFilter = defaultLinkUriFilter;\n } else if (linkFilter && typeof linkFilter !== 'function') {\n throw new Error('`transformLinkUri` must either be a function, or `null` to disable');\n }\n\n var imageFilter = opts.transformImageUri;\n if (typeof imageFilter !== 'undefined' && typeof imageFilter !== 'function') {\n throw new Error('`transformImageUri` must be a function');\n }\n\n if (opts.renderers && !isPlainObject(opts.renderers)) {\n throw new Error('`renderers` must be a plain object of `Type`: `Renderer` pairs');\n }\n\n var allowedTypes = (opts.allowedTypes && opts.allowedTypes.map(normalizeTypeName)) || coreTypes;\n if (opts.disallowedTypes) {\n var disallowed = opts.disallowedTypes.map(normalizeTypeName);\n allowedTypes = allowedTypes.filter(function filterDisallowed(type) {\n return disallowed.indexOf(type) === -1;\n });\n }\n\n return {\n sourcePos: Boolean(opts.sourcePos),\n softBreak: opts.softBreak || '\\n',\n renderers: assign({}, defaultRenderers, normalizeRenderers(opts.renderers)),\n escapeHtml: Boolean(opts.escapeHtml),\n skipHtml: Boolean(opts.skipHtml),\n transformLinkUri: linkFilter,\n transformImageUri: imageFilter,\n allowNode: opts.allowNode,\n allowedTypes: allowedTypes,\n unwrapDisallowed: Boolean(opts.unwrapDisallowed),\n render: renderNodes,\n linkTarget: opts.linkTarget || false\n };\n}\n\nReactRenderer.uriTransformer = defaultLinkUriFilter;\nReactRenderer.types = coreTypes.map(pascalCase);\nReactRenderer.renderers = coreTypes.reduce(function(renderers, type) {\n renderers[pascalCase(type)] = defaultRenderers[type];\n return renderers;\n}, {});\n\nmodule.exports = ReactRenderer;\n","'use strict';\n\nvar React = require('react');\nvar Parser = require('commonmark').Parser;\nvar ReactRenderer = require('commonmark-react-renderer');\nvar propTypes = require('prop-types');\n\nfunction ReactMarkdown(props) {\n React.Component.call(this, props);\n}\n\nReactMarkdown.prototype = Object.create(React.Component.prototype);\nReactMarkdown.prototype.constructor = ReactMarkdown;\n\nReactMarkdown.prototype.render = function() {\n var containerProps = this.props.containerProps || {};\n var renderer = new ReactRenderer(this.props);\n var parser = new Parser(this.props.parserOptions);\n var ast = parser.parse(this.props.source || '');\n\n if (this.props.walker) {\n var walker = ast.walker();\n var event;\n\n while ((event = walker.next())) {\n this.props.walker.call(this, event, walker);\n }\n }\n\n if (this.props.className) {\n containerProps.className = this.props.className;\n }\n\n return React.createElement.apply(React,\n [this.props.containerTagName, containerProps, this.props.childBefore]\n .concat(renderer.render(ast).concat(\n [this.props.childAfter]\n ))\n );\n};\n\nReactMarkdown.propTypes = {\n className: propTypes.string,\n containerProps: propTypes.object,\n source: propTypes.string.isRequired,\n containerTagName: propTypes.string,\n childBefore: propTypes.object,\n childAfter: propTypes.object,\n sourcePos: propTypes.bool,\n escapeHtml: propTypes.bool,\n skipHtml: propTypes.bool,\n softBreak: propTypes.string,\n allowNode: propTypes.func,\n allowedTypes: propTypes.array,\n disallowedTypes: propTypes.array,\n transformLinkUri: propTypes.func,\n transformImageUri: propTypes.func,\n unwrapDisallowed: propTypes.bool,\n renderers: propTypes.object,\n walker: propTypes.func,\n parserOptions: propTypes.object\n};\n\nReactMarkdown.defaultProps = {\n containerTagName: 'div',\n parserOptions: {}\n};\n\nReactMarkdown.types = ReactRenderer.types;\nReactMarkdown.renderers = ReactRenderer.renderers;\nReactMarkdown.uriTransformer = ReactRenderer.uriTransformer;\n\nmodule.exports = ReactMarkdown;\n","import React from 'react';\nimport ReactMarkdown from 'react-markdown';\n\nconst PreviewCard = (props) => {\n const color = props.color || 'green'\n\n return (\n \n \n Read\n \n )\n}\n\n\nexport default PreviewCard\n","import React from 'react';\nimport HeaderSection from '../components/blog_posts/header_section';\nimport PreviewCard from '../components/shared/preview_card.jsx';\n\nexport default (props) => {\n const articles = props.blogPosts.length > 0 ? props.blogPosts.map(article =>\n ()\n ) : null\n const content = articles ?
{articles}
\n : (
\n Coming Soon!\n \"\"\n
)\n return (\n
\n \n {content}\n
\n )\n}\n","import React from 'react'\n\nconst admin = () => [\n {\n question: 'How does the Professional Development work?',\n answer:

After upgrading to Quill School Premium, you’ll receive an email from our team with next steps, which include setting up your professional development session.

\n },\n {\n question: 'How can I arrange the Professional Development session?',\n answer: [

In order to set up that session, you will set up an initial 15-minute call between your PD coordinator and our School Partnerships team to discuss tailoring the session school goals and writing curriculum, which tools you’d like to highlight, and when you’d like the session to happen. You can do this by signing up at quill-partnerships.youcanbook.me.

,\n

Teachers will be asked to set up their Quill accounts prior to the session, so they can jump right into exploring Quill!

\n ]\n },\n {\n question: 'What is the Professional Development session structure like?',\n answer: [\n

The personalized session will last 45 to 75 minutes, and will involve a review of chosen tools as they relate to the school’s focus, and (time allowing) a conversation surrounding how teachers can effectively integrate Quill into their classroom. In the session, teachers will establish a direct line of communication with the School Partnerships team.

\n ]\n },\n {\n question: 'How will I access the Professional Development session?',\n answer: [

Sessions outside of New York City will be held remotely via Zoom, and will be recorded via Zoom to provide teachers with continued access to the information. Teachers will receive a follow up email with a reminder of resources and a link to the session recording.

]\n },\n {\n question: 'How does Premium Reporting Work?',\n answer: [\n

Teachers and administrators will continue to have access to basic reporting features, including the Activity Summary, Activity Analysis and Diagnostic reports. Here’s a guide on standard reports.

,\n

Premium teacher reports are available to teachers within their account and administrators via a link in the Administrator Dashboard. Those reports include List Overview, Concepts and Common Core Standards reporting. You will be able to download and print each of the premium reports to share with your colleagues, administrators or parents. Here’s a guide on Premium Reports.

\n ]\n },\n {\n question: 'What resources can I use to introduce Quill to the teachers in my school?',\n answer: [

You can access a two-page handout to introduce teachers to Quill here. Your teachers can use the teacher resources page to access in-depth guides and video overviews.

]\n }\n]\n\nexport default admin\n","import React from 'react'\n\nconst ap = () => [\n {\n question: 'What is Quill.org?',\n answer:

Quill is a writing tool that provides over 700 writing, grammar, and proofreading activities designed to engage students in the writing process. Quill provides practice in many areas of sentence writing, from comma placement and subject-verb agreement to the use of conjunctions to convey complex relationships between ideas. In the Quill Connect tool, students practice writing different types of sentences using the evidence-based strategy of sentence combining. Students receive specific, targeted feedback on their writing that they can use to revise their work. Through these activities, students practice writing a variety of sophisticated sentences and practice conveying complex ideas in clear, succinct, and grammatically strong ways. Most activities are designed to be completed in 10-15 minutes so that you have the freedom to use them in the way that works best for your classroom.

\n },\n {\n question: 'What is the AP Writing Skills Survey?',\n answer:

The AP Writing Skills Survey is a survey with 17 questions on a range of writing skills. The questions ask students to combine sentences, sometimes with a direction to use a specific strategy, and sometimes without any direction (other than to combine).

\n },\n {\n question: 'For which AP courses is this practice most relevant?',\n answer:

Students in any AP course can benefit from the practice recommended by Quill's AP Writing Skills Survey, but the practice is probably of greatest interest to teachers of AP English Language and Composition and AP English Literature and Composition.

\n },\n {\n question: 'Is a writing skills survey different than a diagnostic?',\n answer:

Quill's writing skills surveys can be used in lieu of Quill's general diagnostics. For example, an AP teacher would likely assign the AP Writing Skills Survey in lieu of the Advanced Diagnostic. Keep in mind, however, that teachers may want ELL students in AP courses to begin with one of the ELL Diagnostics instead of a writing skills survey. This article explains the differences between Quill’s various diagnostics and surveys in more depth.

\n },\n {\n question: 'How long does the Survey take?',\n answer:

The Survey contains 17 questions and is designed to take about 30 minutes for students to complete.

\n },\n {\n question: 'What happens after I assign the Survey and my students complete it?',\n answer:

After you have assigned the Survey and your students have completed it, Quill will show you how your students performed and provide recommendations of personalized practice activities you can digitally assign to students who need further skill development. This article explains how to find and assign those recommendations.

\n },\n {\n question: 'What kind of activities will be recommended to my students after they take the AP Writing Skills Survey?',\n answer: (\n
\n

Depending on their performance, students will be recommended some or all of the following AP Writing Practice packs. The packs provide practice through Quill Connect, Quill's sentence combining tool. With the exception of the AP Writing - Advanced Sentence Combining pack, the activities in each pack are scaffolded to build in complexity. Here are descriptions of the packs:

\n

AP Writing Practice - Complex Sentences

\n

Students practice constructing complex sentences using subordinating conjunctions, such as even though, after, while, and because. Students also practice identifying time order, opposition, and cause/effect relationships.

\n

AP Writing Practice - Relative Clauses

\n

Students begin by using a provided relative pronoun, then progress to choosing between who, that, or which.

\n

AP Writing Practice - Appositive Phrases

\n

Students practice describing nouns using appositive phrases at the beginning, middle, and end of sentences.

\n

AP Writing Practice - Participial Phrases

\n

Students practice constructing sentences with -ing and -ed participial phrases at the beginning, middle, or end.

\n

AP Writing Practice - Parallel Structure

\n

Students practice constructing sentences in parallel structure with correlative conjunctions like either/or, neither/nor, and both/and, and with subordinating conjunctions like although, because, and when. Students also practice constructing sentences with parallel clauses.

\n

AP Writing Practice - Compound-Complex Sentences

\n

Students practice constructing compound sentences with and, or, but, and so. Students also practice constructing complex sentences with subordinating conjunctions such as even though, after, while, and because. Finally, students practice constructing compound-complex sentences with coordinating and subordinating conjunctions. Students also practice identifying time order, opposition, and cause/effect relationships.

\n

AP Writing Practice - Advanced Combining

\n

Students apply their knowledge of multiple sentence structures to combine the sentences in the strongest way possible. Students practice constructing compound and complex sentences, using modifying phrases and clauses, and combining predicates.

\n
\n )\n },\n {\n question: 'Can students complete the AP Writing Practice packs independently?',\n answer:

Yes! From anywhere and at any time! Again though, please note that recommendations of the AP Writing Packs are generated after students complete the AP Writing Skills Survey. Please also note that students' performance on the AP Writing Practice packs will only be recorded if they are assigned to them by their teacher.

\n },\n {\n question: 'How many activities are in each AP Writing Practice pack?',\n answer: (\n
\n

Each AP recommended pack* contains between 4 and 7 activities, each of which are designed to take between 10 and 15 minutes each.

\n

*Please note that the activities in the AP Writing - Advanced Combining pack are different as they are all uncued, meaning the feedback does not direct students to combine in a particular way. These are great for students who are ready to apply the strategies covered in the survey without suggestions or direction.

\n
\n )\n },\n {\n question: 'What grade-level or reading level are the AP Activity Packs designed for?',\n answer: (\n
\n

The focus in most of these activities is to build the target skill of the pack (appositives, relative clauses, etc.), so the vocabulary and reading level are intentionally designed to be accessible by all students.

\n

Teacher Tip: You can preview and play through any pack and its activities to get a sense of whether it's appropriate for your students.

\n
\n )\n },\n {\n question: 'Will my students receive feedback as they work through the AP Writing Practice activity packs?',\n answer: 'Yes! In each recommended practice activity, Quill provides students with immediate feedback on their writing that they can use to revise their responses up to 5 times. Through these rounds of feedback and revision, students improve the clarity and precision of their writing.'\n },\n {\n question: 'Where can I track my students\\' completion of and performance on the AP Writing Practice packs?',\n answer:

Quill has a variety of reports to help you track your students' performance and progress. In the Activity Summary report, you can quickly see which activities your students have completed, along with color-coded icons indicating their proficiency with each activity. Quill has several other reports as well. This Cheat Sheet shows you which report to go to for particular information, and this video will walk you through interpreting and utilizing three of Quill's student data reports.

\n },\n {\n question: 'How many AP Writing Practice packs should I assign to my students and how long will it take them to complete a pack?',\n answer: (\n
\n

You can assign all the recommended packs in one click, or you can pick and choose, revisiting the recommendations report to assign more packs as needed.

\n

As Quill was designed to be a supplementary tool with each activity taking approximately 10-15 minutes, students are ideally completing an activity at least 1-2 times per week (at most completing one activity per day). Since each AP recommended pack contains between 4 and 7 activities, teachers generally expect a recommended pack to be completed in 1-2 weeks. Of course, students may need more or less time depending on the amount of activities in the pack, their level of difficulty, and students' level of proficiency.

\n

This article explains how you can use deadlines to help students pace themselves.

\n
\n )\n },\n {\n question: 'If my students have been using Quill for a while, will they encounter activities in the AP Writing Practice packs that they have completed before?',\n answer:

The activities in the AP Writing Practice packs are curated from existing Quill activities. While your students may encounter an activity they have already completed, the AP Writing Practice packs have been customized to target the skills students need to write successfully at the AP level. Given the quantity and variety of activities available on Quill, chances are that the AP Writing Practice packs will include plenty of new activities, even for students who have been using Quill for a while.

\n },\n {\n question: 'Can I assign my students practice beyond the recommended AP Writing Practice packs?',\n answer:

Yes! Quill offers 5 different tools with more than 700 writing, grammar, and proofreading activities designed to engage students in the writing process. This article will show you how to explore and assign Quill’s featured activity packs, and this article will show you how to create a custom activity pack.

\n },\n {\n question: 'Do I need to create an account on Quill.org to assign the AP Writing Skills Survey?',\n answer: (\n
\n

It is recommended that you and your students create free accounts on Quill.org. Creating an account will give you access to the Survey and its recommended practice. Creating an account also allows you to track your students’ progress and view data reports. You can create an account by visiting the Quill sign-up page.

\n

If you do not want to create an account, you or your students can complete the Survey here. However, please note that if you do not create an account, your students’ performance on the Survey will not be saved or shared with you, and you will not have access to the recommended skills practice. You will also not be able to track student progress or view data reports.

\n
\n )\n },\n {\n question: 'What if I still have questions?',\n answer: (\n
\n

We are here for you! The following resources are available:

\n

Quill Instructional Coach: You can reach out to us atpd@quill.org. Be sure to mention the course(s) you teach.

\n

Teacher Center: The place to go for all things best practice and implementation!

\n

Support: Having a technical issue? Email support@quill.org or use the chat in the lower right corner of Quill to connect with a member of the Quill support team.

\n

AP® is a registered trademark of the College Board.

\n
\n )\n }\n]\n\nexport default ap\n","import React from 'react'\n\nconst lessons = () => [\n {\n question: 'How much time should I allot for a Quill Lesson?',\n answer: [

Lessons are intended to take about 20-30 minutes to complete. The length of time depends on how long you choose to spend discussing each answer. While in most cases five minutes is enough, teachers may want to facilitate a longer conversation.

,\n

To end a lesson early, press the “Start Practice Mode” button or “End Session” button in the toolbar at any time. To continue a lesson with a selected group of students, you can assign other students to start independent practice while keeping the lesson open for your group.

,\n

If you need to abbreviate your time on Quill, you can complete a lesson at any point, and wait to assign the follow up activity until another time.

\n ]\n },\n {\n question: 'How can I support both struggling students and advanced learners in lessons mode?',\n answer:

You can also use the flagging features to privately select students for extra support. If a student’s response requires intervention, you can click on the flag next to their answer, and they will show up in a list for you at the end of the lesson. At this point all other students can begin the independent practice while you work with a small group.

\n },\n {\n question: 'Can I skip slides?',\n answer: [

Yes, the slides and the step-by-step guide are a starting point to introduce these concepts to your learners. You can customize the lessons for your learners by editing all of the prompts and questions. Within each lesson, you can also skip slides by selecting a new slide from the preview section.

,\n

Coming soon: You will soon be able to create your own Lessons using the Quill interface! Keep an eye out for updates about this release.

\n ]\n },\n {\n question: 'How do I project a Quill Lesson?',\n answer: [

After you have launched a lesson, click on the “Launch Projector” icon in the navigation bar at the top. This will open a new window with student facing slides only. In order to ensure that the projector does NOT mirror your screen or show students the teacher notes:

,\n

For PC:

,\n
    \n
  1. Go to Control Panel or right-click on your desktop.
  2. \n
  3. Choose Display Settings.
  4. \n
  5. In the Multiple Display dropdown, select Extend Desktop to This Display.
  6. \n
,\n

For Mac:

,\n
    \n
  1. Go to System Preferences.
  2. \n
  3. Go to Displays.
  4. \n
  5. Next, select the Arrangement tab.
  6. \n
  7. Uncheck Mirror Displays.
  8. \n
,\n

Once you have unmirrored your screen from the projector, you can move the student slide window to the projector so the class could see it. You will be able to control what the students see and the projector slide from your teacher view.

\n ]\n },\n {\n question: 'How can I draw & write on a Quill Lesson using my SMARTboard?',\n answer:

We know that every interactive projector works in different ways. If your setup does not support writing in a browser, you can download the chrome extension Web Paint, and use that to interact with a Quill lesson.

\n },\n {\n question: 'How many answers should I display at a time?',\n answer:

We suggest that you project 2-3 student responses to allow for discussion. More than four responses might not all fit on the screen, and will require scrolling on the part of the students. If you want to discuss more than four answers, try projecting 2-3 options to start. Then deselect those answers and choose another set to continue the conversation.

\n }\n]\n\nexport default lessons\n","import React from 'react'\n\nconst preap = () => [\n {\n question: 'What is Quill.org?',\n answer:

Quill is a writing tool that provides over 600 writing, grammar, and proofreading activities designed to engage students in the writing process. Quill provides practice in many areas of sentence writing, from comma placement and subject-verb agreement to the use of conjunctions to convey complex relationships between ideas. In the Quill Connect tool, students practice writing different types of sentences using the evidence-based strategy of sentence combining. Students receive specific, targeted feedback on their writing that they can use to revise their work. Through these activities, students practice writing a variety of sophisticated sentences and practice conveying complex ideas in clear, succinct, and grammatically strong ways. Most activities are designed to be completed in 10-15 minutes so that you have the freedom to use them in the way that works best for your classroom.

\n },\n {\n question: 'How is Quill.org used in Pre-AP English 1?',\n answer: (\n
\n

As part of the customized Pre-AP + Quill Offering for English 1, there are two distinct skills surveys. Pre-AP Skills Survey 1 addresses the basics of sentence patterns, while Pre-AP Skills Survey 2 engages with tools for sentence expansion. The skills featured as part of each survey are derived directly from the elements of grammar called out by the Pre-AP English High School Course Framework.

\n

You can use these skills surveys during the course to assess your students’ needs and to generate a sequence of recommended activities that provides targeted writing practice on the skills addressed instructionally in the Learning Cycles. In each of these recommended practice activities, students receive immediate feedback on their writing that they can use to revise their responses up to five times. Through these rounds of feedback and revision, students practice key writing skills.

\n

In addition to the skills surveys and recommended practice activities, there are also sentence combining activities aligned to texts that are part of each unit’s instructional materials. These activities provide additional opportunities for students to practice their writing in context, combining sentences with a variety of skills and approaches that explore key ideas and themes from these texts.

\n

In addition to the previously mentioned tools and resources, you will also see direct links to Quill.org activities throughout English 1 lessons where specific grammar skills are addressed. The links will take students to independent practice activities that align with the writing goals of that particular lesson.

\n
\n )\n },\n {\n question: 'How is Quill.org used in Pre-AP English 2?',\n answer: (\n
\n

As part of the customized Pre-AP + Quill Offering for English 2, there are two distinct skills surveys. Pre-AP Skills Survey 1 addresses the basics of sentence patterns, while Pre-AP Skills Survey 2 engages with tools for sentence expansion. The skills featured as part of each survey are derived directly from the elements of grammar called out by the Pre-AP English High School Course Framework.

\n

You can use these skills surveys during the course to assess your students’ needs and to generate a sequence of recommended activities that provides targeted writing practice on the skills addressed instructionally in the Learning Cycles. In each of these recommended practice activities, students receive immediate feedback on their writing that they can use to revise their responses up to five times. Through these rounds of feedback and revision, students practice key writing skills.

\n

At this time, there are no sentence combining activities aligned to texts that are part of each unit’s instructional materials in Pre-AP English 2.

\n
\n )\n },\n {\n question: 'Do I need to create an account on Quill.org?',\n answer: (\n
\n

It is recommended that you and your students create free accounts on Quill.org. Creating an account will give you access to the two skills surveys and recommended practice; creating an account also allows you to track your students’ progress and view data reports. You can create an account by visiting the Quill sign-up page.

\n

If you do not want to create an account, the links provided throughout the English 1 lessons will allow you and your students to complete activities on Quill without Quill accounts.

\n

Please note that if you do not create an account, you will not be able to use the skills surveys, access the recommended skills practice, track student progress, or view data reports.

\n
\n )\n },\n {\n question: 'Is a writing skills survey different than a diagnostic?',\n answer:

Quill's writing skills surveys can be used in lieu of Quill's general diagnostics. For example, an AP teacher would likely assign the AP Writing Skills Survey in lieu of the Advanced Diagnostic. Keep in mind, however, that teachers may want ELL students in Pre-AP, AP, or SpringBoard courses to begin with one of the ELL Diagnostics instead of a writing skills survey. This article explains the differences between Quill’s various diagnostics and surveys in more depth.

\n },\n {\n question: 'How many activities are in each Pre-AP Writing Practice pack?',\n answer:

Each Pre-AP recommended pack contains between 4 and 7 activities, each of which are designed to take between 10 and 15 minutes each. There are also additional practice packs for students who finish the Pre-AP recommended packs: same skills, new content. Learn how to find and assign those here.

\n },\n {\n question: 'How many Pre-AP Writing Practice packs should I assign to my students and how long will it take them to complete a pack?',\n answer: (\n
\n

You can assign all the recommended packs in one click, or you can pick and choose, revisiting the recommendations report to assign more packs as needed.

\n

In general, we've found that students make progress when they are completing 2-4 activities on Quill per week. Since each Pre-AP recommended pack contains between 4 and 7 activities, teachers generally expect a recommended pack to be completed in 1-2 weeks. Of course, students may need more or less time depending on the amount of activities in the pack, their level of difficulty, and students' level of proficiency.

\n

This article explains how you can use deadlines to help students pace themselves.

\n
\n )\n },\n {\n question: \"Where can I track my students' completion of and performance on Quill activities?\",\n answer:

Quill has a variety of reports to help you track your students' performance and progress. In the Activity Summary report, you can quickly see which activities your students have completed, along with color-coded icons indicating proficiency. Quill has several other reports as well. This cheat sheet shows you which report to go to for particular information, and this video will walk you through 3 of Quill's student data reports.

\n },\n {\n question: 'What tools does Quill.org offer?',\n answer: (\n
\n

If you create a free account on Quill.org, you will be able to assign additional activities from any of Quill’s 5 tools:

\n
    \n
  • \n

    Quill Connect

    \n

    Students combine multiple ideas into a single sentence using the evidence-based strategy of sentence combining. Students receive instant feedback. *Note*: All activities recommended based on survey results are in Quill Connect.

    \n
  • \n
  • \n

    Quill Grammar

    \n

    Students practice basic grammar skills, from using correct capitalization to correcting commonly confused words.

    \n
  • \n
  • \n

    Quill Proofreader

    \n

    Students practice editing skills by correcting errors in passages. Students receive personalized follow-up activities based on their results.

    \n
  • \n
  • \n

    Quill Lessons

    \n

    Teachers lead whole-class writing instruction. Teachers control interactive slides that contain a mini-lesson and guided practice. Teachers can model writing strategies in real-time, present prompts to which students can respond, and then anonymously display student responses for discussion. Each Quill Lessons activity provides a lesson plan, writing prompts, discussion topics, and a follow-up independent practice activity. Teachers can also customize any lesson.

    \n
  • \n
  • \n

    Quill Diagnostic

    \n

    Students complete an activity designed to help teachers determine which skills students need to work on. After students complete a Quill Diagnostic activity, Quill recommends writing activities for students based on their results. Note: The writing skills surveys can be used in lieu of general Quill diagnostics.

    \n
  • \n
\n
\n )\n },\n {\n question: 'I see there are passage-aligned activities for Pre-AP English I. Are there passage-aligned activities for other Pre-AP courses?',\n answer:

Unfortunately, at this time, there are no sentence combining activities aligned to texts in Pre-AP courses other than English I. If you would like to see activities like these for another course, please us know here!

\n },\n {\n question: 'What if I still have questions?',\n answer: (\n
\n

We are here for you! The following resources are available:

\n

Quill Instructional Coach: You can reach out to us atpd@quill.org. Be sure to mention the course(s) you teach.

\n

Teacher Center: The place to go for all things best practice and implementation!

\n

Support: Having a technical issue? Email support@quill.org or use the chat in the lower right corner of Quill to connect with a member of the Quill support team.

\n
\n )\n },\n]\n\nexport default preap\n","import React from 'react'\n\nconst premium = () => [\n {\n question: 'What do I get with a free membership?',\n answer:

All of our apps and all of our activities will always remain free, forever. Teachers see their students' results in the scorebook, and teachers may hover over the activity result to see the details.

\n },\n {\n question: 'What do I get with a premium membership?',\n answer:

With Quill Premium, teachers can access Quill Progress Reports, which allow teachers to easily view and download their data. Quill Progress Reports show teachers how students are progressing on the Common Core and which concepts they need help with. With Quill Premium for Schools, teachers and administrators can access a school-wide dashboard that shows student progress and standards mastered across the entire school.

\n },\n {\n question: 'How does payment work on a premium membership?',\n answer:

Quill Premium is provided on an annual license based on the school year. You may pay via credit card or check. Credit cards will be billed annually for Teacher and School Premium. If you pay with a check, Quill will issue an invoice to renew your subscription.

\n },\n {\n question: 'How much does premium cost?',\n answer:

Quill Premium is provided as a teacher license, school license, or district license. The teacher license covers all of the students for one teacher and costs $80 per year. The school license is a site-wide license that covers all teachers and students in the school. For districts, we provide custom pricing, on-site training, and district dashboards. Contact us to receive a demo.

\n },\n {\n question: 'Do you accept purchase orders?',\n answer:

Yes, we accept purchase orders. You may email a purchase order to sales@quill.org. Access our W-9 and reach out with any questions at 510-671-0222.

\n },\n {\n question: 'Do you offer financial aid?',\n answer:

Yes, we provide Quill Premium for free to schools that have a demonstrated financial need. This funding is provided to select partners thanks to the support of our funders. Apply for financial aid.

\n },\n {\n question: 'Have more questions?',\n answer:

You can call us at 510-671-0222 or visit our Support Center.

\n }\n]\n\nexport default premium\n","import React from 'react'\n\nconst springboard = () => [\n {\n question: 'What is Quill.org?',\n answer: (\n
\n

Quill is a writing tool that provides over 600 writing, grammar, and proofreading activities designed to engage students in the writing process. Quill provides practice in many areas of sentence writing, from comma placement and subject-verb agreement to the use of conjunctions to convey complex relationships between ideas. In the Quill Connect tool, students practice writing different types of sentences using the evidence-based strategy of sentence combining. Students receive specific, targeted feedback on their writing that they can use to revise their work. Through these activities, students practice writing a variety of sophisticated sentences and practice conveying complex ideas in clear, succinct, and grammatically strong ways. Most activities are designed to be completed in 10-15 minutes so that you have the freedom to use them in the way that works best for your classroom.

\n

As part of the customized offering for SpringBoard, there are a variety of writing skills surveys to be used, depending on the context of your classes and students. The skills featured as part of each survey are derived directly from the elements of grammar called out by course texts and frameworks.

\n

You can use these skills surveys during the course to assess your students’ needs and to generate a sequence of recommended activities that provides targeted writing practice on the skills addressed instructionally. In each of these recommended practice activities, students receive immediate feedback on their writing that they can use to revise their responses up to five times. Through these rounds of feedback and revision, students practice key writing skills.

\n

In addition to the skills surveys and recommended practice activities, there are also sentence combining activities aligned to texts that appear in the instructional materials of both the Pre-AP English I course Grade 9 SpringBoard English Language Arts: English I. These activities provide additional opportunities for students to practice their writing in context, combining sentences with a variety of skills and approaches that explore key ideas and themes from these texts.

\n
\n )\n },\n {\n question: 'How do teachers typically incorporate Quill into their SpringBoard ELA courses?',\n answer: (\n
\n

Teachers generally begin by having students complete a writing skills survey during class time. The practice that is recommended once students complete a survey can be completed by students independently and at their own pace, or can also be completed during class time. Some teachers ask students to complete recommended activities during a “Do Now,” during another portion of class time, or as homework. Since SpringBoard’s Language and Writer’s Craft elements of activities feature focused practice on specific grammatical skills, you may also find that there are Quill Lessons (Quill’s whole-class instructional tool) that can support your instruction.

\n

Of course, this customized offering for SpringBoard has been designed to empower you to make the best decisions for your classroom and your students. Knowledge of your students’ needs will assist you in making appropriate decisions.

\n
\n )\n },\n {\n question: 'Do I need to create an account on Quill.org?',\n answer: (\n
\n

It is recommended that you and your students create free accounts on Quill.org. Creating an account will give you access to the two skills surveys and recommended practice; creating an account also allows you to track your students’ progress and view data reports. You can create an account by visiting the Quill sign-up page.

\n

Please note that if you do not create an account, you will not be able to use the skills surveys, access the recommended skills practice, track student progress, or view data reports.

\n
\n )\n },\n {\n question: 'Is a writing skills survey different than a diagnostic?',\n answer:

Quill's writing skills surveys can be used in lieu of Quill's general diagnostics. For example, a 7th grade SpringBoard ELA teacher would likely assign the SpringBoard Writing Skills Survey in lieu of the Starter or Intermediate Diagnostic. Keep in mind, however, that teachers may want ELL students in Pre-AP, AP, or SpringBoard classes to begin with one of the ELL Diagnostics instead of a writing skills survey. This article explains the differences between Quill’s various diagnostics and surveys in more depth.

\n },\n {\n question: 'How many activities are in a skills survey recommended pack?',\n answer:

Most recommended packs contain between 4 and 7 activities, each of which are designed to take between 10 and 15 minutes.

\n },\n {\n question: 'How many recommended packs should I assign to my students and how long will it take them to complete a pack?',\n answer: (\n
\n

You can assign all the recommended packs in one click, or you can pick and choose, revisiting the recommendations report to assign more packs as needed.

\n

In general, we've found that students make progress when they are completing 2-4 activities on Quill per week. Since each recommended pack contains between 4 and 7 activities, teachers generally expect a recommended pack to be completed in 1-2 weeks. Of course, students may need more or less time depending on the amount of activities in the pack, their level of difficulty, and students' level of proficiency.

\n

This article explains how you can use deadlines to help students pace themselves.

\n
\n )\n },\n {\n question: \"Where can I track my students' completion of and performance on Quill activities?\",\n answer:

Quill has a variety of reports to help you track your students' performance and progress. In the Activity Summary report, you can quickly see which activities your students have completed, along with color-coded icons indicating proficiency. Quill has several other reports as well. This cheat sheet shows you which report to go to for particular information, and this video will walk you through 3 of Quill's student data reports.

\n },\n {\n question: 'What tools does Quill.org offer?',\n answer: (\n
\n

If you create a free account on Quill.org, you will be able to assign additional activities from any of Quill’s 5 tools:

\n
    \n
  • \n

    Quill Connect

    \n

    Students combine multiple ideas into a single sentence using the evidence-based strategy of sentence combining. Students receive instant feedback. *Note*: All activities recommended based on survey results are in Quill Connect.

    \n
  • \n
  • \n

    Quill Grammar

    \n

    Students practice basic grammar skills, from using correct capitalization to correcting commonly confused words.

    \n
  • \n
  • \n

    Quill Proofreader

    \n

    Students practice editing skills by correcting errors in passages. Students receive personalized follow-up activities based on their results.

    \n
  • \n
  • \n

    Quill Lessons

    \n

    Teachers lead whole-class writing instruction. Teachers control interactive slides that contain a mini-lesson and guided practice. Teachers can model writing strategies in real-time, present prompts to which students can respond, and then anonymously display student responses for discussion. Each Quill Lessons activity provides a lesson plan, writing prompts, discussion topics, and a follow-up independent practice activity. Teachers can also customize any lesson.

    \n
  • \n
  • \n

    Quill Diagnostic

    \n

    Students complete an activity designed to help teachers determine which skills students need to work on. After students complete a Quill Diagnostic activity, Quill recommends writing activities for students based on their results. Note: The writing skills surveys can be used in lieu of general Quill diagnostics.

    \n
  • \n
\n
\n )\n },\n {\n question: 'I see there are passage-aligned activities for SpringBoard ELA English I. Are there passage-aligned activities for other SpringBoard ELA courses?',\n answer:

Unfortunately, at this time, there are no sentence combining activities aligned to texts in SpringBoard ELA courses other than SpringBoard ELA Grade 9. If you would like to see activities like these for another course, please us know here!

\n },\n {\n question: 'What if I still have questions?',\n answer: (\n
\n

We are here for you! The following resources are available:

\n

Quill Instructional Coach: You can reach out to us atpd@quill.org. Be sure to mention the course(s) you teach.

\n

Teacher Center: The place to go for all things best practice and implementation!

\n

Support: Having a technical issue? Email support@quill.org or use the chat in the lower right corner of Quill to connect with a member of the Quill support team.

\n

AP® is a registered trademark of the College Board.

\n
\n )\n },\n]\n\nexport default springboard\n","import React from 'react';\n\nexport default class QuestionAndAnswer extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n expanded: false\n }\n }\n\n answer() {\n const { expanded } = this.state;\n const { qa } = this.props;\n const { answer } = qa;\n if (expanded) {\n return
{answer}
\n }\n }\n\n expandOrCollapseButton() {\n const { questionsAndAnswersFile } = this.props\n const { expanded } = this.state\n const files = ['premium', 'preap', 'ap', 'springboard', 'socialStudies'];\n const buttonClass = questionsAndAnswersFile === 'lessons' ? 'focus-on-dark' : 'focus-on-light';\n let innerElement;\n\n if (files.includes(questionsAndAnswersFile)) {\n const imageLink = expanded ? 'collapse.svg' : 'expand.svg'\n innerElement = \"expand-and-collapse\"\n } else {\n innerElement = expanded ?

Collapse

:

Expand

\n }\n return \n }\n\n handleKeyPress = (e) => {\n e.preventDefault();\n const { key } = e;\n if(key === 'Enter') {\n this.handleToggleExpansion();\n }\n }\n\n handleToggleExpansion = () => {\n this.setState(prevState => ({ expanded: !prevState.expanded }));\n };\n\n render() {\n const { qa } = this.props;\n const { question } = qa;\n return (\n
\n
\n \n {this.answer()}\n
\n
\n {this.expandOrCollapseButton()}\n
\n
\n )\n }\n}\n","import React from 'react'\n\nexport default class ScrollToTop extends React.Component {\n constructor() {\n super()\n window.scrollTo(0, 0)\n }\n\n render() {\n return null\n }\n}\n","import React from 'react';\n\nimport { ButtonLoadingSpinner, } from '../../../../Shared/index';\nimport AssignmentFlowNavigation from '../assignment_flow_navigation';\nimport CustomActivityPack from './custom_activity_pack/index';\n\nexport default class SelectActivitiesContainer extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n prematureContinueAttempted: false,\n loading: false,\n }\n }\n\n clickContinue = () => {\n if (this.props.determineIfInputProvidedAndValid()) {\n this.props.clickContinue();\n } else {\n this.setState({ prematureContinueAttempted: true, });\n }\n }\n\n ctaButton = () => {\n if (this.props.editing) {\n const clickHandler = this.state.loading ? null : this.handleClick;\n const color = this.state.loading ? 'lightgray' : 'quillgreen';\n const text = this.state.loading ? Saving : 'Update Activities';\n return ;\n }\n }\n\n determineErrorMessageClass = () => {\n if (this.state.prematureContinueAttempted) {\n return 'error-message visible-error-message';\n }\n return 'error-message hidden-error-message';\n }\n\n handleClick = () => {\n this.props.updateActivities();\n this.setState({ loading: true, });\n }\n\n render() {\n const { editing, errorMessage, clickContinue, activities, selectedActivities, setSelectedActivities, toggleActivitySelection, unitName, showLessonsBanner, showEvidenceBanner, flagset, } = this.props\n const error = errorMessage ? {errorMessage} : '';\n const navigation = editing ? null : \n\n const clickFunction = editing ? this.handleClick : clickContinue\n\n return (\n
\n {navigation}\n \n
\n );\n }\n}\n","\nmodule.exports = function () {\n var selection = document.getSelection();\n if (!selection.rangeCount) {\n return function () {};\n }\n var active = document.activeElement;\n\n var ranges = [];\n for (var i = 0; i < selection.rangeCount; i++) {\n ranges.push(selection.getRangeAt(i));\n }\n\n switch (active.tagName.toUpperCase()) { // .toUpperCase handles XHTML\n case 'INPUT':\n case 'TEXTAREA':\n active.blur();\n break;\n\n default:\n active = null;\n break;\n }\n\n selection.removeAllRanges();\n return function () {\n selection.type === 'Caret' &&\n selection.removeAllRanges();\n\n if (!selection.rangeCount) {\n ranges.forEach(function(range) {\n selection.addRange(range);\n });\n }\n\n active &&\n active.focus();\n };\n};\n","\"use strict\";\n\nvar deselectCurrent = require(\"toggle-selection\");\n\nvar clipboardToIE11Formatting = {\n \"text/plain\": \"Text\",\n \"text/html\": \"Url\",\n \"default\": \"Text\"\n}\n\nvar defaultMessage = \"Copy to clipboard: #{key}, Enter\";\n\nfunction format(message) {\n var copyKey = (/mac os x/i.test(navigator.userAgent) ? \"⌘\" : \"Ctrl\") + \"+C\";\n return message.replace(/#{\\s*key\\s*}/g, copyKey);\n}\n\nfunction copy(text, options) {\n var debug,\n message,\n reselectPrevious,\n range,\n selection,\n mark,\n success = false;\n if (!options) {\n options = {};\n }\n debug = options.debug || false;\n try {\n reselectPrevious = deselectCurrent();\n\n range = document.createRange();\n selection = document.getSelection();\n\n mark = document.createElement(\"span\");\n mark.textContent = text;\n // avoid screen readers from reading out loud the text\n mark.ariaHidden = \"true\"\n // reset user styles for span element\n mark.style.all = \"unset\";\n // prevents scrolling to the end of the page\n mark.style.position = \"fixed\";\n mark.style.top = 0;\n mark.style.clip = \"rect(0, 0, 0, 0)\";\n // used to preserve spaces and line breaks\n mark.style.whiteSpace = \"pre\";\n // do not inherit user-select (it may be `none`)\n mark.style.webkitUserSelect = \"text\";\n mark.style.MozUserSelect = \"text\";\n mark.style.msUserSelect = \"text\";\n mark.style.userSelect = \"text\";\n mark.addEventListener(\"copy\", function(e) {\n e.stopPropagation();\n if (options.format) {\n e.preventDefault();\n if (typeof e.clipboardData === \"undefined\") { // IE 11\n debug && console.warn(\"unable to use e.clipboardData\");\n debug && console.warn(\"trying IE specific stuff\");\n window.clipboardData.clearData();\n var format = clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting[\"default\"]\n window.clipboardData.setData(format, text);\n } else { // all other browsers\n e.clipboardData.clearData();\n e.clipboardData.setData(options.format, text);\n }\n }\n if (options.onCopy) {\n e.preventDefault();\n options.onCopy(e.clipboardData);\n }\n });\n\n document.body.appendChild(mark);\n\n range.selectNodeContents(mark);\n selection.addRange(range);\n\n var successful = document.execCommand(\"copy\");\n if (!successful) {\n throw new Error(\"copy command was unsuccessful\");\n }\n success = true;\n } catch (err) {\n debug && console.error(\"unable to copy using execCommand: \", err);\n debug && console.warn(\"trying IE specific stuff\");\n try {\n window.clipboardData.setData(options.format || \"text\", text);\n options.onCopy && options.onCopy(window.clipboardData);\n success = true;\n } catch (err) {\n debug && console.error(\"unable to copy using clipboardData: \", err);\n debug && console.error(\"falling back to prompt\");\n message = format(\"message\" in options ? options.message : defaultMessage);\n window.prompt(message, text);\n }\n } finally {\n if (selection) {\n if (typeof selection.removeRange == \"function\") {\n selection.removeRange(range);\n } else {\n selection.removeAllRanges();\n }\n }\n\n if (mark) {\n document.body.removeChild(mark);\n }\n reselectPrevious();\n }\n\n return success;\n}\n\nmodule.exports = copy;\n","\"use strict\";\n\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.CopyToClipboard = void 0;\n\nvar _react = _interopRequireDefault(require(\"react\"));\n\nvar _copyToClipboard = _interopRequireDefault(require(\"copy-to-clipboard\"));\n\nvar _excluded = [\"text\", \"onCopy\", \"options\", \"children\"];\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nvar CopyToClipboard = /*#__PURE__*/function (_React$PureComponent) {\n _inherits(CopyToClipboard, _React$PureComponent);\n\n var _super = _createSuper(CopyToClipboard);\n\n function CopyToClipboard() {\n var _this;\n\n _classCallCheck(this, CopyToClipboard);\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n _this = _super.call.apply(_super, [this].concat(args));\n\n _defineProperty(_assertThisInitialized(_this), \"onClick\", function (event) {\n var _this$props = _this.props,\n text = _this$props.text,\n onCopy = _this$props.onCopy,\n children = _this$props.children,\n options = _this$props.options;\n\n var elem = _react[\"default\"].Children.only(children);\n\n var result = (0, _copyToClipboard[\"default\"])(text, options);\n\n if (onCopy) {\n onCopy(text, result);\n } // Bypass onClick if it was present\n\n\n if (elem && elem.props && typeof elem.props.onClick === 'function') {\n elem.props.onClick(event);\n }\n });\n\n return _this;\n }\n\n _createClass(CopyToClipboard, [{\n key: \"render\",\n value: function render() {\n var _this$props2 = this.props,\n _text = _this$props2.text,\n _onCopy = _this$props2.onCopy,\n _options = _this$props2.options,\n children = _this$props2.children,\n props = _objectWithoutProperties(_this$props2, _excluded);\n\n var elem = _react[\"default\"].Children.only(children);\n\n return /*#__PURE__*/_react[\"default\"].cloneElement(elem, _objectSpread(_objectSpread({}, props), {}, {\n onClick: this.onClick\n }));\n }\n }]);\n\n return CopyToClipboard;\n}(_react[\"default\"].PureComponent);\n\nexports.CopyToClipboard = CopyToClipboard;\n\n_defineProperty(CopyToClipboard, \"defaultProps\", {\n onCopy: undefined,\n options: undefined\n});","\"use strict\";\n\nvar _require = require('./Component'),\n CopyToClipboard = _require.CopyToClipboard;\n\nCopyToClipboard.CopyToClipboard = CopyToClipboard;\nmodule.exports = CopyToClipboard;","import React from 'react';\nimport { Input, } from '../../../../../Shared/index';\n\nconst NameTheUnit = ({ nameError, unitName, updateUnitName, timesSubmitted, }) => {\n return (\n
\n
\n 1\n Name the assignment\n
\n
\n \n
\n
\n )\n}\n\nexport default NameTheUnit\n","import moment from 'moment';\nimport React from 'react';\n\nimport { requestGet } from '../../../../../../modules/request';\nimport {\n DataTable,\n Snackbar,\n Tooltip,\n defaultSnackbarTimeout,\n getIconForActivityClassification,\n} from '../../../../../Shared/index';\nimport {\n DUE_DATE_DEFAULT_TEXT,\n DatePickerContainer,\n INVALID_DATES_SNACKBAR_COPY,\n PUBLISH_DATE_DEFAULT_TEXT,\n formatDateTimeForDisplay,\n} from '../../../../helpers/unitActivityDates';\nimport PreviouslyAssignedTooltip from '../../previouslyAssignedTooltip';\n\nconst PUBLISH_DATE_ATTRIBUTE_KEY = 'publishDates'\nconst DUE_DATE_ATTRIBUTE_KEY = 'dueDates'\n\nconst activityColumnMaxWidth = '392px';\nconst rowSectionTooltipClassName = 'tooltip-section review-activities-data-table-section';\n\nconst tableHeaders = [\n {\n name: 'Tool',\n attribute: 'tool',\n width: '30px',\n rowSectionClassName: rowSectionTooltipClassName\n },\n {\n name: 'Activity',\n attribute: 'activity',\n rowSectionClassName: rowSectionTooltipClassName,\n width: activityColumnMaxWidth\n },\n {\n name: 'Concept',\n attribute: 'concept',\n width: '166px'\n },\n {\n name: (\n
}\n />\n ),\n attribute: 'publishDatePicker',\n width: '123px',\n headerClassName: 'publish-date-header-container',\n rowSectionClassName: 'datetime-picker'\n },\n {\n name: (\n Due date (optional)}\n />\n ),\n attribute: 'dueDatePicker',\n width: '123px',\n headerClassName: 'due-date-header-container',\n rowSectionClassName: 'datetime-picker'\n },\n {\n name: 'Previously assigned',\n attribute: 'previouslyAssigned',\n width: '60px',\n rowSectionClassName: `${rowSectionTooltipClassName} previously-assigned-section`,\n noTooltip: true\n },\n]\n\nexport default class ReviewActivities extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n snackbarVisible: false,\n erroredActivityIds: [],\n previouslyAssignedActivityData: null\n }\n }\n\n componentDidUpdate() {\n const { activities } = this.props\n const { previouslyAssignedActivityData } = this.state\n if(!previouslyAssignedActivityData && activities) {\n this.getPreviouslyAssignedActivityData()\n }\n }\n\n getPreviouslyAssignedActivityData = () => {\n const { activities } = this.props\n const activityIds = JSON.stringify(activities.map(activity => activity.id))\n requestGet(`${process.env.DEFAULT_URL}/teachers/unit_templates/previously_assigned_activities?activity_ids=${activityIds}`, (response) => {\n if(response.previously_assigned_activity_data && Object.keys(response.previously_assigned_activity_data).length) {\n const { previously_assigned_activity_data } = response\n this.setState({ previouslyAssignedActivityData: previously_assigned_activity_data })\n }\n })\n }\n\n handleDateChange = (date, id, dateAttributeKey) => {\n const { activities, assignActivityDate, } = this.props\n const dates = this.props[dateAttributeKey]\n const activity = activities.find(act => act.id === id)\n const formattedDate = date || null\n this.setState({ erroredActivityIds: [], })\n assignActivityDate(activity, formattedDate, dateAttributeKey);\n }\n\n triggerSnackbar() {\n this.setState({ snackbarVisible: true }, () => {\n setTimeout(() => this.setState({ snackbarVisible: false, }), defaultSnackbarTimeout)\n })\n }\n\n handleDueDateChange = (date, id) => {\n const { activities, publishDates, } = this.props\n const dueDateIsBeforePublishDate = date && publishDates[id] && date <= moment.utc(publishDates[id])\n if (dueDateIsBeforePublishDate) {\n this.setState({\n erroredActivityIds: [id]\n }, this.triggerSnackbar)\n } else {\n this.handleDateChange(date, id, DUE_DATE_ATTRIBUTE_KEY)\n }\n }\n\n handlePublishDateChange = (date, id) => {\n const { activities, dueDates, } = this.props\n const publishDateIsAfterDueDate = date && dueDates[id] && date > moment.utc(dueDates[id])\n if (publishDateIsAfterDueDate) {\n this.setState({\n erroredActivityIds: [id]\n }, this.triggerSnackbar)\n } else {\n this.handleDateChange(date, id, PUBLISH_DATE_ATTRIBUTE_KEY)\n }\n }\n\n copyPublishDateToAll = () => {\n const { publishDates, dueDates, activities, } = this.props\n const publishDate = publishDates[activities[0].id]\n const activitiesWithEarlierDueDates = activities.filter(act => dueDates[act.id] && (publishDate >= dueDates[act.id]))\n\n if (publishDate && activitiesWithEarlierDueDates.length) {\n this.setState({\n erroredActivityIds: activitiesWithEarlierDueDates.map(a => a.id)\n }, this.triggerSnackbar)\n } else {\n this.copyDateToAll(PUBLISH_DATE_ATTRIBUTE_KEY)\n }\n }\n\n copyDueDateToAll = () => {\n const { publishDates, dueDates, activities, } = this.props\n const dueDate = dueDates[activities[0].id]\n const activitiesWithEarlierDueDates = activities.filter(act => publishDates[act.id] && (dueDate < publishDates[act.id]))\n\n if (dueDate && activitiesWithEarlierDueDates.length) {\n this.setState({\n erroredActivityIds: activitiesWithEarlierDueDates.map(a => a.id)\n }, this.triggerSnackbar)\n } else {\n this.copyDateToAll(DUE_DATE_ATTRIBUTE_KEY)\n }\n }\n\n copyDateToAll = (dateAttributeKey) => {\n const { activities, assignActivityDate, } = this.props\n const dates = this.props[dateAttributeKey]\n const existingDate = dates[activities[0].id] ? moment.utc(dates[activities[0].id]) : null\n this.setState({ erroredActivityIds: [], })\n activities.forEach(a => assignActivityDate(a, existingDate, dateAttributeKey))\n }\n\n removeRow = id => {\n const { activities, toggleActivitySelection } = this.props\n const activity = activities.find(act => act.id === id)\n toggleActivitySelection(activity, false)\n };\n\n rows() {\n const { activities, dueDates, publishDates, } = this.props\n const { erroredActivityIds, previouslyAssignedActivityData } = this.state\n\n return activities.map((activity, i) => {\n const {\n name,\n activity_classification,\n standard_level,\n activity_category,\n description,\n id,\n readability_grade_level\n } = activity\n const dueDateInMoment = dueDates[id] ? moment.utc(dueDates[id]) : null\n const publishDateInMoment = publishDates[id] ? moment.utc(publishDates[id]) : null\n const showCopyToAll = i === 0 && activities.length > 1\n\n const dueDatePicker = (\n this.handleDueDateChange(date, id)}\n defaultText={DUE_DATE_DEFAULT_TEXT}\n handleClickCopyToAll={this.copyDueDateToAll}\n initialValue={dueDateInMoment}\n key={dueDateInMoment ? formatDateTimeForDisplay(dueDateInMoment) : id}\n showCopyToAll={showCopyToAll}\n />\n )\n\n const publishDatePicker = (\n this.handlePublishDateChange(date, id)}\n defaultText={PUBLISH_DATE_DEFAULT_TEXT}\n handleClickCopyToAll={this.copyPublishDateToAll}\n initialValue={publishDateInMoment}\n key={publishDateInMoment ? formatDateTimeForDisplay(publishDateInMoment) : id}\n showCopyToAll={showCopyToAll}\n />\n )\n\n const toolName = activity_classification.alias;\n const toolDescription = activity_classification.description;\n const readabilityScore = readability_grade_level ? `

Readability score: ${readability_grade_level}

` : '';\n const standardLevelName = standard_level.name ? `

${standard_level.name}

` : '';\n const toolIconTooltipText = `
${toolName}

${toolDescription}

`;\n const activityNameTooltipText = `
${name}

Tool: ${toolName}

${readabilityScore}${standardLevelName}

${description}

`;\n\n const toolIcon = (\n \n );\n const activityName = (\n \n );\n\n const className = erroredActivityIds.includes(activity.id) ? 'checked' : ''\n const data = previouslyAssignedActivityData && previouslyAssignedActivityData[id] ? previouslyAssignedActivityData[id] : null\n\n return {\n id,\n className,\n tool: toolIcon,\n activity: activityName,\n concept: activity_category.name,\n dueDatePicker,\n publishDatePicker,\n previouslyAssigned: ,\n removable: true\n }\n })\n }\n\n render() {\n const { snackbarVisible, } = this.state\n return (\n
\n \n
\n 2\n Review activities and pick due dates\n
\n
\n \n
\n
\n )\n }\n}\n","import * as React from 'react';\n\nimport AssignStudents from './assign_students';\nimport GradeLevelWarningModal from './gradeLevelWarningModal';\nimport NameTheUnit from './name_the_unit';\nimport OverrideWarningModal from './overrideWarningModal';\nimport ReviewActivities from './review_activities';\nimport SkipRecommendationsWarningModal from './skipRecommendationsWarningModal';\n\nimport { ButtonLoadingSpinner, } from '../../../../../Shared/index'\n;\nimport ScrollToTop from '../../../shared/scroll_to_top';\nimport { postTestClassAssignmentLockedMessages, } from '../../assignmentFlowConstants';\nimport AssignmentFlowNavigation from '../../assignment_flow_navigation';\n\nexport class Stage2 extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n prematureAssignAttempted: false,\n loading: false,\n timesSubmitted: 0\n }\n }\n\n assignButton() {\n const { loading, } = this.state\n return loading\n ? \n : ;\n }\n\n determineAssignButtonClass() {\n let buttonClass = 'quill-button-archived contained primary medium';\n if (!this.buttonEnabled()) {\n buttonClass += ' disabled';\n }\n return buttonClass;\n }\n\n buttonEnabled() {\n const { areAnyStudentsSelected, selectedActivities, errorMessage } = this.props\n return areAnyStudentsSelected && selectedActivities.length && !errorMessage\n }\n\n selectedClassrooms() {\n const { classrooms, } = this.props\n\n return classrooms.filter(c => c.students.find(s => s.isSelected) || c.classroom.emptyClassroomSelected)\n }\n\n handleClickAssign = () => {\n const { timesSubmitted, } = this.state\n const { errorMessage, finish, alreadyCompletedDiagnosticStudentNames, notYetCompletedPreTestStudentNames, showGradeLevelWarning, selectedActivities, } = this.props\n\n const selectedClassrooms = this.selectedClassrooms()\n const lowestSelectedClassroomGrade = Math.min(...selectedClassrooms.map(c => Number(c.classroom.grade) || 12))\n const aboveGradeLevelContentBeingAssigned = selectedActivities.find(a => {\n if (!a.minimum_grade_level) { return }\n\n return a.minimum_grade_level > lowestSelectedClassroomGrade\n })\n\n if (alreadyCompletedDiagnosticStudentNames.length) {\n this.setState({ showOverrideWarningModal: true })\n } else if (notYetCompletedPreTestStudentNames.length) {\n this.setState({ showSkipRecommendationsWarningModal: true, })\n } else if (showGradeLevelWarning && aboveGradeLevelContentBeingAssigned) {\n this.setState({ showGradeLevelWarningModal: true, })\n } else if (this.buttonEnabled() && !errorMessage) {\n this.setState({ loading: true, });\n finish();\n } else {\n this.setState({ prematureAssignAttempted: true, timesSubmitted: timesSubmitted + 1 });\n }\n };\n\n onAssignDespiteWarning = () => {\n const { finish, } = this.props\n this.setState({ loading: true, });\n finish();\n }\n\n closeSkipRecommendationsWarningModal = () => {\n this.setState({ showSkipRecommendationsWarningModal: false, })\n }\n\n closeOverrideWarningModal = () => {\n this.setState({ showOverrideWarningModal: false, })\n }\n\n closeGradeLevelWarningModal = () => {\n this.setState({ showGradeLevelWarningModal: false, })\n }\n\n renderOverrideWarningModal() {\n const { showOverrideWarningModal, } = this.state\n const { alreadyCompletedDiagnosticStudentNames, unitTemplateName, unitName } = this.props\n\n if (!showOverrideWarningModal) { return }\n\n return (\n \n )\n }\n\n renderSkipRecommendationsWarningModal() {\n const { showSkipRecommendationsWarningModal, } = this.state\n const { notYetCompletedPreTestStudentNames, restrictedActivity, } = this.props\n\n if (!showSkipRecommendationsWarningModal) { return }\n\n return (\n \n )\n }\n\n renderGradeLevelWarningModal() {\n const { showGradeLevelWarningModal, } = this.state\n const { selectedActivities, } = this.props\n\n if (!showGradeLevelWarningModal) { return }\n\n return (\n \n )\n }\n\n renderAssignStudentsSection() {\n const {\n toggleClassroomSelection,\n toggleStudentSelection,\n user,\n classrooms,\n fetchClassrooms,\n lockedClassroomIds,\n restrictedActivity,\n cleverLink,\n googleLink,\n } = this.props\n\n return (\n \n )\n }\n\n renderNameSection() {\n const { timesSubmitted, } = this.state\n const { errorMessage, unitName, updateUnitName, } = this.props\n return (\n \n )\n }\n\n renderReviewActivitiesSection() {\n const {\n selectedActivities,\n toggleActivitySelection,\n assignActivityDate,\n dueDates,\n publishDates,\n } = this.props\n return (\n \n )\n }\n\n render() {\n const { unitTemplateName, unitTemplateId, isFromDiagnosticPath, } = this.props\n return (\n
\n {this.renderGradeLevelWarningModal()}\n {this.renderOverrideWarningModal()}\n {this.renderSkipRecommendationsWarningModal()}\n \n \n
\n

Review and assign

\n {this.renderNameSection()}\n {this.renderReviewActivitiesSection()}\n {this.renderAssignStudentsSection()}\n
\n
\n );\n }\n}\n\nexport default Stage2\n","import React from 'react';\n\nimport _ from 'lodash';\nimport { requestGet, requestPost, } from '../../../../../modules/request';\nimport {\n ACTIVITY_IDS_ARRAY,\n ASSIGNED_CLASSROOMS,\n CLASSROOMS,\n UNIT_ID,\n UNIT_NAME,\n UNIT_TEMPLATE_ID,\n UNIT_TEMPLATE_NAME\n} from '../assignmentFlowConstants';\nimport parsedQueryParams from '../parsedQueryParams';\nimport Stage1 from './select_activities_container';\nimport ShareToStudents from './share_activity_pack/shareToStudents';\nimport Stage2 from './stage2/Stage2';\nimport UnitAssignmentFollowup from './unit_assignment_followup.tsx';\n\nexport default class CreateUnit extends React.Component {\n constructor(props) {\n super(props)\n\n let stage = 1\n let name = ''\n let assignSuccess = false\n let classrooms = []\n const pathArray = props.location.pathname.split('/')\n const path = pathArray[pathArray.length - 1]\n const previouslyStoredName = props.match.params.unitName || window.localStorage.getItem(UNIT_NAME) || window.localStorage.getItem(UNIT_TEMPLATE_NAME)\n const previouslyStoredClassrooms = window.localStorage.getItem(CLASSROOMS) ? JSON.parse(window.localStorage.getItem(CLASSROOMS)) : []\n if (parsedQueryParams().unit_template_id || parsedQueryParams().diagnostic_unit_template_id || path === 'select-classes') {\n stage = 2\n name = previouslyStoredName\n classrooms = previouslyStoredClassrooms\n } else if (['next', 'referral', 'add-students'].includes(path)) {\n stage = 3;\n name = previouslyStoredName\n assignSuccess = true\n classrooms = previouslyStoredClassrooms\n }\n\n this.state = {\n prohibitedUnitNames: [],\n newUnitId: null,\n stage,\n selectedActivities: [],\n name,\n classrooms,\n assignSuccess,\n model: {\n dueDates: {},\n publishDates: {}\n },\n }\n }\n\n componentDidMount = () => {\n const { classrooms, stage, } = this.state\n this.getProhibitedUnitNames();\n\n this.fetchClassrooms()\n\n if (stage === 1 && this.unitTemplateId()) {\n window.localStorage.removeItem(UNIT_TEMPLATE_ID)\n window.localStorage.removeItem(UNIT_TEMPLATE_NAME)\n window.localStorage.removeItem(UNIT_NAME)\n window.localStorage.removeItem(ACTIVITY_IDS_ARRAY)\n window.localStorage.removeItem(CLASSROOMS)\n window.localStorage.removeItem(ASSIGNED_CLASSROOMS)\n }\n\n if (stage === 2 || window.localStorage.getItem(ACTIVITY_IDS_ARRAY)) {\n this.getActivities()\n }\n }\n\n onCreateSuccess = (response) => {\n const { history, } = this.props\n const { classrooms, name, } = this.state\n const { id } = response;\n this.setState({ newUnitId: id, assignSuccess: true, }, () => {\n const assignedClassrooms = classrooms.filter(c => c.classroom.emptyClassroomSelected || c.students.find(s => s.isSelected))\n window.localStorage.setItem(UNIT_NAME, name)\n window.localStorage.setItem(UNIT_ID, id)\n window.localStorage.setItem(ASSIGNED_CLASSROOMS, JSON.stringify(assignedClassrooms))\n if (assignedClassrooms.every(c => c.classroom.emptyClassroomSelected)) {\n history.push('/assign/add-students')\n } else {\n history.push('/assign/referral')\n }\n this.setStage(3);\n });\n }\n\n getActivities = () => {\n const { match, } = this.props\n const { stage, } = this.state\n const privateFlag = [2, 3].includes(stage) ? \"?flagset=private\" : ''\n requestGet(`/activities/search${privateFlag}`, (body) => {\n const { activities, } = body\n const activityIdsArray = match.params.activityIdsArray || window.localStorage.getItem(ACTIVITY_IDS_ARRAY)\n const activityIdsArrayAsArray = activityIdsArray.split(',')\n const selectedActivities = activityIdsArrayAsArray.map(id => activities.find(act => String(act.id) === id)).filter(Boolean)\n this.setState({ activities: activities, selectedActivities: selectedActivities, })\n })\n }\n\n getClassrooms = () => {\n const { classrooms, } = this.state\n return classrooms\n }\n\n getId = () => {\n const { model, } = this.state\n return model.id;\n }\n\n getProhibitedUnitNames = () => {\n requestGet('/teachers/prohibited_unit_names', (data) => {\n this.setState({ prohibitedUnitNames: data.prohibitedUnitNames, });\n });\n }\n\n getSelectedActivities = () => {\n const { selectedActivities, } = this.state\n return selectedActivities\n }\n\n getStage = () => {\n const { stage, } = this.state\n return stage\n }\n\n getUnitName = () => {\n const { name, } = this.state\n return name\n }\n\n setStage = (stage) => {\n this.setState({ stage, });\n }\n\n areAnyStudentsSelected = () => {\n const classroomsWithSelectedStudents = this.getClassrooms().filter(c => {\n let includeClassroom;\n if (this.emptyClassroomSelected(c)) {\n includeClassroom = true;\n } else {\n const selectedStudents = c.students.filter(s => s.isSelected)\n includeClassroom = selectedStudents.length > 0;\n }\n return includeClassroom;\n })\n\n return (classroomsWithSelectedStudents.length > 0);\n }\n\n assignActivityDate = (activity, date, dateKey) => {\n const { model, } = this.state\n model[dateKey][activity.id] = date;\n this.setState({ model, });\n }\n\n clickContinue = () => {\n const { history, } = this.props\n history.push('/assign/select-classes')\n this.setStage(2);\n this.resetWindowPosition();\n }\n\n determineIfInputProvidedAndValid = () => {\n return (this.getSelectedActivities().length > 0);\n }\n\n determineStage1ErrorMessage = () => {\n if (!this.getSelectedActivities().length > 0) {\n return 'Please select activities';\n }\n }\n\n determineStage2ErrorMessage = () => {\n if (!this.areAnyStudentsSelected()) {\n return { students: 'Please select students', }\n } else if (!this.isUnitNameValid()) {\n return { name: 'Please provide a name for your activity pack.', }\n } else if (!this.isUnitNameUnique()) {\n return { name: \"Each activity pack needs a unique name. You're already using that name for another activity pack. Please choose a different name.\", }\n }\n }\n\n dueDate = (id) => {\n const { model, } = this.state\n if (model.dueDates && model.dueDates[id]) {\n return model.dueDates[id];\n }\n }\n\n publishDate = (id) => {\n const { model, } = this.state\n if (model.publishDates && model.publishDates[id]) {\n return model.publishDates[id];\n }\n }\n\n emptyClassroomSelected = (c) => {\n return c.classroom.emptyClassroomSelected === true\n }\n\n fetchClassrooms = () => {\n requestGet('/teachers/classrooms/retrieve_classrooms_i_teach_for_custom_assigning_activities', (body) => {\n window.localStorage.setItem(CLASSROOMS, JSON.stringify(body.classrooms_and_their_students))\n this.setState({ classrooms: body.classrooms_and_their_students })\n })\n }\n\n finish = () => {\n const data = this.formatCreateRequestData()\n requestPost('/teachers/units', data, (body) => {\n this.onCreateSuccess(body)\n })\n }\n\n formatCreateRequestData = () => {\n let classroomPostData = this.getClassrooms().filter((c) => {\n let includeClassroom\n let selectedStudents;\n if (this.emptyClassroomSelected(c)) {\n includeClassroom = true;\n } else {\n selectedStudents = c.students.filter(s => s.isSelected)\n includeClassroom = selectedStudents.length > 0;\n }\n return includeClassroom;\n });\n\n classroomPostData = classroomPostData.map((c) => {\n let selectedStudentIds\n let assignOnJoin\n const selectedStudents = c.students.filter(s => s.isSelected)\n if (selectedStudents.length === c.students.length) {\n selectedStudentIds = [];\n assignOnJoin = true;\n } else {\n selectedStudentIds = selectedStudents.map(s => s.id)\n }\n return { id: c.classroom.id, student_ids: selectedStudentIds, assign_on_join: assignOnJoin, };\n })\n\n const selectedActivities = this.getSelectedActivities();\n\n const activityPostData = selectedActivities.map((sa) => {\n return {\n id: sa.id,\n due_date: this.dueDate(sa.id),\n publish_date: this.publishDate(sa.id)\n }\n })\n\n const unitObject = {\n unit: {\n id: this.getId(),\n name: this.getUnitName(),\n classrooms: classroomPostData,\n activities: activityPostData,\n unit_template_id: this.unitTemplateId()\n }\n };\n return unitObject;\n }\n\n isUnitNameUnique = () => {\n const { prohibitedUnitNames, } = this.state\n const unit = this.getUnitName();\n return !prohibitedUnitNames.includes(unit.toLowerCase());\n }\n\n isUnitNameValid = () => this.getUnitName() && this.getUnitName().length\n\n resetWindowPosition = () => {\n window.scrollTo(500, 0);\n }\n\n stage1SpecificComponents = () => {\n const { activities, } = this.state\n const { showLessonsBanner, showEvidenceBanner, flagset, } = this.props\n return (\n \n );\n }\n\n restrictedActivityBeingAssigned = () => {\n const { assignedPreTests, } = this.props\n const { selectedActivities, } = this.state\n\n const restrictedActivityIds = assignedPreTests.map(pretest => pretest.post_test_id)\n return selectedActivities && selectedActivities.find(act => restrictedActivityIds.includes(act.id))\n }\n\n lockedClassroomIds = () => {\n const { assignedPreTests, } = this.props\n const { classrooms, } = this.state\n let lockedClassroomIds = []\n\n const restrictedActivity = this.restrictedActivityBeingAssigned()\n\n if (restrictedActivity) {\n const relevantPretest = assignedPreTests.find(pretest => pretest.post_test_id === restrictedActivity.id)\n lockedClassroomIds = classrooms.filter(c => !relevantPretest.assigned_classroom_ids.includes(c.classroom.id)).map(c => c.classroom.id)\n }\n\n return lockedClassroomIds\n }\n\n notYetCompletedPreTestStudentNames = () => {\n const { assignedPreTests, } = this.props\n const { classrooms, } = this.state\n\n const restrictedActivity = this.restrictedActivityBeingAssigned()\n if (!restrictedActivity) { return [] }\n\n const relevantPretest = assignedPreTests.find(pretest => pretest.post_test_id === restrictedActivity.id)\n const studentsBeingAssignedWhoDidNotCompletePreTest = []\n classrooms.forEach(c => {\n const studentsBeingAssigned = c.students.filter(s => s.isSelected)\n const relevantPreTestClassroom = relevantPretest.all_classrooms.find(ac => ac.id === c.classroom.id)\n studentsBeingAssigned.forEach(s => {\n if (!relevantPreTestClassroom.completed_pre_test_student_ids.includes(s.id)) {\n studentsBeingAssignedWhoDidNotCompletePreTest.push(s.name)\n }\n })\n })\n return studentsBeingAssignedWhoDidNotCompletePreTest\n }\n\n alreadyCompletedDiagnosticStudentNames = () => {\n const { assignedPreTests, } = this.props\n const { selectedActivities, } = this.state\n\n const preTestActivityIds = assignedPreTests.map(pretest => pretest.id)\n const postTestActivityIds = assignedPreTests.map(pretest => pretest.post_test_id)\n\n const preTestBeingAssigned = selectedActivities && selectedActivities.find(act => preTestActivityIds.includes(act.id))\n const postTestBeingAssigned = selectedActivities && selectedActivities.find(act => postTestActivityIds.includes(act.id))\n let students = []\n\n if (preTestBeingAssigned) {\n const relevantPretest = assignedPreTests.find(pretest => pretest.id === preTestBeingAssigned.id)\n students = this.potentiallyOverwrittenStudentNames(relevantPretest, 'completed_pre_test_student_ids')\n } else if (postTestBeingAssigned) {\n const relevantPretest = assignedPreTests.find(pretest => pretest.post_test_id === postTestBeingAssigned.id)\n students = this.potentiallyOverwrittenStudentNames(relevantPretest, 'completed_post_test_student_ids')\n }\n return [... new Set(students.flat())]\n }\n\n potentiallyOverwrittenStudentNames = (relevantPretest, relevantStudentIdKey) => {\n const { classrooms, } = this.state\n return relevantPretest.all_classrooms.map(classroom => {\n const classroomFromState = classrooms.find(classroomFromState => classroomFromState.classroom.id === classroom.id)\n const studentNamesWhoCouldBeOverwritten = []\n classroom[relevantStudentIdKey].forEach(id => {\n const studentFromState = classroomFromState.students.find(student => student.id === id)\n const isOverwriteCandidate = studentFromState && studentFromState.isSelected // student is both still in classroom and selected to be assigned\n if (isOverwriteCandidate) {\n studentNamesWhoCouldBeOverwritten.push(studentFromState.name)\n }\n })\n return studentNamesWhoCouldBeOverwritten\n })\n }\n\n stage2SpecificComponents = () => {\n const { model, } = this.state\n const { cleverLink, googleLink, user, showGradeLevelWarning, } = this.props\n\n const restrictedActivity = this.restrictedActivityBeingAssigned()\n\n return (\n \n )\n }\n\n moveToStage4 = () => {\n this.setStage(4);\n }\n\n stage3specificComponents = () => {\n const { assignSuccess, name, selectedActivities } = this.state;\n if (assignSuccess) {\n const activityPackData = {\n name: name,\n activityCount: selectedActivities && selectedActivities.length,\n activities: selectedActivities\n }\n return(\n \n );\n }\n }\n\n stage4specificComponents = () => {\n const { referralCode, location, history, } = this.props\n const { classrooms, selectedActivities, name, assignSuccess, newUnitId, } = this.state\n if (assignSuccess) {\n return (\n \n );\n }\n\n if (_.map(selectedActivities, activity => { return activity.activity_classification.id }).includes(6)) {\n // There is a lesson here, so we should send the teacher to the Lessons page.\n window.location.href = `/teachers/classrooms/activity_planner/lessons#${newUnitId}`;\n } else {\n window.location.href = `/teachers/classrooms/activity_planner#${newUnitId}`;\n }\n }\n\n toggleActivitySelection = (activity) => {\n const { selectedActivities, } = this.state\n activity.selected = !activity.selected\n const indexOfActivity = selectedActivities.findIndex(act => act.id === activity.id);\n const newActivityArray = selectedActivities.slice();\n if (indexOfActivity === -1) {\n newActivityArray.push(activity);\n } else {\n newActivityArray.splice(indexOfActivity, 1);\n }\n this.setSelectedActivities(newActivityArray)\n }\n\n setSelectedActivities = (newActivityArray) => {\n const newActivityArrayIds = newActivityArray.map(a => a.id).join(',')\n this.setState({ selectedActivities: newActivityArray, }, () => {\n window.localStorage.setItem(ACTIVITY_IDS_ARRAY, newActivityArrayIds)\n })\n }\n\n toggleClassroomSelection = (classroom = null, select = null) => {\n const classrooms = this.getClassrooms();\n const selectHasValue = select === true || select === false\n if (!classrooms) {\n return;\n }\n\n const lockedClassroomIds = this.lockedClassroomIds()\n const updated = classrooms.map((c) => {\n if (lockedClassroomIds.includes(c.classroom.id)) { return c }\n const classroomGettingUpdated = c\n if (!classroom || classroomGettingUpdated.classroom.id === classroom.id) {\n const { students, } = classroomGettingUpdated\n if (!students.length) {\n classroomGettingUpdated.classroom.emptyClassroomSelected = selectHasValue ? select : this.toggleEmptyClassroomSelected(c);\n } else {\n const selected = students.filter(s => s.isSelected)\n const updatedStudents = students.map((s) => {\n const student = s\n student.isSelected = selectHasValue ? select : !selected.length\n return student;\n })\n classroomGettingUpdated.students = updatedStudents;\n }\n }\n return c;\n })\n this.setState({ classrooms: updated, }, () => window.localStorage.setItem(CLASSROOMS, JSON.stringify(updated)));\n }\n\n toggleEmptyClassroomSelected = (c) => {\n return !(this.emptyClassroomSelected(c));\n }\n\n toggleStudentSelection = (studentIds, classroomId) => {\n const allClassrooms = this.getClassrooms()\n const updated = allClassrooms.map((c) => {\n const changedClassroom = c\n if (changedClassroom.classroom.id === classroomId) {\n const updateStudents = changedClassroom.students.map((s) => {\n const student = s\n student.isSelected = studentIds.includes(student.id)\n return student;\n });\n changedClassroom.students = updateStudents;\n }\n return changedClassroom;\n })\n this.setState({ classrooms: updated, }, () => window.localStorage.setItem(CLASSROOMS, JSON.stringify(updated)));\n }\n\n unitTemplateId = () => parsedQueryParams().unit_template_id || parsedQueryParams().diagnostic_unit_template_id || window.localStorage.getItem(UNIT_TEMPLATE_ID)\n\n unitTemplateName = () => {\n const { match, } = this.props\n match.params.unitName || window.localStorage.getItem(UNIT_TEMPLATE_NAME)\n }\n\n updateUnitName = (e) => {\n this.isUnitNameValid();\n this.setState({ name: e.target.value, });\n }\n\n render = () => {\n const { stage } = this.state;\n let stageSpecificComponents;\n\n if (stage === 1) {\n stageSpecificComponents = this.stage1SpecificComponents();\n } else if (stage === 2) {\n stageSpecificComponents = this.stage2SpecificComponents();\n } else if (stage === 3) {\n stageSpecificComponents = this.stage3specificComponents();\n } else if (stage === 4) {\n stageSpecificComponents = this.stage4specificComponents();\n }\n return (\n \n
\n {stageSpecificComponents}\n
\n
\n\n );\n }\n}\n","import React from 'react';\nimport _ from 'underscore';\n\nexport default class UnitTemplateProfileShareButtons extends React.Component {\n\n urlEncodedMessage() {\n const { text, } = this.props\n return encodeURI(text) ;\n }\n\n render() {\n const { url, text, } = this.props\n\n const stuff = [\n {\n icon: 'fa-twitter',\n className: 'btn-twitter',\n href: `http://x.com/home?status=${encodeURIComponent(text)}`,\n title: 'Share on Twitter',\n action: 'Tweet',\n },\n {\n icon: 'fa-facebook',\n className: 'btn-facebook',\n href: `https://www.facebook.com/share.php?u=${url}`,\n title: 'Share this Activity pack on Facebook',\n action: 'Post',\n },\n {\n icon: 'fa-google-plus',\n className: 'btn-google-plus',\n href: `https://plus.google.com/share?url=${url}`,\n title: 'Share with Google Plus',\n action: 'Post',\n },\n {\n icon: 'fa-pinterest',\n className: 'btn-linkedin',\n href: `https://pinterest.com/pin/create/button/?url=${url}&media=https%3A%2F%2Fassets.quill.org%2Fimages%2Fshare%2Fpinterest.png&description=${this.urlEncodedMessage()}`,\n title: 'Share on Pinterest',\n action: 'Pin',\n }\n ];\n\n const links = _.map(stuff, hash => (\n \n {hash.action}\n \n ));\n\n return (\n
\n Share this Activity Pack\n
\n {links}\n
\n
\n );\n }\n}\n","'use strict'\n\nimport React from 'react'\n\nimport { requestGet, } from '../../../../modules/request/index'\nimport LoadingIndicator from '../shared/loading_indicator'\nimport UnitTemplateProfileShareButtons from './unit_templates_manager/unit_template_profile/unit_template_profile_share_buttons'\n\nexport default class UnitTemplateAssigned extends React.Component {\n constructor(props) {\n super(props)\n\n this.state = {\n loading: true,\n data: null,\n lastUnitId: ''\n }\n }\n\n getDefaultProps() {\n // the only time we won't pass this is if they are assigning the diagnostic,\n // but actions shouldn't be undefined\n return {actions: {getInviteStudentsUrl(){'placeholder function'}}}\n }\n\n UNSAFE_componentWillMount() {\n requestGet(\n `${process.env.DEFAULT_URL}/teachers/classrooms_i_teach_with_students`,\n (body) => {\n const studentsPresent = this.anyClassroomsWithStudents(body.classrooms)\n this.setState({ studentsPresent, loading: false, })\n }\n )\n\n requestGet(\n `${process.env.DEFAULT_URL}/teachers/last_assigned_unit_id`,\n (body) => {\n this.setState({ lastUnitId: body.id, referralCode: body.referral_code, loading: false, })\n }\n )\n\n requestGet(\n `${process.env.DEFAULT_URL}/teachers/unit_templates/assigned_info?id=${this.props.match.params.activityPackId}`,\n (body) => {\n this.setState({ data: body })\n }\n )\n }\n\n getInviteStudentsUrl() {\n return ('/teachers/classrooms');\n }\n\n activityName() {\n return this.state.data ? this.state.data.name : '';\n }\n\n anyClassroomsWithStudents(classrooms) {\n return !!classrooms.find((e) => e.students.length > 0)\n }\n\n socialShareCopy() {\n return `I’m using the ${this.activityName()} Activity Pack from Quill.org to teach writing & grammar. ${this.socialShareUrl()}`;\n }\n\n socialShareUrl() {\n return `${window.location.origin}/activities/packs/${this.props.match.params.activityPackId}${this.state.referralCode ? '?referral_code=' + this.state.referralCode : ''}`;\n }\n\n teacherSpecificComponents() {\n let href;\n let text;\n\n if (this.props.type === 'diagnostic' || this.state.studentsPresent) {\n href = `/teachers/classrooms/activity_planner#${this.state.lastUnitId}`;\n text = 'View Assigned Activity Packs';\n } else {\n href = this.getInviteStudentsUrl();\n text = 'Add Students'\n }\n\n return (\n \n \n \n \n \n )\n }\n\n unitTemplatesAssignedActions() {\n return {studentsPresent: this.props.students, getInviteStudentsUrl: this.getInviteStudentsUrl};\n }\n\n renderSharingContainer() {\n return (\n
\n

\n Share Quill With Your Colleagues\n

\n

\n We’re a nonprofit providing free literacy activities. The more people
\n who use Quill, the more free activities we can create.\n

\n

\n {this.socialShareCopy()}\n

\n
\n \n
\n
\n )\n }\n\n render() {\n if (this.state.loading) {\n return();\n }\n\n $('html,body').scrollTop(0);\n return (\n
\n
\n
\n
\n
\n You’ve successfully assigned the {this.activityName()} Activity Pack!\n
\n
\n {this.teacherSpecificComponents()}\n
\n
\n
\n
\n {this.renderSharingContainer()}\n
\n );\n }\n}\n","import React from 'react';\nimport _ from 'underscore';\n\nconst UnitTemplateProfileStandards = ({ data, }) => {\n const standards = _.uniq(data.activities.map(act => act.standard && act.standard.name)).filter(Boolean)\n const concepts = _.uniq(data.activities.map(act => act.standard && act.standard.standard_category && act.standard.standard_category.name)).filter(Boolean)\n const productionActivitiesRecommendedBy = data.diagnostics_recommended_by.filter(act => act.flags.includes(\"production\") && act.name.length)\n\n if (!standards.length && !concepts.length && !data.readability && !data.grade_range && !productionActivitiesRecommendedBy.length) { return }\n\n const renderStandards = () => {\n if (!standards.length) { return }\n\n return (\n \n
Standards
\n {standards.map(s =>
{s}
)}\n
\n )\n };\n\n const renderConcepts = () => {\n if (!concepts.length) { return }\n\n return (\n \n
Concepts
\n {concepts.map(s =>
{s}
)}\n
\n )\n };\n\n const renderGradeRange = () => {\n if (!data.grade_level_range) { return }\n\n return (\n \n
Grade Level Range
\n
{data.grade_level_range}
\n
\n )\n };\n\n const renderReadability = () => {\n if (!data.readability) { return }\n\n return (\n \n
Readability
\n
{data.readability}
\n
\n )\n };\n\n const renderRecommendedBy = () => {\n if (productionActivitiesRecommendedBy.length === 0) { return }\n\n return (\n \n
Recommended by
\n {productionActivitiesRecommendedBy.map(s =>
{s.name}
)}\n
\n )\n };\n\n\n return (\n
\n
\n {renderStandards()}\n {renderConcepts()}\n {renderGradeRange()}\n {renderReadability()}\n {renderRecommendedBy()}\n
\n
\n );\n}\n\nexport default UnitTemplateProfileStandards\n","import React from 'react';\nimport { Link } from 'react-router-dom';\n\nexport default class CategoryLabel extends React.Component {\n generateClassName = () => {\n return `category-label img-rounded ${this.props.extraClassName}`\n };\n\n getLink = () => {\n return this.props.nonAuthenticated\n ? `/activities/packs?category=${this.props.data.name.toLowerCase()}`\n : `/teachers/classrooms/assign_activities/featured-activity-packs?category=${this.props.data.name.toLowerCase()}`\n };\n\n render() {\n if (this.props.data.name) {\n const label =
{this.props.data.name.toUpperCase()}
\n if (this.props.isLink) {\n return (\n {label}\n )\n } else {\n return label\n }\n } else {\n return null\n }\n }\n}\n","import * as _ from 'lodash'\nimport moment from 'moment'\nimport React from 'react'\n\nimport { hexToRGBA } from '../../../../Shared'\nimport { imageTagForClassification, READING_TEXTS } from '../assignmentFlowConstants'\nimport CategoryLabel from '../category_label'\n\nconst cutOffTimeForNew = moment().subtract(1, 'months').unix()\nconst DEFAULT_ACTIVITY_PACK_IMAGE_LINKS = {\n 'Default': 'https://s3.amazonaws.com/quill-image-uploads/uploads/files/Writing_1_2379.jpg',\n 'Diagnostic': 'https://s3.amazonaws.com/quill-image-uploads/uploads/files/Chart_2380.jpg',\n 'Whole Class Lessons': 'https://s3.amazonaws.com/quill-image-uploads/uploads/files/Class_2381.jpg'\n}\n\nexport class UnitTemplateFirstRow extends React.Component {\n\n renderFlag(renderEvidenceTag) {\n const { data, } = this.props\n if(renderEvidenceTag) {\n return

BETA

\n }\n if (cutOffTimeForNew < data.created_at) {\n return

NEW

\n }\n }\n\n renderToolNames() {\n const { data, } = this.props\n\n const toolClassifications = data.activities.map(act => act.classification)\n const toolRows = _.uniqWith(toolClassifications, _.isEqual).map(classification => {\n return (\n \n {imageTagForClassification(classification.key)}\n {classification.name}\n \n )\n });\n\n return (\n
\n Contains activities from\n

\n {toolRows}\n

\n
\n )\n }\n\n renderActivityPackImage(data) {\n if(!data) { return }\n\n const { image_link, type, unit_template_category } = data\n const { name } = unit_template_category\n const link = image_link || DEFAULT_ACTIVITY_PACK_IMAGE_LINKS[name] || DEFAULT_ACTIVITY_PACK_IMAGE_LINKS['Default']\n const color = unit_template_category.primary_color || type.primary_color\n const opaqueColor = hexToRGBA(color, 1)\n const translucentColor = hexToRGBA(color, 0.4)\n\n return(\n
\n
\n \"\"\n
\n )\n }\n\n render() {\n const { data, } = this.props\n const { unit_template_category, type, name } = data\n const renderEvidenceTag = unit_template_category.name === READING_TEXTS\n const color = unit_template_category.primary_color || type.primary_color\n\n return (\n
\n {this.renderActivityPackImage(data)}\n
\n
\n
\n \n {renderEvidenceTag && NEW}\n
\n
\n
\n
\n {name}\n
\n {this.renderFlag(renderEvidenceTag)}\n
\n
\n
\n {this.renderToolNames()}\n
\n
\n );\n }\n}\n\nexport default UnitTemplateFirstRow\n","import React from 'react';\n\nexport default class UnitTemplateSecondRow extends React.Component {\n authorName = () => {\n const { data, } = this.props\n let name;\n if (data.author) {\n name = data.author.name;\n } else {\n name = null;\n }\n return name;\n };\n\n numberOfActivities = () => {\n const { data, } = this.props\n return data.activities ? data.activities.length : 0;\n };\n\n sayActivitiesCount = () => {\n const { modules, } = this.props\n return modules.string.sayNumberOfThings(this.numberOfActivities(), 'Activity', 'Activities')\n };\n\n sayTime = () => {\n const { data, } = this.props\n return [data.time, 'mins'].join(' ');\n };\n\n renderGradeLevelRange = () => {\n const { data, } = this.props\n\n if (!data.grade_level_range) { return }\n\n return (\n
\n \n Grade Level Range: {data.grade_level_range}\n
\n )\n }\n\n render() {\n return (\n
\n
\n {this.renderGradeLevelRange()}\n
\n
\n \n {this.sayActivitiesCount()}\n
\n
\n \n
\n {this.sayTime()}\n
\n
\n
\n
\n
\n );\n }\n}\n","'use strict'\n\n\nexport default function () {\n\n this.sayNumberOfThings = function (number, singular, plural) {\n let value;\n if (number == 1) {\n value = singular;\n } else {\n value = plural;\n }\n return [number, value].join(' ');\n }\n}\n","import React from 'react'\n\nimport UnitTemplateFirstRow from './unit_template_first_row'\nimport UnitTemplateSecondRow from './unit_template_second_row'\n\nimport { Tooltip } from '../../../../Shared'\nimport { renderActivityPackTooltipElement } from '../../../helpers/unitTemplates'\nimport String from '../../modules/string.jsx'\nimport { CLICKED_ACTIVITY_PACK_ID, CREATE_YOUR_OWN_ID } from '../assignmentFlowConstants'\n\nexport class UnitTemplateMini extends React.Component {\n constructor(props) {\n super(props)\n\n this.modules = { string: new String() }\n this.miniRef = React.createRef()\n }\n\n componentDidMount() {\n const clickedActivityPackId = window.sessionStorage.getItem(CLICKED_ACTIVITY_PACK_ID);\n const miniRefId = this.miniRef.current ? this.miniRef.current.id : null;\n const isClickedMini = clickedActivityPackId && miniRefId && clickedActivityPackId === miniRefId;\n\n if(isClickedMini) {\n const element = document.getElementById(clickedActivityPackId)\n if (!element) { return }\n const yOffset = -80;\n const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;\n element.focus()\n window.scrollTo({top: y});\n }\n }\n\n isSignedIn() {\n const { signedInTeacher, non_authenticated, } = this.props\n return signedInTeacher || (non_authenticated === false)\n }\n\n getLink() {\n const { data, } = this.props\n let link\n if (data.id == 'createYourOwn') {\n if (this.isSignedIn()) {\n link = '/assign/activity-library'\n } else {\n link = '/account/new'\n }\n } else {\n if (this.isSignedIn()) {\n link = `/assign/featured-activity-packs/${data.id}`;\n } else {\n link = `/activities/packs/${data.id}`\n }\n }\n return link\n }\n\n miniSpecificComponents() {\n const { data, } = this.props\n const { id } = data;\n if (id === CREATE_YOUR_OWN_ID) {\n return (\n
\n
\n \"plus\n

Create your own activity pack

\n
Select from over 800 writing activities
\n
\n
\n );\n }\n return (\n
\n \n \n
\n )\n }\n\n handleClick = () => {\n const url = this.getLink()\n window.location.href = url\n }\n\n renderMiniContent = () => {\n return(\n \n )\n }\n\n render() {\n const { data } = this.props\n const { id } = data;\n if(id === CREATE_YOUR_OWN_ID) {\n return this.renderMiniContent()\n }\n return (\n \n );\n }\n}\n\nexport default UnitTemplateMini\n","import _ from 'lodash'\nimport React from 'react'\nimport { Link } from 'react-router-dom'\n\nimport UnitTemplateMini from './unit_template_mini'\nimport UnitTemplateMinisTable from './unitTemplateMinisTable'\n\nimport { DropdownInput } from '../../../../Shared/index'\nimport AssignmentFlowNavigation from '../assignment_flow_navigation'\nimport { ACTIVITY_PACK_TYPES, CREATE_YOUR_OWN_ID, DAILY_PROOFREADING, DIAGNOSTIC, LANGUAGE_SKILLS, READING_TEXTS, WHOLE_CLASS_LESSONS } from '../assignmentFlowConstants'\n\nconst ALL = 'All'\nconst GRADE_LEVEL_LABELS = ['4th-12th', '6th-12th', '8th-12th', '10th-12th']\nconst GRID_VIEW_OPTION = { label: \"Grid\", value: \"grid\"}\nconst LIST_VIEW_OPTION = { label: \"List\", value: \"list\"}\n\nexport default class UnitTemplateMinis extends React.Component {\n\n state = { onMobile: window.innerWidth < 770, currentView: GRID_VIEW_OPTION }\n\n componentDidMount() {\n window.addEventListener('resize', this.updateDimensions);\n }\n componentWillUnmount() {\n window.removeEventListener('resize', this.updateDimensions);\n }\n\n updateDimensions = () => {\n const { currentView, onMobile } = this.state\n if(window.innerWidth < 770 !== onMobile) {\n this.setState({ onMobile: window.innerWidth < 770 })\n }\n if(window.innerWidth < 970 && currentView === LIST_VIEW_OPTION) {\n this.setState({ currentView: GRID_VIEW_OPTION })\n }\n }\n\n getIndexLink() {\n const { signedInTeacher } = this.props;\n return signedInTeacher ? '/assign/featured-activity-packs' : '/activities/packs'\n }\n\n //adds a final model, which is simply flagged as a createYourOwn one via the key\n addCreateYourOwnModel(models) {\n const { data } = this.props;\n const { non_authenticated } = data;\n if (models && models.length) {\n models.push({id: 'createYourOwn', non_authenticated: non_authenticated, unit_template_category: null });\n }\n return _.uniqBy(models, 'id');\n }\n\n generateGradeLevelOptions(selectedTypeId) {\n return [ALL].concat(GRADE_LEVEL_LABELS).map((level) => {\n if (level === ALL) {\n return {\n label: level,\n value: null,\n link: `${this.getIndexLink()}${this.generateQueryString(null, selectedTypeId)}`\n }\n }\n\n return {\n label: level,\n value: level,\n link: `${this.getIndexLink()}${this.generateQueryString(level, selectedTypeId)}`\n }\n })\n }\n\n generateShowAllGradesView() {\n const { data, } = this.props\n if (data.grade) {\n return (\n Show All Activity Packs\n )\n }\n }\n\n generateUnitTemplateView = (model, index, type) => {\n const { actions, signedInTeacher, } = this.props\n return (\n
\n {type && index === 0 &&

{type}

}\n \n
\n )\n };\n\n getModelCardsByType(models, type) {\n const filteredModels = models.filter(model => {\n const { unit_template_category, id } = model\n if(id === CREATE_YOUR_OWN_ID && type === WHOLE_CLASS_LESSONS) {\n // we want to include the create your own pack card as the last card in the last section which is Whole Class Lessons\n return model\n }\n if(unit_template_category && type === LANGUAGE_SKILLS) {\n return ACTIVITY_PACK_TYPES.find(type => type.name === LANGUAGE_SKILLS).types.includes(unit_template_category.name)\n }\n if(!unit_template_category) { return }\n\n return unit_template_category.name === type\n })\n return filteredModels.map((model, index) => {\n return this.generateUnitTemplateView(model, index, type)\n });\n }\n\n generateUnitTemplateViews() {\n const { signedInTeacher, data, displayedModels, selectedTypeId } = this.props;\n const { grade, } = data;\n let models;\n if (grade) {\n models = _.filter(displayedModels, (m) => {\n return _.contains(m.grades, grade.toString());\n });\n } else {\n models = displayedModels;\n }\n models = _.sortBy(models, 'order_number');\n if (signedInTeacher) {\n models = this.addCreateYourOwnModel(models);\n }\n if(!selectedTypeId) {\n const readingTextModels = this.getModelCardsByType(models, READING_TEXTS)\n const diagnosticModels = this.getModelCardsByType(models, DIAGNOSTIC)\n const languageSkillsModels = this.getModelCardsByType(models, LANGUAGE_SKILLS)\n const dailyProofreadingModels = this.getModelCardsByType(models, DAILY_PROOFREADING)\n const wholeClassModels = this.getModelCardsByType(models, WHOLE_CLASS_LESSONS)\n return(\n \n {!!readingTextModels.length &&
\n
\n {readingTextModels}\n
\n
}\n {!!diagnosticModels.length &&
\n
\n {diagnosticModels}\n
\n
}\n {!!languageSkillsModels.length &&
\n
\n {languageSkillsModels}\n
\n
}\n {!!dailyProofreadingModels.length &&
\n
\n {dailyProofreadingModels}\n
\n
}\n {!!wholeClassModels.length &&
\n
\n {wholeClassModels}\n
\n
}\n
\n )\n }\n const modelCards = models.map((model, index) => this.generateUnitTemplateView(model, index));\n return modelCards;\n }\n\n userLoggedIn() {\n const { signedInTeacher, } = this.props\n return signedInTeacher\n }\n\n userNotLoggedIn() {\n return !this.userLoggedIn();\n }\n\n handleTypeDropdownChange(type) {\n const { value } = type;\n window.location.href = value;\n }\n\n getDropdownValue(typeOptionsForDropdown) {\n const { location } = window;\n const { href } = location;\n\n if(href.includes('diagnostic')) {\n return typeOptionsForDropdown[1];\n } else if(href.includes('whole-class')) {\n return typeOptionsForDropdown[3];\n } else if(href.includes('independent')) {\n return typeOptionsForDropdown[2];\n }\n return typeOptionsForDropdown[0];\n }\n\n getLabelName(name) {\n switch (name) {\n case 'Whole class lessons':\n return 'Whole class lessons';\n case 'Independent practice':\n return 'Independent'\n default:\n return name;\n }\n }\n\n generateQueryString(gradeLevel, typeId=null) {\n let qs = ''\n\n if (gradeLevel) {\n const gradeLevelQuery = `gradeLevel=${gradeLevel}`\n qs+= qs.length ? `&${gradeLevelQuery}` : `?${gradeLevelQuery}`\n }\n\n if (typeId) {\n const typeQuery = `type=${typeId}`\n qs+= qs.length ? `&${typeQuery}` : `?${typeQuery}`\n }\n\n return qs\n }\n\n selectView(option) {\n this.setState({ currentView: option })\n }\n\n renderFilterOptions() {\n const { onMobile, currentView } = this.state\n const { types, selectedTypeId, data, selectGradeLevel, } = this.props\n const gradeLevelOptions = this.generateGradeLevelOptions(selectedTypeId)\n const currentGradeLevel = gradeLevelOptions.find(cat => cat.value && cat.value === data.selectedGradeLevel)\n\n const viewOptions = [GRID_VIEW_OPTION, LIST_VIEW_OPTION]\n\n const baseLink = this.getIndexLink()\n\n const typeOptions = types.map(type => {\n const { id, name, } = type\n const qs = this.generateQueryString(data.selectedGradeLevel, id)\n return (\n {name}\n )\n })\n\n const typeOptionsForDropdown = types.map(type => {\n const { id, name } = type;\n const qs = this.generateQueryString(data.selectedGradeLevel, id)\n return {\n label: this.getLabelName(name),\n value: `${baseLink}${qs}`\n }\n });\n typeOptionsForDropdown.unshift({ label: 'All Packs', value: '/activities/packs' });\n\n const allPacksLink = (\n All Packs\n );\n\n const typeOptionsWidget = onMobile ? (\n \n ) : (\n
\n {allPacksLink}\n {typeOptions}\n
\n )\n\n return (\n
\n
\n \n this.selectView(option)}\n label=\"View\"\n options={viewOptions}\n value={currentView || viewOptions[0]}\n />\n
\n {typeOptionsWidget}\n
\n )\n }\n\n renderActivityPacks() {\n const { displayedModels } = this.props;\n const { currentView } = this.state;\n const { value } = currentView;\n if(value === GRID_VIEW_OPTION.value) {\n return(\n \n
\n {this.generateUnitTemplateViews()}\n
\n
\n {this.generateShowAllGradesView()}\n
\n
\n )\n }\n if(value === LIST_VIEW_OPTION.value) {\n return(\n \n \n
\n {this.generateShowAllGradesView()}\n
\n
\n )\n }\n }\n\n render() {\n return (\n
\n {this.userLoggedIn() ? : null}\n
\n
\n

Select an activity pack for your students.

\n
\n {this.renderFilterOptions()}\n {this.generateShowAllGradesView()}\n {this.renderActivityPacks()}\n
\n
\n
\n
\n )\n }\n}\n","export default function getParameterByName(name, url) {\n if (!url) url = window.location.href;\n name = name.replace(/[\\[\\]]/g, '\\\\$&');\n let regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`),\n results = regex.exec(url);\n if (!results) return null;\n if (!results[2]) return '';\n return decodeURIComponent(results[2].replace(/\\+/g, ' '));\n}\n","'use strict'\n// setter has drastically changed as per slack conversation between ryan and donald\n// this will affect anything that was set up to use setter before 6/16/2016\n\nimport _ from 'underscore';\n\n//http://stackoverflow.com/questions/14843815/recursive-deep-extend-assign-in-underscore-js\nlet _deepFunction = function(mergeArrays) {\n var f = function(a, b) {\n let result;\n if (_.isArray(a) && _.isArray(b)) {\n if (mergeArrays) {\n result = a.concat(b)\n } else {\n result = b\n }\n } else if (_.isObject(a) && _.isObject(b)) {\n result = _.extend(a, b, f)\n } else {\n result = b;\n }\n return result;\n };\n return f\n}\n\nexport default function (object, path, value, mergeArrays) {\n let pathArr, len, keysExceptLastKey, lastKey, _deep;\n _deep = _deepFunction(mergeArrays)\n\n if (!path) {\n object = _.extend({}, object, value, _deep);\n } else {\n pathArr = path.split('.');\n len = pathArr.length;\n keysExceptLastKey = _.take(pathArr, len -1);\n lastKey = pathArr[len - 1]\n\n let nestedItem = _.reduce(keysExceptLastKey, function (acc, ele) {\n if (! acc[ele]) acc[ele] = {}\n return acc[ele]\n }, object)\n\n if ((value instanceof Object) && (nestedItem[lastKey] instanceof Object)){\n nestedItem[lastKey] = _.extend({}, nestedItem[lastKey], value, _deep);\n } else {\n nestedItem[lastKey] = value;\n }\n }\n\n return object;\n}\n","'use strict'\n\nimport setter from './setter'\n\nexport default function (component) {\n this.updater = function (path) {\n return function (value) {\n let x = setter(component.state, path, value)\n component.setState(x)\n }\n }\n}\n","'use strict'\n\nexport default function () {\n\n this.reset = function () {\n window.scrollTo(500, 0);\n }\n}\n","import qs from 'qs'\nimport React from 'react'\nimport _ from 'underscore'\n\nimport UnitTemplateMinis from './unit_template_minis'\n\nimport { requestGet } from '../../../../../modules/request'\nimport fnl from '../../modules/fnl'\nimport getParameterByName from '../../modules/get_parameter_by_name'\nimport updaterGenerator from '../../modules/updater'\nimport WindowPosition from '../../modules/windowPosition'\nimport AnalyticsWrapper from '../../shared/analytics_wrapper'\nimport LoadingIndicator from '../../shared/loading_indicator'\nimport ScrollToTop from '../../shared/scroll_to_top'\nimport { ACTIVITY_PACK_TYPES } from '../assignmentFlowConstants'\n\nexport default class UnitTemplatesManager extends React.Component {\n constructor(props) {\n super(props)\n\n this.modules = {\n fnl: new fnl,\n updaterGenerator: new updaterGenerator(this),\n windowPosition: new WindowPosition()\n }\n\n this.state = {\n signedInTeacher: false,\n unitTemplatesManager: {\n firstAssignButtonClicked: false,\n assignSuccess: false,\n models: [],\n categories: [],\n stage: 'index', // index, profile,\n model: null,\n model_id: null,\n relatedModels: [],\n selectedGradeLevel: null,\n lastActivityAssigned: null,\n grade: getParameterByName('grade'),\n }\n }\n\n this.updateCreateUnit = this.modules.updaterGenerator.updater('createUnit');\n this.updateUnitTemplatesManager = this.modules.updaterGenerator.updater('unitTemplatesManager');\n }\n\n componentDidMount() {\n this.fetchUnitTemplateModels();\n this.fetchTeacher();\n }\n\n parsedQueryParams = () => {\n const { location, } = this.props\n return qs.parse(location.search.replace('?', ''))\n }\n\n setTeacher(data) {\n this.setState({\n signedInTeacher: !_.isEmpty(data)\n })\n }\n\n analytics() {\n return new AnalyticsWrapper();\n }\n\n fetchClassrooms() {\n requestGet('/teachers/classrooms/retrieve_classrooms_for_assigning_activities', (data) => {\n this.updateCreateUnit({\n options: {\n classrooms: data.classrooms_and_their_students\n }\n })\n })\n }\n\n fetchTeacher() {\n requestGet('/current_user_json', (data) => {\n this.setTeacher(data)\n })\n }\n\n fetchUnitTemplateModels() {\n requestGet('/teachers/unit_templates', (data) => {\n this.updateUnitTemplateModels(data.unit_templates)\n })\n }\n\n filterModels = (grade, typeId, gradeLevelRange) => {\n const { unitTemplatesManager, } = this.state\n let displayedModels = unitTemplatesManager.models\n\n if (grade) {\n displayedModels = this.modelsInGrade(grade)\n }\n if (typeId) {\n const selectedType = ACTIVITY_PACK_TYPES.find(t => t.id === typeId)\n const { name, types, } = selectedType\n displayedModels = displayedModels.filter(ut => {\n const { type, unit_template_category } = ut\n if(['proofreading', 'independent-practice'].includes(typeId)) {\n return selectedType.types.includes(unit_template_category.name)\n } else if(unit_template_category) {\n return unit_template_category.name === name\n } else if(type) {\n return type.name === name\n }\n })\n }\n if (gradeLevelRange) {\n displayedModels = displayedModels.filter(ut => ut.grade_level_range === gradeLevelRange)\n }\n return displayedModels\n };\n\n modelsInGrade(grade) {\n const { unitTemplatesManager, } = this.state\n return _.reject(unitTemplatesManager.models, (m) => {\n return _.indexOf(m.grades, grade)\n });\n }\n\n returnToIndex() {\n this.updateUnitTemplatesManager({ stage: 'index' })\n window.scrollTo(0, 0);\n }\n\n selectGradeLevel = gradeLevel => {\n const { history, } = this.props\n const { unitTemplatesManager, } = this.state\n const newUnitTemplatesManager = unitTemplatesManager\n newUnitTemplatesManager.selectedGradeLevel = gradeLevel.value\n this.setState({ unitTemplatesManager: newUnitTemplatesManager })\n\n history.push(gradeLevel.link)\n };\n\n showAllGrades() {\n this.updateUnitTemplatesManager({grade: null});\n window.scrollTo(0, 0);\n }\n\n showUnitTemplates() {\n const { unitTemplatesManager, signedInTeacher, } = this.state\n if (unitTemplatesManager.models.length < 1) {\n return \n }\n\n const { grade, type, gradeLevel, } = this.parsedQueryParams()\n const displayedModels = this.filterModels(grade, type, gradeLevel)\n return (\n \n )\n }\n\n toggleTab(tab) {\n if (tab === 'createUnit') {\n this.analytics().track('click Create Unit', {});\n this.updateCreateUnit({\n stage: 1,\n model: {\n name: null,\n selectedActivities: []\n }\n });\n\n this.setState({tab: tab});\n } else {\n this.setState({tab: tab});\n }\n }\n\n unitTemplatesManagerActions() {\n return {\n toggleTab: this.toggleTab,\n clickAssignButton: this.clickAssignButton,\n returnToIndex: this.returnToIndex,\n selectModel: this.selectModel,\n showAllGrades: this.showAllGrades\n };\n }\n\n updateUnitTemplateModels = models => {\n const { unitTemplatesManager, } = this.state\n const categories = _.chain(models).pluck('unit_template_category').uniq(_.property('id')).value();\n const newHash = {\n models,\n displayedModels: models,\n categories\n }\n const modelId = unitTemplatesManager.model_id // would be set if we arrived here from a deep link\n if (modelId) {\n newHash.model = _.findWhere(models, {id: model_id});\n newHash.stage = 'profile'\n }\n this.updateUnitTemplatesManager(newHash)\n\n const { grade, type, gradeLevel, } = this.parsedQueryParams()\n\n if (grade || type || gradeLevel) {\n this.filterModels(grade, type, gradeLevel)\n }\n };\n\n render() {\n return (\n \n \n
\n {this.showUnitTemplates()}\n
\n
\n );\n }\n}\n","import React from 'react'\n\nconst AssignActivitiesContainer = (props) =>
{props.children}
\n\nexport default AssignActivitiesContainer\n","import React from 'react';\nimport { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';\nimport { CompatRouter } from \"react-router-dom-v5-compat\";\n\nimport ActivityType from '../components/assignment_flow/create_unit/activity_type.tsx';\nimport AssignADiagnostic from '../components/assignment_flow/create_unit/assign_a_diagnostic.tsx';\nimport AssignANewActivity from '../components/assignment_flow/create_unit/assign_a_new_activity';\nimport AssignAp from '../components/assignment_flow/create_unit/assign_ap.tsx';\nimport AssignPreAp from '../components/assignment_flow/create_unit/assign_pre_ap.tsx';\nimport AssignSpringBoard from '../components/assignment_flow/create_unit/assign_springboard.tsx';\nimport CollegeBoard from '../components/assignment_flow/create_unit/college_board.tsx';\nimport CreateUnit from '../components/assignment_flow/create_unit/create_unit';\nimport UnitTemplateAssigned from '../components/assignment_flow/unit_template_assigned';\nimport UnitTemplateProfile from '../components/assignment_flow/unit_templates_manager/unit_template_profile/unit_template_profile.tsx';\nimport UnitTemplatesManager from '../components/assignment_flow/unit_templates_manager/unit_templates_manager';\nimport AssignActivitiesContainer from './AssignActivitiesContainer.jsx';\nimport AssignWorldHistory1200ToPresent from '../components/assignment_flow/create_unit/assign_world_history_1200_to_present.tsx';\nimport AssignSocialStudiesSubjectPage from '../components/assignment_flow/create_unit/assign_social_studies_subject_page.tsx';\nimport AssignBuildingAIKnowledge from '../components/assignment_flow/create_unit/assign_building_ai_knowledge.tsx';\nimport AssignInterdisciplinaryScienceSubjectPage from '../components/assignment_flow/create_unit/assign_interdisciplinary_science_subject_page.tsx';\n\nconst AssignActivitiesRouter = props => (\n \n \n \n \n } path=\"/assign/interdisciplinary-science/building-ai-knowledge\" />\n } path=\"/assign/interdisciplinary-science\" />\n } path=\"/assign/social-studies/world-history-1200-to-present\" />\n } path=\"/assign/social-studies\" />\n } path=\"/assign/activity-type\" />\n } path=\"/assign/pre-ap\" />\n } path=\"/assign/ap\" />\n } path=\"/assign/springboard\" />\n } path=\"/assign/college-board\" />\n } path=\"/assign/diagnostic\" />\n } path=\"/assign/activity-library\" />\n } path=\"/assign/select-classes\" />\n } path=\"/assign/referral\" />\n } path=\"/assign/add-students\" />\n } path=\"/assign/next\" />\n \n \n \n \n \n } path=\"/assign/new_unit/students/edit/name/:unitName/activity_ids/:activityIdsArray\" />\n } path=\"/assign\" />\n \n \n \n);\n\nexport default AssignActivitiesRouter\n","import React from 'react';\nimport AssignActivitiesRouter from '../containers/AssignActivitiesRouter';\n\nexport default (props) => (\n \n);\n","import moment from 'moment';\nimport * as React from 'react';\nimport ReactMarkdown from 'react-markdown';\n\nexport default class BlogPostContent extends React.Component {\n renderBodyOrPaywall() {\n const { body, displayPaywall, } = this.props\n if(displayPaywall) {\n return (\n
\n

This article is only for Premium users.

\n

Quill Premium users have access to a slew of awesome features, including premium reports, priority support, and enhanced professional development opportunities.

\n Try Quill Premium \n
\n );\n } else {\n return ;\n return ').replace(/>/g, '>\\n').replace(/;\n }\n }\n\n renderName = () => {\n const { author, } = this.props\n return author ?

By {author.name}

: null\n };\n\n render() {\n const { centerImages, title, updatedAt, } = this.props\n const className = centerImages ? 'center-images' : ''\n return(\n
\n
\n

{title}

\n

{moment(updatedAt).format('MMMM Do, YYYY')}

\n {this.renderName()}\n
\n
\n {this.renderBodyOrPaywall()}\n
\n
\n )\n }\n}\n","import * as React from 'react';\n\nimport {\n BLOG_POST_TO_COLOR,\n TEACHER_CENTER_SLUG,\n} from './blog_post_constants';\nimport BlogPostContent from './blog_post_content';\n\nimport { requestPost, } from '../../../../modules/request/index';\nimport PreviewCard from '../shared/preview_card.jsx';\n\nconst RATING_MESSAGES = {\n instructions: 'Was this article helpful?',\n success: 'Thanks for rating!',\n sign_up: 'Please sign up to rate.'\n}\n\nexport default class BlogPost extends React.Component {\n constructor(props) {\n super(props);\n\n const { blogPost, displayPaywall, } = props\n\n this.state = {\n backLink: blogPost.topic.toLowerCase().replace(/\\s/g, '_'),\n ratingMessage: displayPaywall ? '' : RATING_MESSAGES['instructions']\n }\n }\n\n selectRatingEmoji(rating) {\n const { blogPost, } = this.props\n\n requestPost(\n `${process.env.DEFAULT_URL}/rate_blog_post`,\n {\n rating: rating,\n blog_post_id: blogPost.id\n },\n (body) => {\n this.setState({ ratingMessage: RATING_MESSAGES['success'] })\n },\n (body) => {\n this.setState({ ratingMessage: RATING_MESSAGES['sign_up'] })\n }\n )\n }\n\n renderRelatedPosts() {\n const { relatedPosts, } = this.props\n\n return relatedPosts.map(post =>\n ()\n )\n }\n\n renderRatingEmoji() {\n const { ratingMessage, } = this.state\n\n if(ratingMessage === RATING_MESSAGES['instructions']) {\n return (\n
    \n
  • \n
  • \n
  • \n
\n )\n }\n }\n\n render() {\n const { ratingMessage, } = this.state\n const { author, blogPost, displayPaywall, } = this.props\n\n return (\n
\n
\n \n
\n

{ratingMessage}

\n {this.renderRatingEmoji()}\n
\n
\n
\n
\n

\n Teacher Center Articles\n Show more\n

\n
\n {this.renderRelatedPosts()}\n
\n
\n
\n
\n )\n }\n}\n","/* global define */\n\n(function (root, pluralize) {\n /* istanbul ignore else */\n if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {\n // Node.\n module.exports = pluralize();\n } else if (typeof define === 'function' && define.amd) {\n // AMD, registers as an anonymous module.\n define(function () {\n return pluralize();\n });\n } else {\n // Browser global.\n root.pluralize = pluralize();\n }\n})(this, function () {\n // Rule storage - pluralize and singularize need to be run sequentially,\n // while other rules can be optimized using an object for instant lookups.\n var pluralRules = [];\n var singularRules = [];\n var uncountables = {};\n var irregularPlurals = {};\n var irregularSingles = {};\n\n /**\n * Title case a string.\n *\n * @param {string} str\n * @return {string}\n */\n function toTitleCase (str) {\n return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();\n }\n\n /**\n * Sanitize a pluralization rule to a usable regular expression.\n *\n * @param {(RegExp|string)} rule\n * @return {RegExp}\n */\n function sanitizeRule (rule) {\n if (typeof rule === 'string') {\n return new RegExp('^' + rule + '$', 'i');\n }\n\n return rule;\n }\n\n /**\n * Pass in a word token to produce a function that can replicate the case on\n * another word.\n *\n * @param {string} word\n * @param {string} token\n * @return {Function}\n */\n function restoreCase (word, token) {\n // Tokens are an exact match.\n if (word === token) {\n return token;\n }\n\n // Upper cased words. E.g. \"HELLO\".\n if (word === word.toUpperCase()) {\n return token.toUpperCase();\n }\n\n // Title cased words. E.g. \"Title\".\n if (word[0] === word[0].toUpperCase()) {\n return toTitleCase(token);\n }\n\n // Lower cased words. E.g. \"test\".\n return token.toLowerCase();\n }\n\n /**\n * Interpolate a regexp string.\n *\n * @param {string} str\n * @param {Array} args\n * @return {string}\n */\n function interpolate (str, args) {\n return str.replace(/\\$(\\d{1,2})/g, function (match, index) {\n return args[index] || '';\n });\n }\n\n /**\n * Sanitize a word by passing in the word and sanitization rules.\n *\n * @param {string} token\n * @param {string} word\n * @param {Array} collection\n * @return {string}\n */\n function sanitizeWord (token, word, collection) {\n // Empty string or doesn't need fixing.\n if (!token.length || uncountables.hasOwnProperty(token)) {\n return word;\n }\n\n var len = collection.length;\n\n // Iterate over the sanitization rules and use the first one to match.\n while (len--) {\n var rule = collection[len];\n\n // If the rule passes, return the replacement.\n if (rule[0].test(word)) {\n return word.replace(rule[0], function (match, index, word) {\n var result = interpolate(rule[1], arguments);\n\n if (match === '') {\n return restoreCase(word[index - 1], result);\n }\n\n return restoreCase(match, result);\n });\n }\n }\n\n return word;\n }\n\n /**\n * Replace a word with the updated word.\n *\n * @param {Object} replaceMap\n * @param {Object} keepMap\n * @param {Array} rules\n * @return {Function}\n */\n function replaceWord (replaceMap, keepMap, rules) {\n return function (word) {\n // Get the correct token and case restoration functions.\n var token = word.toLowerCase();\n\n // Check against the keep object map.\n if (keepMap.hasOwnProperty(token)) {\n return restoreCase(word, token);\n }\n\n // Check against the replacement map for a direct word replacement.\n if (replaceMap.hasOwnProperty(token)) {\n return restoreCase(word, replaceMap[token]);\n }\n\n // Run all the rules against the word.\n return sanitizeWord(token, word, rules);\n };\n }\n\n /**\n * Pluralize or singularize a word based on the passed in count.\n *\n * @param {string} word\n * @param {number} count\n * @param {boolean} inclusive\n * @return {string}\n */\n function pluralize (word, count, inclusive) {\n var pluralized = count === 1\n ? pluralize.singular(word) : pluralize.plural(word);\n\n return (inclusive ? count + ' ' : '') + pluralized;\n }\n\n /**\n * Pluralize a word.\n *\n * @type {Function}\n */\n pluralize.plural = replaceWord(\n irregularSingles, irregularPlurals, pluralRules\n );\n\n /**\n * Singularize a word.\n *\n * @type {Function}\n */\n pluralize.singular = replaceWord(\n irregularPlurals, irregularSingles, singularRules\n );\n\n /**\n * Add a pluralization rule to the collection.\n *\n * @param {(string|RegExp)} rule\n * @param {string} replacement\n */\n pluralize.addPluralRule = function (rule, replacement) {\n pluralRules.push([sanitizeRule(rule), replacement]);\n };\n\n /**\n * Add a singularization rule to the collection.\n *\n * @param {(string|RegExp)} rule\n * @param {string} replacement\n */\n pluralize.addSingularRule = function (rule, replacement) {\n singularRules.push([sanitizeRule(rule), replacement]);\n };\n\n /**\n * Add an uncountable word rule.\n *\n * @param {(string|RegExp)} word\n */\n pluralize.addUncountableRule = function (word) {\n if (typeof word === 'string') {\n uncountables[word.toLowerCase()] = true;\n return;\n }\n\n // Set singular and plural references for the word.\n pluralize.addPluralRule(word, '$0');\n pluralize.addSingularRule(word, '$0');\n };\n\n /**\n * Add an irregular word definition.\n *\n * @param {string} single\n * @param {string} plural\n */\n pluralize.addIrregularRule = function (single, plural) {\n plural = plural.toLowerCase();\n single = single.toLowerCase();\n\n irregularSingles[single] = plural;\n irregularPlurals[plural] = single;\n };\n\n /**\n * Irregular rules.\n */\n [\n // Pronouns.\n ['I', 'we'],\n ['me', 'us'],\n ['he', 'they'],\n ['she', 'they'],\n ['them', 'them'],\n ['myself', 'ourselves'],\n ['yourself', 'yourselves'],\n ['itself', 'themselves'],\n ['herself', 'themselves'],\n ['himself', 'themselves'],\n ['themself', 'themselves'],\n ['is', 'are'],\n ['was', 'were'],\n ['has', 'have'],\n ['this', 'these'],\n ['that', 'those'],\n // Words ending in with a consonant and `o`.\n ['echo', 'echoes'],\n ['dingo', 'dingoes'],\n ['volcano', 'volcanoes'],\n ['tornado', 'tornadoes'],\n ['torpedo', 'torpedoes'],\n // Ends with `us`.\n ['genus', 'genera'],\n ['viscus', 'viscera'],\n // Ends with `ma`.\n ['stigma', 'stigmata'],\n ['stoma', 'stomata'],\n ['dogma', 'dogmata'],\n ['lemma', 'lemmata'],\n ['schema', 'schemata'],\n ['anathema', 'anathemata'],\n // Other irregular rules.\n ['ox', 'oxen'],\n ['axe', 'axes'],\n ['die', 'dice'],\n ['yes', 'yeses'],\n ['foot', 'feet'],\n ['eave', 'eaves'],\n ['goose', 'geese'],\n ['tooth', 'teeth'],\n ['quiz', 'quizzes'],\n ['human', 'humans'],\n ['proof', 'proofs'],\n ['carve', 'carves'],\n ['valve', 'valves'],\n ['looey', 'looies'],\n ['thief', 'thieves'],\n ['groove', 'grooves'],\n ['pickaxe', 'pickaxes'],\n ['whiskey', 'whiskies']\n ].forEach(function (rule) {\n return pluralize.addIrregularRule(rule[0], rule[1]);\n });\n\n /**\n * Pluralization rules.\n */\n [\n [/s?$/i, 's'],\n [/([^aeiou]ese)$/i, '$1'],\n [/(ax|test)is$/i, '$1es'],\n [/(alias|[^aou]us|tlas|gas|ris)$/i, '$1es'],\n [/(e[mn]u)s?$/i, '$1s'],\n [/([^l]ias|[aeiou]las|[emjzr]as|[iu]am)$/i, '$1'],\n [/(alumn|syllab|octop|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, '$1i'],\n [/(alumn|alg|vertebr)(?:a|ae)$/i, '$1ae'],\n [/(seraph|cherub)(?:im)?$/i, '$1im'],\n [/(her|at|gr)o$/i, '$1oes'],\n [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i, '$1a'],\n [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, '$1a'],\n [/sis$/i, 'ses'],\n [/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i, '$1$2ves'],\n [/([^aeiouy]|qu)y$/i, '$1ies'],\n [/([^ch][ieo][ln])ey$/i, '$1ies'],\n [/(x|ch|ss|sh|zz)$/i, '$1es'],\n [/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, '$1ices'],\n [/(m|l)(?:ice|ouse)$/i, '$1ice'],\n [/(pe)(?:rson|ople)$/i, '$1ople'],\n [/(child)(?:ren)?$/i, '$1ren'],\n [/eaux$/i, '$0'],\n [/m[ae]n$/i, 'men'],\n ['thou', 'you']\n ].forEach(function (rule) {\n return pluralize.addPluralRule(rule[0], rule[1]);\n });\n\n /**\n * Singularization rules.\n */\n [\n [/s$/i, ''],\n [/(ss)$/i, '$1'],\n [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(?:sis|ses)$/i, '$1sis'],\n [/(^analy)(?:sis|ses)$/i, '$1sis'],\n [/(wi|kni|(?:after|half|high|low|mid|non|night|[^\\w]|^)li)ves$/i, '$1fe'],\n [/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, '$1f'],\n [/ies$/i, 'y'],\n [/\\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i, '$1ie'],\n [/\\b(mon|smil)ies$/i, '$1ey'],\n [/(m|l)ice$/i, '$1ouse'],\n [/(seraph|cherub)im$/i, '$1'],\n [/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|tlas|gas|(?:her|at|gr)o|ris)(?:es)?$/i, '$1'],\n [/(e[mn]u)s?$/i, '$1'],\n [/(movie|twelve)s$/i, '$1'],\n [/(cris|test|diagnos)(?:is|es)$/i, '$1is'],\n [/(alumn|syllab|octop|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, '$1us'],\n [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i, '$1um'],\n [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i, '$1on'],\n [/(alumn|alg|vertebr)ae$/i, '$1a'],\n [/(cod|mur|sil|vert|ind)ices$/i, '$1ex'],\n [/(matr|append)ices$/i, '$1ix'],\n [/(pe)(rson|ople)$/i, '$1rson'],\n [/(child)ren$/i, '$1'],\n [/(eau)x?$/i, '$1'],\n [/men$/i, 'man']\n ].forEach(function (rule) {\n return pluralize.addSingularRule(rule[0], rule[1]);\n });\n\n /**\n * Uncountable rules.\n */\n [\n // Singular words with no plurals.\n 'advice',\n 'adulthood',\n 'agenda',\n 'aid',\n 'alcohol',\n 'ammo',\n 'athletics',\n 'bison',\n 'blood',\n 'bream',\n 'buffalo',\n 'butter',\n 'carp',\n 'cash',\n 'chassis',\n 'chess',\n 'clothing',\n 'commerce',\n 'cod',\n 'cooperation',\n 'corps',\n 'digestion',\n 'debris',\n 'diabetes',\n 'energy',\n 'equipment',\n 'elk',\n 'excretion',\n 'expertise',\n 'flounder',\n 'fun',\n 'gallows',\n 'garbage',\n 'graffiti',\n 'headquarters',\n 'health',\n 'herpes',\n 'highjinks',\n 'homework',\n 'housework',\n 'information',\n 'jeans',\n 'justice',\n 'kudos',\n 'labour',\n 'literature',\n 'machinery',\n 'mackerel',\n 'mail',\n 'media',\n 'mews',\n 'moose',\n 'music',\n 'news',\n 'pike',\n 'plankton',\n 'pliers',\n 'pollution',\n 'premises',\n 'rain',\n 'research',\n 'rice',\n 'salmon',\n 'scissors',\n 'series',\n 'sewage',\n 'shambles',\n 'shrimp',\n 'species',\n 'staff',\n 'swine',\n 'trout',\n 'traffic',\n 'transporation',\n 'tuna',\n 'wealth',\n 'welfare',\n 'whiting',\n 'wildebeest',\n 'wildlife',\n 'you',\n // Regexes.\n /pox$/i, // \"chickpox\", \"smallpox\"\n /ois$/i,\n /deer$/i, // \"deer\", \"reindeer\"\n /fish$/i, // \"fish\", \"blowfish\", \"angelfish\"\n /sheep$/i,\n /measles$/i,\n /[^aeiou]ese$/i // \"chinese\", \"japanese\"\n ].forEach(pluralize.addUncountableRule);\n\n return pluralize;\n});\n","import pluralize from 'pluralize';\nimport * as React from 'react';\n\nimport {\n STUDENT,\n STUDENT_CENTER_SLUG,\n TEACHER_CENTER_SLUG\n} from './blog_post_constants';\n\nimport PreviewCard from '../shared/preview_card.jsx';\n\nexport default class TopicSection extends React.Component {\n displayTitle() {\n const { role, title, } = this.props\n if(role !== STUDENT) {\n return title\n }\n const titleWithoutWordStudent = title.replace('Student ', '')\n return titleWithoutWordStudent.charAt(0).toUpperCase() + titleWithoutWordStudent.slice(1)\n }\n\n sectionLink() {\n const { role, } = this.props\n return role === STUDENT ? STUDENT_CENTER_SLUG : TEACHER_CENTER_SLUG\n }\n\n renderArticleCards() {\n const { articles, color, onSearchPage, } = this.props\n const articlesForDisplay = onSearchPage ? articles : articles.slice(0, 3)\n return articlesForDisplay.map(article =>\n ()\n )\n }\n\n render() {\n const { color, articleCount, slug, onSearchPage, } = this.props\n return (\n
\n
\n

{this.displayTitle()}

\n
\n

{articleCount} {pluralize('article', articleCount)}

\n {!onSearchPage && Show all}\n
\n
\n
\n {this.renderArticleCards()}\n
\n
\n )\n }\n}\n","import pluralize from 'pluralize';\nimport * as React from 'react';\nimport _ from 'underscore';\n\nimport {\n ALL,\n BEST_PRACTICES,\n BLOG_POST_TO_COLOR,\n GETTING_STARTED,\n SEARCH,\n STUDENT,\n STUDENT_CENTER,\n STUDENT_CENTER_SLUG,\n SUPPORT,\n TEACHER_CENTER,\n TEACHER_CENTER_SLUG,\n TEACHER_MATERIALS,\n TEACHER_STORIES,\n TOPIC,\n WRITING_FOR_LEARNING,\n VIDEO_TUTORIALS,\n WEBINARS,\n WHATS_NEW,\n WRITING_INSTRUCTION_RESEARCH,\n} from './blog_post_constants';\nimport HeaderSection from './header_section';\nimport TopicSection from './topic_section.jsx';\n\nimport PreviewCard from '../shared/preview_card.jsx';\n\nexport default class BlogPostIndex extends React.Component {\n constructor(props) {\n super(props);\n\n const { blogPosts, } = props\n\n this.state = {\n articleFilter: window.location.pathname.includes(TOPIC) || props.query ? ALL : TOPIC,\n loading: true,\n blogPostsSortedByMostRead: [...blogPosts].sort((a, b) => (a.read_count < b.read_count) ? 1 : ((b.read_count < a.read_count) ? -1 : 0))\n };\n }\n\n filterArticlesBy(filter) {\n this.setState({ articleFilter: filter });\n }\n\n pageSubtitle() {\n const { role, } = this.props\n if (role === STUDENT) {\n return 'Everything you need to know about using Quill'\n }\n\n switch (this.pageTitle()) {\n case TEACHER_STORIES:\n return 'Read success stories about Quill in the classroom'\n case GETTING_STARTED:\n return 'Set up your classroom on Quill with guides, videos, and presentations'\n case WRITING_INSTRUCTION_RESEARCH:\n return \"Learn about the research behind Quill's methods and pedagogy\"\n case SUPPORT:\n return 'The most common questions teachers ask about Quill'\n case WEBINARS:\n return \"Watch Quill's recorded professional development sessions to learn Quill's implementation best practices\"\n case VIDEO_TUTORIALS:\n return \"View detailed walkthroughs of Quill tools, set-up, and features\"\n case BEST_PRACTICES:\n return \"Explore implementation ideas from Quill's instructional experts\"\n case WHATS_NEW:\n return 'Stay up to date on the latest Quill news'\n case TEACHER_MATERIALS:\n return 'Read and download useful materials to help navigate Quill, support students, and teach writing'\n case WRITING_FOR_LEARNING:\n return \"Learn about using Quill to simultaneously strengthen students' content knowledge and writing skills\"\n case TEACHER_CENTER:\n default:\n return \"Everything you need to know about Quill's pedagogy and use in the classroom\"\n }\n }\n\n pageTitle() {\n const { role, title, } = this.props\n if (window.location.pathname.includes(TOPIC)) {\n const topicTitle = title\n return role === STUDENT ? topicTitle.replace('Student ', '') : topicTitle\n } else if (role === STUDENT) {\n return STUDENT_CENTER\n } else {\n return TEACHER_CENTER\n }\n }\n\n currentPageIsSearchPage = () => window.location.pathname.includes(SEARCH);\n\n renderAnnouncement() {\n const { announcement, } = this.props\n\n if(announcement) {\n return (\n \n
\n

{announcement.text}

\n \n
\n )\n }\n }\n\n renderBasedOnArticleFilter() {\n const { articleFilter, } = this.state\n const { blogPosts,} = this.props\n\n let response;\n if (blogPosts.length === 0) {\n response =

No results found.

\n } else if (articleFilter === TOPIC || this.currentPageIsSearchPage()) {\n response = this.renderPreviewCardsByTopic();\n } else if (articleFilter === 'popularity') {\n response = (\n
\n {this.renderPreviewCardsByPopularity()}\n
\n )\n } else {\n response = (\n
\n {this.renderPreviewCards()}\n
\n )\n }\n return
{response}
\n }\n\n renderMostReadPost() {\n const { blogPostsSortedByMostRead, } = this.state\n const mostReadArticle = blogPostsSortedByMostRead[0];\n if (window.location.pathname.includes(SEARCH)) { return null; }\n const link = mostReadArticle.external_link ? mostReadArticle.external_link : `/teacher-center/${mostReadArticle.slug}`\n return (\n

\n {mostReadArticle.title}\n

\n )\n }\n\n renderNavAndSectionHeader() {\n const { blogPosts, } = this.props\n if (this.currentPageIsSearchPage()) {\n return (\n
\n
\n

Search results

\n

{blogPosts.length} {pluralize('article', blogPosts.length)}

\n
\n
\n )\n }\n\n return \n }\n\n renderPreviewCards() {\n const { role, blogPosts, } = this.props\n const sectionLink = role === STUDENT ? STUDENT_CENTER_SLUG : TEACHER_CENTER_SLUG\n return blogPosts.map(article =>\n ()\n )\n }\n\n renderPreviewCardsByPopularity() {\n const { blogPostsSortedByMostRead, } = this.state\n\n return blogPostsSortedByMostRead.map(article =>\n ()\n )\n }\n\n renderPreviewCardsByTopic() {\n const { blogPosts, role, topics } = this.props;\n let sections = [];\n const articlesByTopic = _.groupBy(blogPosts, TOPIC);\n topics.forEach(topic => {\n const articlesInThisTopic = articlesByTopic[topic.name];\n\n if (articlesInThisTopic) {\n sections.push( a.order_number - b.order_number)}\n color={BLOG_POST_TO_COLOR[topic.name]}\n key={topic.name}\n onSearchPage={this.currentPageIsSearchPage()}\n role={role}\n slug={topic.slug}\n title={topic.name}\n />\n );\n }\n })\n return sections;\n }\n\n render() {\n const { blogPosts, query, } = this.props\n if (blogPosts.length === 0 && !query) {\n return (\n
\n
\n Coming Soon!\n \"\"\n
\n
\n )\n } else {\n return (\n
\n \n {this.renderNavAndSectionHeader()}\n {this.renderAnnouncement()}\n {this.renderBasedOnArticleFilter()}\n
\n )};\n }\n}\n","import moment from 'moment';\nimport * as React from 'react';\nimport { SingleDatePicker } from 'react-dates';\nimport \"react-dates/initialize\";\nimport Dropzone from 'react-dropzone';\nimport Textarea from 'react-textarea-autosize';\n\nimport { requestPost, requestPut, } from '../../../../../modules/request/index';\nimport { smallWhiteCheckIcon } from '../../../../Shared/index';\nimport { BLOG_POST_TO_COLOR, } from '../../blog_posts/blog_post_constants';\nimport BlogPostContent from '../../blog_posts/blog_post_content';\nimport ItemDropdown from '../../general_components/dropdown_selectors/item_dropdown.jsx';\nimport getAuthToken from '../../modules/get_auth_token';\nimport PreviewCard from '../../shared/preview_card.jsx';\n\nconst defaultPreviewCardContent = `
\n

Party Parrot Parade

\n

There exist many excellent party parrots.

\n
\n`;\n\nexport const EDIT = 'edit'\nexport const NEW = 'new'\nconst STANDARD = 'Standard'\nconst CUSTOM_HTML = 'Custom HTML'\n\nexport default class CreateOrEditBlogPost extends React.Component {\n constructor(props) {\n super(props);\n\n const { postToEdit, action } = props\n const {\n id,\n title,\n subtitle,\n image_link,\n body,\n author_id,\n topic,\n draft,\n slug,\n preview_card_content,\n footer_content,\n premium,\n press_name,\n published_at,\n external_link,\n center_images\n } = postToEdit\n // set state to empty values or those of the postToEdit\n\n this.state = {\n previewCardHasAlreadyBeenManuallyEdited: action !== NEW,\n id,\n title,\n subtitle,\n imageLink: image_link,\n body,\n author_id,\n topic,\n draft,\n slug,\n preview_card_content,\n custom_preview_card_content: preview_card_content,\n preview_card_type: action === NEW ? STANDARD : CUSTOM_HTML,\n blogPostPreviewImage: 'http://placehold.it/300x135',\n blogPostPreviewTitle: title,\n blogPostPreviewDescription: 'Write your description here, but be careful not to make it too long!',\n videoLink: 'https://www.youtube.com/watch?v=oVXZTmi2ruI',\n videoDescription: \"I'll write it myself, and we'll do it live!\",\n tweetLink: 'https://x.com/EdSurge/status/956861254982873088',\n tweetImage: 'http://placehold.it/300x135/00998a/fff',\n tweetText: '\"Climbing up Ben Bloom’s learning hierarchy won’t be easy, but it is necessary if we want to build education technology capable of helping learners move beyond basic remembering and understanding.\"',\n tweetAuthor: 'EdSurge',\n premium,\n pressName: press_name,\n publishedAt: published_at,\n externalLink: external_link,\n centerImages: center_images,\n focused: false,\n footerContent: footer_content\n };\n }\n\n componentDidMount = () => {\n this.updatePreviewCardBasedOnType();\n }\n\n changeAuthor = (e) => {\n this.setState({author_id: e.id}, this.updatePreviewCardFromBlogPostPreview)\n }\n\n changePreviewCardType = (e) => {\n this.setState({ preview_card_type: e }, this.updatePreviewCardBasedOnType)\n }\n\n changeTopic = (e) => {\n this.setState({topic: e})\n }\n\n goToPreview = () => {\n const { studentTopics, } = this.props\n const { slug, externalLink, topic, } = this.state\n let url\n if (externalLink) {\n url = externalLink\n } else if (studentTopics.includes(topic)) {\n url = `/student-center/${slug}`\n } else {\n url = `/teacher-center/${slug}`\n }\n window.open(url, '_blank')\n }\n\n handleBlogPostPreviewDescriptionChange = (e) => {\n this.setState({\n blogPostPreviewDescription: e.target.value,\n previewCardHasAlreadyBeenManuallyEdited: true\n }, this.updatePreviewCardFromBlogPostPreview)\n }\n\n handleBlogPostPreviewImageChange = (e) => {\n this.setState({\n blogPostPreviewImage: e.target.value,\n previewCardHasAlreadyBeenManuallyEdited: true\n }, this.updatePreviewCardFromBlogPostPreview)\n }\n\n handleBlogPostPreviewTitleChange = (e) => {\n this.setState({\n blogPostPreviewTitle: e.target.value,\n previewCardHasAlreadyBeenManuallyEdited: true\n }, this.updatePreviewCardFromBlogPostPreview)\n }\n\n handleBodyChange = (e) => {\n this.setState({body: e.target.value})\n const container = document.getElementById('markdown-content');\n container.rows = 4;\n const rows = Math.ceil((container.scrollHeight - 64) / 20.3);\n container.rows = 2 + rows;\n }\n\n handleCenterImagesChange = () => {\n this.setState(prevState => ({centerImages: !prevState.centerImages}));\n }\n\n handleClickEdit = () => {\n this.setState({showArticlePreview: false})\n }\n\n handleClickPreview = () => {\n this.setState({showArticlePreview: true})\n }\n\n handleCustomPreviewChange = (e) => {\n this.setState({\n preview_card_content: e.target.value,\n custom_preview_card_content: e.target.value,\n previewCardHasAlreadyBeenManuallyEdited: true\n })\n const container = document.getElementById('preview-markdown-content');\n container.rows = 4;\n const rows = Math.ceil((container.scrollHeight - 64) / 20.3);\n container.rows = 2 + rows;\n }\n\n handleDrop = (acceptedFiles) => {\n acceptedFiles.forEach(file => {\n const data = new FormData()\n data.append('file', file)\n fetch(`${process.env.DEFAULT_URL}/cms/images`, {\n method: 'POST',\n mode: 'cors',\n credentials: 'include',\n headers: {\n 'X-CSRF-Token': getAuthToken()\n },\n body: data\n })\n .then(response => response.json()) // if the response is a JSON object\n .then(response => this.setState({uploadedMediaLink: response.url})); // Handle the success response object\n });\n }\n\n handleExternalLinkChange = (e) => {\n this.setState({externalLink: e.target.value})\n }\n\n handleFooterChange = (e) => {\n this.setState({ footerContent: e.target.value })\n }\n\n handleImageLinkChange = (e) => {\n const { value, } = e.target;\n const { previewCardHasAlreadyBeenManuallyEdited, } = this.state\n let state = { imageLink: value };\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n state['blogPostPreviewImage'] = targetValue;\n }\n this.setState(state, () => {\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n this.updatePreviewCardFromBlogPostPreview();\n }\n });\n }\n\n handleInsertBold = () => this.insertMarkdown('**', '**')\n\n handleInsertFileImage = () => this.insertMarkdown('![', '](http://cultofthepartyparrot.com/parrots/hd/parrot.gif)')\n\n handleInsertIFrame = () => this.insertMarkdown('')\n\n handleInsertH1 = () => this.insertMarkdown('# ')\n\n handleInsertH2 = () => this.insertMarkdown('## ')\n\n handleInsertH3 = () => this.insertMarkdown('### ')\n\n handleInsertItalic = () => this.insertMarkdown('*', '*')\n\n handleInsertLink = () => this.insertMarkdown('[', '](http://samepicofdavecoulier.tumblr.com)')\n\n handleInsertOrderedList = () => this.insertMarkdown('1. ')\n\n handleInsertPrimaryButton = () => this.insertMarkdown(\"\\n\", \"\\n\")\n\n handleInsertQuote = () => this.insertMarkdown('> ')\n\n handleInsertSecondaryButton = () => this.insertMarkdown(\"\\n\", \"\\n\")\n\n handleInsertUnorderedList = () => this.insertMarkdown('* ')\n\n handlePremiumChange = () => {\n this.setState(prevState => ({premium: !prevState.premium}));\n }\n\n handlePressNameChange = (e) => {\n this.setState({ pressName: e.target.value })\n }\n\n handlePreviewCardVideoDescriptionChange = (e) => {\n this.setState({videoDescription: e.target.value}, this.updatePreviewCardVideoContent)\n }\n\n handlePreviewCardVideoLinkChange = (e) => {\n this.setState({videoLink: e.target.value}, this.updatePreviewCardVideoContent)\n }\n\n handlePublishClick = (e) => this.handleSubmitClick(e, true)\n\n handlePublishedAtChange = (e) => {\n this.setState({ publishedAt: e}, this.updatePreviewCardBasedOnType)\n }\n\n handleSaveAndPreviewClick = (e) => {\n const { draft, } = this.state\n this.handleSubmitClick(e, !draft, false, this.goToPreview)\n }\n\n handleSaveDraftClick = (e) => { this.handleSubmitClick(e, false) }\n\n handleSubmitClick = (e, shouldPublish, unpublish = false, callback) => {\n const { action, postToEdit, } = this.props\n const {\n title,\n subtitle,\n imageLink,\n body,\n topic,\n author_id,\n preview_card_content,\n premium,\n publishedAt,\n externalLink,\n centerImages,\n pressName,\n footerContent\n } = this.state\n\n e.preventDefault()\n\n if (unpublish && window.prompt('To unpublish this post, please type UNPUBLISH.') !== 'UNPUBLISH') { return }\n let requestAction\n let url = `${process.env.DEFAULT_URL}/cms/blog_posts/`\n\n const blogPost = {\n blog_post: {\n title: title,\n subtitle: subtitle,\n image_link: imageLink,\n body: body,\n topic: topic,\n author_id: author_id,\n preview_card_content: preview_card_content,\n draft: !shouldPublish,\n premium: premium,\n published_at: publishedAt ? new Date(publishedAt) : null,\n external_link: externalLink,\n center_images: centerImages,\n press_name: pressName,\n footer_content: footerContent\n }\n }\n\n if (action === NEW && !unpublish) {\n requestPost(\n url,\n blogPost,\n (body) => {\n alert('Post added successfully!');\n window.location.href = (`/cms/blog_posts/${body.id}/edit`)\n callback ? callback() : null\n },\n (body) => {\n alert(\"😨 Rut roh. Something went wrong! (Don't worry, it's probably not your fault.)\");\n callback ? callback() : null\n }\n )\n } else {\n url += postToEdit.id\n requestPut(\n url,\n blogPost,\n (body) => {\n this.setState({draft: body.draft})\n alert('Update successful!');\n callback ? callback() : null\n },\n (body) => {\n alert(\"😨 Rut roh. Something went wrong! (Don't worry, it's probably not your fault.)\");\n callback ? callback() : null\n }\n )\n }\n }\n\n handleSubtitleChange = (e) => {\n const { value, } = e.target;\n const { previewCardHasAlreadyBeenManuallyEdited, } = this.state\n let state = {subtitle: value};\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n state['blogPostPreviewDescription'] = value;\n }\n this.setState(state, () => {\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n this.updatePreviewCardFromBlogPostPreview();\n }\n });\n }\n\n handleTitleChange = (e) => {\n const { value, } = e.target;\n const { previewCardHasAlreadyBeenManuallyEdited, } = this.state\n let state = { title: value };\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n state['blogPostPreviewTitle'] = value;\n }\n this.setState(state, () => {\n if(!previewCardHasAlreadyBeenManuallyEdited) {\n this.updatePreviewCardFromBlogPostPreview();\n }\n });\n }\n\n handleTweetAuthorChange = (e) => {\n this.setState({ tweetAuthor: e.target.value }, this.updatePreviewCardTweetContent)\n }\n\n handleTweetImageChange = (e) => {\n this.setState({ tweetImage: e.target.value }, this.updatePreviewCardTweetContent)\n }\n\n handleTweetLinkChange = (e) => {\n this.setState({ tweetLink: e.target.value }, this.updatePreviewCardTweetContent)\n }\n\n handleTweetTextChange = (e) => {\n this.setState({ tweetText: e.target.value }, this.updatePreviewCardTweetContent)\n }\n\n handleUnpublishClick = (e) => { this.handleSubmitClick(e, false, true) }\n\n insertMarkdown = (startChar, endChar = null) => {\n /*\n TODO:\n - Special behaviors:\n - startChars should automatically be placed at the front of the line\n - if multiple lines are highlighted, we should insert startChar at beginning of each line\n - Extract this and the buttons into a separate component\n */\n const { body, } = this.state\n const container = document.getElementById('markdown-content');\n let newValue = body;\n if (container.selectionStart || container.selectionStart === 0) {\n let startPos = container.selectionStart;\n let endPos = container.selectionEnd;\n newValue = container.value.substring(0, startPos);\n newValue += startChar;\n newValue += container.value.substring(startPos, endPos);\n newValue += endChar ? endChar : '';\n newValue += container.value.substring(endPos, container.value.length);\n container.focus();\n } else {\n newValue += startChar;\n }\n this.setState({ body: newValue });\n }\n\n updatePreviewCardBasedOnType = () => {\n const { preview_card_type, custom_preview_card_content, } = this.state\n switch (preview_card_type) {\n case STANDARD:\n this.updatePreviewCardFromBlogPostPreview()\n break;\n default:\n this.setState({ preview_card_content: custom_preview_card_content })\n }\n }\n\n updatePreviewCardFromBlogPostPreview = () => {\n const { authors, } = this.props\n const {\n publishedAt,\n externalLink,\n blogPostPreviewImage,\n blogPostPreviewTitle,\n blogPostPreviewDescription,\n author_id,\n } = this.state\n const author = authors.find(a => a.id == author_id)\n let footerContent, button\n if (author) {\n footerContent = `

by ${author.name}

`\n } else if (publishedAt) {\n footerContent = `

${this.formatDate(new Date(publishedAt))}

`\n } else {\n footerContent = ``\n }\n const previewCardContent = `\n
\n

${blogPostPreviewTitle}

\n

${blogPostPreviewDescription}

\n
\n `;\n this.setState({ preview_card_content: previewCardContent })\n }\n\n updatePreviewCardTweetContent = () => {\n const { authors, } = this.props\n const { publishedAt, tweetImage, tweetText, tweetAuthor, author_id, } = this.state\n const author = authors.find(a => a.id == author_id)\n let footerContent\n if (author) {\n footerContent = `

by ${author.name}

`\n } else if (publishedAt) {\n footerContent = `

${this.formatDate(new Date(publishedAt))}

`\n } else {\n footerContent = ``\n }\n const previewCardContent = `\n
\n

${tweetText}

\n

@${tweetAuthor}

\n
\n `;\n this.setState({ preview_card_content: previewCardContent, previewCardHasAlreadyBeenManuallyEdited: true })\n }\n\n updatePreviewCardVideoContent = () => {\n const { videoLink, author_id, publishedAt, videoDescription, } = this.state\n const { authors, } = this.props\n const matchedQueryParameter = videoLink.match(/\\?v=(.*)(\\&)/) || videoLink.match(/\\?v=(.*)$/)\n const embedUrl = `https://www.youtube-nocookie.com/embed/${matchedQueryParameter[1]}?rel=0&controls=0&showinfo=0&player=html5`\n const author = authors.find(a => a.id == author_id)\n let footerContent\n if (author) {\n footerContent = `

by ${author.name}

`\n } else if (publishedAt) {\n footerContent = `

${this.formatDate(new Date(publishedAt))}

`\n } else {\n footerContent = ``\n }\n const previewCardContent = `
\n \n
\n
\n

${videoDescription}

\n
\n `;\n this.setState({ preview_card_content: previewCardContent, previewCardHasAlreadyBeenManuallyEdited: true })\n }\n\n formatDate(date) {\n const options = { year: 'numeric', month: 'long', day: '2-digit' };\n const dateTimeFormat = new Intl.DateTimeFormat('en-US', options);\n return dateTimeFormat.format(date)\n }\n\n renderArticleMarkdownOrPreview = () => {\n const { publishedAt, showArticlePreview, body, centerImages, author_id, title, } = this.state\n const { postToEdit, authors, } = this.props\n let content, toolbarLeft, dateDisplayed\n if (publishedAt) {\n dateDisplayed = publishedAt\n } else if (postToEdit) {\n dateDisplayed = postToEdit.updated_at\n } else {\n dateDisplayed = new Date()\n }\n if (showArticlePreview) {\n toolbarLeft =
\n content = (
\n
\n a.id == author_id)}\n body={body}\n centerImages={centerImages}\n displayPaywall={false}\n title={title}\n updatedAt={dateDisplayed}\n />\n
\n
)\n } else {\n toolbarLeft = (
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
)\n content =