diff --git a/assets/images/images-v2/certificate-step-bg.jpg b/assets/images/images-v2/certificate-step-bg.jpg deleted file mode 100644 index d56f3393ae..0000000000 Binary files a/assets/images/images-v2/certificate-step-bg.jpg and /dev/null differ diff --git a/assets/images/images-v2/email-heading.svg b/assets/images/images-v2/email-heading.svg deleted file mode 100644 index 397b0f4425..0000000000 --- a/assets/images/images-v2/email-heading.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/assets/images/images-v2/email.png b/assets/images/images-v2/email.png deleted file mode 100644 index ce2ad2d0ad..0000000000 Binary files a/assets/images/images-v2/email.png and /dev/null differ diff --git a/assets/images/images-v2/signature-demo.svg b/assets/images/images-v2/signature-demo.svg deleted file mode 100644 index 0e99f2b387..0000000000 --- a/assets/images/images-v2/signature-demo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/instructor-layout/pp-cp.jpg b/assets/images/instructor-layout/pp-cp.jpg deleted file mode 100644 index 0ec3f908d7..0000000000 Binary files a/assets/images/instructor-layout/pp-cp.jpg and /dev/null differ diff --git a/assets/images/instructor-layout/pp-left-full.jpg b/assets/images/instructor-layout/pp-left-full.jpg deleted file mode 100644 index d1c9e2f06d..0000000000 Binary files a/assets/images/instructor-layout/pp-left-full.jpg and /dev/null differ diff --git a/assets/images/instructor-layout/pp-left-middle.jpg b/assets/images/instructor-layout/pp-left-middle.jpg deleted file mode 100644 index 18ee6d5eea..0000000000 Binary files a/assets/images/instructor-layout/pp-left-middle.jpg and /dev/null differ diff --git a/assets/images/instructor-layout/pp-top-full.jpg b/assets/images/instructor-layout/pp-top-full.jpg deleted file mode 100644 index 667ba240e3..0000000000 Binary files a/assets/images/instructor-layout/pp-top-full.jpg and /dev/null differ diff --git a/assets/images/instructor-layout/pp-top-left.jpg b/assets/images/instructor-layout/pp-top-left.jpg deleted file mode 100644 index 439d6e091e..0000000000 Binary files a/assets/images/instructor-layout/pp-top-left.jpg and /dev/null differ diff --git a/assets/images/public-profile/no-cp.jpg b/assets/images/public-profile/no-cp.jpg deleted file mode 100644 index db3ef851cc..0000000000 Binary files a/assets/images/public-profile/no-cp.jpg and /dev/null differ diff --git a/assets/images/public-profile/pp-circle.jpg b/assets/images/public-profile/pp-circle.jpg deleted file mode 100644 index ed129b75d2..0000000000 Binary files a/assets/images/public-profile/pp-circle.jpg and /dev/null differ diff --git a/assets/images/public-profile/pp-rectangle.jpg b/assets/images/public-profile/pp-rectangle.jpg deleted file mode 100644 index b5fe4153de..0000000000 Binary files a/assets/images/public-profile/pp-rectangle.jpg and /dev/null differ diff --git a/assets/images/whats-new.png b/assets/images/whats-new.png deleted file mode 100644 index bc865f4c99..0000000000 Binary files a/assets/images/whats-new.png and /dev/null differ diff --git a/assets/react/admin-dashboard/quiz-attempts.js b/assets/react/admin-dashboard/quiz-attempts.js index a1d28a0b47..a9b743e99e 100644 --- a/assets/react/admin-dashboard/quiz-attempts.js +++ b/assets/react/admin-dashboard/quiz-attempts.js @@ -17,10 +17,12 @@ document.addEventListener('DOMContentLoaded', async function() { const response = await post.json(); if (response.success && response.data) { const navItems = document.querySelectorAll('.tutor-nav-item .tutor-ml-4'); - let i = 0; - for (let [key, value] of Object.entries(response.data)) { - navItems[i].innerHTML = `(${value})`; - i++; + if (navItems.length) { + let i = 0; + for (let [key, value] of Object.entries(response.data)) { + navItems[i].innerHTML = `(${value})`; + i++; + } } } } diff --git a/assets/react/lib/tutor.js b/assets/react/lib/tutor.js index 91f8dfb079..88303c2fcb 100644 --- a/assets/react/lib/tutor.js +++ b/assets/react/lib/tutor.js @@ -342,8 +342,15 @@ jQuery(document).ready(function($) { beforeSend: function() { $that.find('button').attr('disabled', 'disabled').addClass('is-loading'); }, - success: function() { - tutor_toast(__('Success', 'tutor'), $that.data('toast_success_message'), 'success'); + success: function(response) { + if (response.success) { + tutor_toast(__('Success', 'tutor'), $that.data('toast_success_message'), 'success'); + } else { + tutor_toast(__('Error!', 'tutor'), response.data, 'error'); + } + }, + error: function(response) { + tutor_toast(__('Error!', 'tutor'), response.statusText, 'error'); }, complete: function() { $that.find('button').removeAttr('disabled').removeClass('is-loading'); diff --git a/assets/scss/front/_theme.scss b/assets/scss/front/_theme.scss index b00f975d30..70974f348f 100644 --- a/assets/scss/front/_theme.scss +++ b/assets/scss/front/_theme.scss @@ -7,6 +7,10 @@ body { box-sizing: border-box; } } + + .media-modal * { + box-sizing: content-box; + } } //common and reset css diff --git a/classes/Q_and_A.php b/classes/Q_and_A.php index 50ef94cab3..037ee41625 100644 --- a/classes/Q_and_A.php +++ b/classes/Q_and_A.php @@ -51,6 +51,26 @@ public function __construct() { add_action( 'wp_ajax_tutor_q_and_a_load_more', __CLASS__ . '::load_more' ); } + /** + * Check user has access to QnA. + * + * @since 2.6.1 + * + * @param int $user_id user id. + * @param int $course_id course id. + * + * @return boolean + */ + public static function has_qna_access( $user_id, $course_id ) { + $is_public_course = Course_List::is_public( $course_id ); + + $has_access = $is_public_course + || User::is_admin() + || tutor_utils()->is_instructor_of_this_course( $user_id, $course_id ) + || tutor_utils()->is_enrolled( $course_id ); + return $has_access; + } + /** * Undocumented function * @@ -60,8 +80,17 @@ public function __construct() { */ public function tutor_qna_create_update() { tutor_utils()->checking_nonce(); + + $user_id = get_current_user_id(); + $course_id = Input::post( 'course_id', 0, Input::TYPE_INT ); + + if ( ! $this->has_qna_access( $user_id, $course_id ) ) { + wp_send_json_error( array( 'message' => tutor_utils()->error_message() ) ); + } + global $wpdb; - $qna_text = Input::post( 'answer', '', Input::TYPE_KSES_POST ); + $qna_text = Input::post( 'answer', '', tutor()->has_pro ? Input::TYPE_KSES_POST : Input::TYPE_TEXTAREA ); + if ( ! $qna_text ) { // Content validation. wp_send_json_error( array( 'message' => __( 'Empty Content Not Allowed!', 'tutor' ) ) ); @@ -73,9 +102,8 @@ public function tutor_qna_create_update() { $context = Input::post( 'context' ); // Prepare user info. - $user_id = get_current_user_id(); - $user = get_userdata( $user_id ); - $date = gmdate( 'Y-m-d H:i:s', tutor_time() ); + $user = get_userdata( $user_id ); + $date = gmdate( 'Y-m-d H:i:s', tutor_time() ); // Insert data prepare. $data = apply_filters( diff --git a/classes/Quiz.php b/classes/Quiz.php index fc5a35d1a3..b7711f8927 100644 --- a/classes/Quiz.php +++ b/classes/Quiz.php @@ -195,11 +195,11 @@ public static function quiz_question_layouts() { */ public static function quiz_question_orders() { $orders = array( - 'rand' => __( 'Random', 'tutor' ), - 'sorting' => __( 'Sorting', 'tutor' ), - 'asc' => __( 'Ascending', 'tutor' ), - 'desc' => __( 'Descending', 'tutor' ), - ); + 'rand' => __( 'Random', 'tutor' ), + 'sorting' => __( 'Sorting', 'tutor' ), + 'asc' => __( 'Ascending', 'tutor' ), + 'desc' => __( 'Descending', 'tutor' ), + ); return apply_filters( 'tutor_quiz_layouts', $orders ); } @@ -317,8 +317,6 @@ public function start_the_quiz() { die( 'Please sign in to do this operation' ); } - global $wpdb; - $user_id = get_current_user_id(); $user = get_userdata( $user_id ); @@ -326,7 +324,27 @@ public function start_the_quiz() { $quiz = get_post( $quiz_id ); $course = CourseModel::get_course_by_quiz( $quiz_id ); - if ( empty( $course->ID ) ) { + + self::quiz_attempt( $course->ID, $quiz_id, $user_id ); + wp_safe_redirect( get_permalink( $quiz_id ) ); + die(); + } + + /** + * Manage quiz attempt + * + * @since 2.6.1 + * + * @param integer $course_id course id. + * @param integer $quiz_id quiz id. + * @param integer $user_id user id. + * + * @return int inserted id|0 + */ + public static function quiz_attempt( int $course_id, int $quiz_id, int $user_id, $attempt_status = 'attempt_started' ) { + global $wpdb; + + if ( ! $course_id ) { die( 'There is something went wrong with course, please check if quiz attached with a course' ); } @@ -366,13 +384,13 @@ public function start_the_quiz() { $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds; $attempt_data = array( - 'course_id' => $course->ID, + 'course_id' => $course_id, 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'total_questions' => $max_question_allowed, 'total_answered_questions' => 0, 'attempt_info' => maybe_serialize( $tutor_quiz_option ), - 'attempt_status' => 'attempt_started', + 'attempt_status' => $attempt_status, 'attempt_ip' => tutor_utils()->get_ip(), 'attempt_started_at' => $date, ); @@ -380,10 +398,12 @@ public function start_the_quiz() { $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_data ); $attempt_id = (int) $wpdb->insert_id; - do_action( 'tutor_quiz/start/after', $quiz_id, $user_id, $attempt_id ); - - wp_safe_redirect( get_permalink( $quiz_id ) ); - die(); + if ( $attempt_id ) { + do_action( 'tutor_quiz/start/after', $quiz_id, $user_id, $attempt_id ); + return $attempt_id; + } else { + return 0; + } } /** @@ -442,7 +462,6 @@ public static function tutor_quiz_attemp_submit() { tutor_utils()->checking_nonce(); // Prepare attempt info. - global $wpdb; $user_id = get_current_user_id(); $attempt_id = Input::post( 'attempt_id', 0, Input::TYPE_INT ); $attempt = tutor_utils()->get_attempt( $attempt_id ); @@ -456,17 +475,33 @@ public static function tutor_quiz_attemp_submit() { if ( ! $attempt || $user_id != $attempt->user_id ) { die( 'Operation not allowed, attempt not found or permission denied' ); } + self::manage_attempt_answers( $attempt_answers, $attempt, $attempt_id, $course_id, $user_id ); + return true; + } - // Before ook. + /** + * Manage attempt answers + * + * Evaluate each attempt answer and update the attempts table & insert in the attempt_answers table. + * + * @since 2.6.1 + * + * @param array $attempt_answers attempt answers. + * @param object $attempt single attempt. + * @param int $attempt_id attempt id. + * @param int $course_id course id. + * @param int $user_id user id. + * + * @return void + */ + public static function manage_attempt_answers( $attempt_answers, $attempt, $attempt_id, $course_id, $user_id ) { + global $wpdb; + // Before hook. do_action( 'tutor_quiz/attempt_analysing/before', $attempt_id ); - // Loop through every single attempt answer // Single quiz can have multiple question. So multiple answer should be saved. foreach ( $attempt_answers as $attempt_id => $attempt_answer ) { - - /** - * Get total marks of all question comes - */ + // Get total marks of all question comes. $question_ids = tutor_utils()->avalue_dot( 'quiz_question_ids', $attempt_answer ); $question_ids = array_filter( $question_ids, @@ -710,8 +745,6 @@ function ( $ans ) { // After hook. do_action( 'tutor_quiz/attempt_ended', $attempt_id, $course_id, $user_id ); - - return true; } diff --git a/classes/RestAPI.php b/classes/RestAPI.php index eb326e6df0..31b2fbae6d 100644 --- a/classes/RestAPI.php +++ b/classes/RestAPI.php @@ -278,7 +278,7 @@ public function init_routes() { 'methods' => 'GET', 'callback' => array( $this->announcement_obj, - 'course_annoucement', + 'course_announcement', ), 'args' => array( 'id' => array( diff --git a/classes/Shortcode.php b/classes/Shortcode.php index 4d02249e0b..a33f57466e 100644 --- a/classes/Shortcode.php +++ b/classes/Shortcode.php @@ -48,7 +48,6 @@ public function __construct() { add_shortcode( 'tutor_course', array( $this, 'tutor_course' ) ); add_shortcode( 'tutor_instructor_list', array( $this, 'tutor_instructor_list' ) ); - add_action( 'tutor_options_after_instructors', array( $this, 'tutor_instructor_layout' ) ); add_action( 'wp_ajax_load_filtered_instructor', array( $this, 'load_filtered_instructor' ) ); add_action( 'wp_ajax_nopriv_load_filtered_instructor', array( $this, 'load_filtered_instructor' ) ); @@ -460,15 +459,4 @@ function( $cat ) { wp_send_json_success( array( 'html' => ob_get_clean() ) ); exit; } - - /** - * Show layout selection dashboard in instructor setting - * - * @since 1.0.0 - * - * @return void - */ - public function tutor_instructor_layout() { - tutor_load_template( 'instructor-setting', array( 'templates' => $this->instructor_layout ) ); - } } diff --git a/classes/Tutor_Setup.php b/classes/Tutor_Setup.php index a538223c1d..d905d2d22e 100644 --- a/classes/Tutor_Setup.php +++ b/classes/Tutor_Setup.php @@ -470,7 +470,7 @@ public function tutor_setup_attributes() { ), 'enable_q_and_a_on_course' => array( 'type' => 'switch', - 'lable' => __( 'Question and Anwser', 'tutor' ), + 'lable' => __( 'Question and Answer', 'tutor' ), 'desc' => __( 'Allows a Q&A forum on each course.', 'tutor' ), ), 'courses_col_per_row' => array( diff --git a/gulpfile.js b/gulpfile.js index abfb675db5..3e9be7175b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,12 +2,13 @@ var gulp = require('gulp'), sass = require('gulp-sass')(require('sass')), sourcemaps = require('gulp-sourcemaps'), rename = require('gulp-rename'), - prefix = require('gulp-autoprefixer'), plumber = require('gulp-plumber'), notify = require('gulp-notify'), wpPot = require('gulp-wp-pot'), clean = require('gulp-clean'), zip = require('gulp-zip'), + watch = require("gulp-watch"), + gulpIf = require("gulp-if"), fs = require('fs'), path = require('path'), versionNumber = ''; @@ -29,12 +30,6 @@ var onError = function(err) { this.emit('end'); }; -var prefixerOptions = { - overrideBrowserslist: ['last 2 versions'], -}; - - - var scss_blueprints = { tutor_front: { src: 'assets/scss/front/index.scss', mode: 'expanded', destination: 'tutor-front.min.css' }, @@ -46,8 +41,9 @@ var scss_blueprints = { destination: 'tutor-setup.min.css', }, - tutor_v2: { src: 'v2-library/_src/scss/tutor-main.scss', mode: 'expanded', destination: 'tutor.min.css' }, + tutor_v2: { src: 'v2-library/_src/scss/main.scss', mode: 'expanded', destination: 'tutor.min.css' }, tutor_v2_rtl: { src: 'v2-library/_src/scss/main.rtl.scss', mode: 'expanded', destination: 'tutor.rtl.min.css' }, + tutor_icon: { src: 'v2-library/bundle/fonts/tutor-icon/tutor-icon.css', mode: 'expanded', @@ -65,21 +61,14 @@ var scss_blueprints = { mode: 'expanded', destination: 'tutor-course-builder.min.css', }, - - v2_scss: { src: 'v2-library/_src/scss/main.scss', destination: 'main.min.css', dest_path: 'v2-library/bundle' }, - v2_rtl_scss: { src: 'v2-library/_src/scss/main.rtl.scss', destination: 'main.rtl.min.css', dest_path: 'v2-library/bundle' }, - - v2_scss_docz: { - src: 'v2-library/_src/scss/main.scss', - destination: 'main.min.css', - dest_path: '.docz/static/v2-library/bundle', - }, }; var task_keys = Object.keys(scss_blueprints); for (let task in scss_blueprints) { let blueprint = scss_blueprints[task]; + const isV2 = blueprint.src === 'v2-library/_src/scss/main.scss' + const isV2RTL = blueprint.src === 'v2-library/_src/scss/main.rtl.scss' gulp.task(task, function() { return gulp @@ -88,26 +77,15 @@ for (let task in scss_blueprints) { .pipe(sourcemaps.init({ loadMaps: true, largeFile: true })) .pipe(sass({ outputStyle: 'compressed', sass: require('sass') })) .pipe(rename(blueprint.destination)) - .pipe(gulp.dest(blueprint.dest_path || 'assets/css')); + .pipe(gulp.dest(blueprint.dest_path || 'assets/css')) + .pipe(gulpIf(isV2, rename('main.min.css'))) + .pipe(gulpIf(isV2, gulp.dest('v2-library/bundle'))) + .pipe(gulpIf(isV2, gulp.dest('.docz/static/v2-library/bundle'))) + .pipe(gulpIf(isV2RTL, rename('main.rtl.min.css'))) + .pipe(gulpIf(isV2RTL, gulp.dest('v2-library/bundle'))); }); } -// Add task to add tutor prefix to v2 scss -// gulp.task('v2_tutor_prefix', function(resolve) { -// var exp = path.resolve(__dirname + '/assets/css/tutor.min.css'); -// var min = path.resolve(__dirname + '/assets/css/tutor.min.css'); -// var docz = path.resolve(__dirname + '/v2-library/bundle/main.min.css'); - -// [exp, min, docz].forEach((css) => { -// var string = fs.readFileSync(css).toString(); -// string = string.replace(/\.tutor\-prefix \./g, '.tutor-'); -// fs.writeFileSync(css, string); -// }); - -// resolve(); -// }); -// task_keys.push('v2_tutor_prefix'); - var added_texts = []; const regex = /__\(\s*(['"])((?:(?!(?prefix . 'tutor_quiz_attempt_answers'; + $table_quiz_questions = $wpdb->prefix . 'tutor_quiz_questions'; + $table_quiz_attempts = $wpdb->prefix . 'tutor_quiz_attempts'; + $table_quiz_question_answers = $wpdb->prefix . 'tutor_quiz_question_answers'; + + $query = "SELECT + ques.question_id, + ques.question_title, + ques.question_type, + ( + SELECT + GROUP_CONCAT(answer_title) + FROM + {$table_quiz_question_answers} + WHERE + belongs_question_id = ques.question_id + AND is_correct = 1 + ) AS correct_answers, + + ( + + SELECT + + CASE + WHEN CHAR_LENGTH(att_ans.given_answer) = 1 AND att_ans.given_answer REGEXP '^[0-9]$' THEN + -- If given_answer is a single digit integer + ( + SELECT + answer_title + FROM + {$table_quiz_question_answers} + WHERE + answer_id = CAST(att_ans.given_answer AS UNSIGNED) + ) + WHEN CHAR_LENGTH(att_ans.given_answer) > 1 AND SUBSTRING(att_ans.given_answer, 1, 2) = 'a:' THEN + -- If given_answer is serialized array + ( + att_ans.given_answer + ) + ELSE + -- If given_answer is a serialized string + att_ans.given_answer + END + ) AS given_answer, + att_ans.question_mark, + att_ans.achieved_mark, + att_ans.is_correct, + ( + SELECT + attempt_info + FROM {$table_quiz_attempts} + WHERE attempt_id = {$attempt_id} + LIMIT 1 + ) AS attempt_info + FROM + {$table_quiz_attempt_answers} AS att_ans + JOIN {$table_quiz_questions} AS ques ON ques.question_id = att_ans.question_id + JOIN {$table_quiz_question_answers} AS ans ON ans.answer_id = att_ans.attempt_answer_id + WHERE + quiz_attempt_id = %d + LIMIT + 50 + "; + + $result = $wpdb->get_results( $wpdb->prepare( $query, $attempt_id ) ); + + // If array and count result then loop with each result and prepare given answer. + if ( is_array( $result ) && count( $result ) ) { + foreach ( $result as $key => $value ) { + // Check if given answer is a serialized string. + if ( is_serialized( $value->given_answer ) ) { + $given_answers = tutor_utils()->get_answer_by_id( maybe_unserialize( $value->given_answer ) ); + $result[ $key ]->given_answer = array_column( $given_answers, 'answer_title' ); + } elseif ( is_numeric( $value->given_answer ) ) { + $given_answers = tutor_utils()->get_answer_by_id( maybe_unserialize( $value->given_answer ) ); + $result[ $key ]->given_answer = array_column( $given_answers, 'answer_title' ); + } + } + } + + return $result; + } } diff --git a/package-lock.json b/package-lock.json index 6d7f7c4f74..07a0464cf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3812,7 +3812,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", - "dev": true, "requires": { "ansi-wrap": "0.1.0" } @@ -3847,8 +3846,7 @@ "ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", - "dev": true + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==" }, "anymatch": { "version": "3.1.3", @@ -5958,8 +5956,7 @@ "clone-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", - "dev": true + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==" }, "clone-deep": { "version": "4.0.1", @@ -5989,14 +5986,12 @@ "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", - "dev": true + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==" }, "cloneable-readable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "process-nextick-args": "^2.0.0", @@ -6078,8 +6073,7 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, "colorette": { "version": "2.0.20", @@ -9468,6 +9462,57 @@ } } }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -9909,6 +9954,11 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "optional": true }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==" + }, "filesize": { "version": "3.5.11", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz", @@ -10158,6 +10208,14 @@ "parse-filepath": "^1.0.1" } }, + "first-chunk-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha512-X8Z+b/0L4lToKYq+lwnKqi9X/Zek0NibLpsJgVsSxpoYq7JtiCtRb5HqKVEjEw/qAb/4AKKRLOwwKHlWNpm2Eg==", + "requires": { + "readable-stream": "^2.0.2" + } + }, "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", @@ -10236,6 +10294,11 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" }, + "fork-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", + "integrity": "sha512-Pqq5NnT78ehvUnAk/We/Jr22vSvanRlFTpAmQ88xBY/M1TlHe+P0ILuEyXS595ysdGfaj22634LBkGMA2GTcpA==" + }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", @@ -12839,6 +12902,38 @@ "path-is-absolute": "^1.0.0" } }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -13727,32 +13822,6 @@ } } }, - "gulp-autoprefixer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gulp-autoprefixer/-/gulp-autoprefixer-7.0.1.tgz", - "integrity": "sha512-QJGEmHw+bEt7FSqvmbAUTxbCuNLJYx4sz3ox9WouYqT/7j5FH5CQ8ZnpL1M7H5npX1bUJa7lUVY1w20jXxhOxg==", - "dev": true, - "requires": { - "autoprefixer": "^9.6.1", - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.1", - "postcss": "^7.0.17", - "through2": "^3.0.1", - "vinyl-sourcemaps-apply": "^0.2.1" - }, - "dependencies": { - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - } - } - }, "gulp-clean": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz", @@ -14324,6 +14393,35 @@ } } }, + "gulp-if": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-3.0.0.tgz", + "integrity": "sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw==", + "requires": { + "gulp-match": "^1.1.0", + "ternary-stream": "^3.0.0", + "through2": "^3.0.1" + }, + "dependencies": { + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, + "gulp-match": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz", + "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==", + "requires": { + "minimatch": "^3.0.3" + } + }, "gulp-notify": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", @@ -14468,100 +14566,711 @@ "kind-of": "^1.1.0" } }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", - "dev": true - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", - "dev": true, - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - } + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", + "dev": true + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, + "gulp-rename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", + "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", + "dev": true + }, + "gulp-sass": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-5.1.0.tgz", + "integrity": "sha512-7VT0uaF+VZCmkNBglfe1b34bxn/AfcssquLKVDYnCDJ3xNBaW7cUuI3p3BQmoKcoKFrs9jdzUxyb+u+NGfL4OQ==", + "dev": true, + "requires": { + "lodash.clonedeep": "^4.5.0", + "picocolors": "^1.0.0", + "plugin-error": "^1.0.1", + "replace-ext": "^2.0.0", + "strip-ansi": "^6.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true + } + } + }, + "gulp-sourcemaps": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", + "dev": true, + "requires": { + "@gulp-sourcemaps/identity-map": "1.X", + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "5.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "1.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom-string": "1.X", + "through2": "2.X" + }, + "dependencies": { + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "gulp-watch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", + "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", + "requires": { + "ansi-colors": "1.1.0", + "anymatch": "^1.3.0", + "chokidar": "^2.0.0", + "fancy-log": "1.3.2", + "glob-parent": "^3.0.1", + "object-assign": "^4.1.0", + "path-is-absolute": "^1.0.1", + "plugin-error": "1.0.1", + "readable-stream": "^2.2.2", + "slash": "^1.0.0", + "vinyl": "^2.1.0", + "vinyl-file": "^2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "requires": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "fancy-log": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha512-7E6IFy84FpO6jcnzEsCcoxDleHpMTFzncmCXXBIVYq1/Oakqnbc/lTKPJyyW6edGeC/rnZmV78hJe7SuoZo0aQ==", + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "requires": { + "hasown": "^2.0.0" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "requires": { + "hasown": "^2.0.0" + } + }, + "is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "requires": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "requires": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==" }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "requires": { - "ansi-regex": "^2.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - } - } - }, - "gulp-rename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", - "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", - "dev": true - }, - "gulp-sass": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-5.1.0.tgz", - "integrity": "sha512-7VT0uaF+VZCmkNBglfe1b34bxn/AfcssquLKVDYnCDJ3xNBaW7cUuI3p3BQmoKcoKFrs9jdzUxyb+u+NGfL4OQ==", - "dev": true, - "requires": { - "lodash.clonedeep": "^4.5.0", - "picocolors": "^1.0.0", - "plugin-error": "^1.0.1", - "replace-ext": "^2.0.0", - "strip-ansi": "^6.0.1", - "vinyl-sourcemaps-apply": "^0.2.1" - }, - "dependencies": { - "replace-ext": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", - "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", - "dev": true - } - } - }, - "gulp-sourcemaps": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", - "dev": true, - "requires": { - "@gulp-sourcemaps/identity-map": "1.X", - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "5.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "1.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom-string": "1.X", - "through2": "2.X" - }, - "dependencies": { - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -14829,6 +15538,21 @@ } } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + }, + "dependencies": { + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + } + } + }, "hast-to-hyperscript": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", @@ -15866,6 +16590,19 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", + "requires": { + "is-primitive": "^2.0.0" + } + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -16019,6 +16756,16 @@ "isobject": "^3.0.1" } }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==" + }, "is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -16151,8 +16898,7 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" }, "is-valid-domain": { "version": "0.1.6", @@ -17270,6 +18016,11 @@ "integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==", "dev": true }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, "md5-file": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-5.0.0.tgz", @@ -19137,6 +19888,25 @@ "make-iterator": "^1.0.0" } }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "requires": { + "for-in": "^1.0.1" + } + } + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -19530,6 +20300,32 @@ "path-root": "^0.1.1" } }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -19961,7 +20757,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, "requires": { "ansi-colors": "^1.0.1", "arr-diff": "^4.0.0", @@ -19973,7 +20768,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, "requires": { "ansi-wrap": "^0.1.0" } @@ -21152,6 +21946,11 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==" + }, "prettier": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", @@ -21428,6 +22227,28 @@ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + } + } + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -22376,6 +23197,14 @@ "@babel/runtime": "^7.8.4" } }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, "regex-escape": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/regex-escape/-/regex-escape-3.4.10.tgz", @@ -24338,6 +25167,25 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" }, + "strip-bom-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", + "integrity": "sha512-yH0+mD8oahBZWnY43vxs4pSinn8SMKAdml/EOGBewoe1Y0Eitd0h2Mg3ZRiXruUW6L4P+lvZiEgbh0NgUGia1w==", + "requires": { + "first-chunk-stream": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, "strip-bom-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", @@ -24716,6 +25564,49 @@ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" }, + "ternary-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-3.0.0.tgz", + "integrity": "sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ==", + "requires": { + "duplexify": "^4.1.1", + "fork-stream": "^0.0.4", + "merge-stream": "^2.0.0", + "through2": "^3.0.1" + }, + "dependencies": { + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, "terser": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", @@ -24879,8 +25770,7 @@ "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", - "dev": true + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==" }, "timed-out": { "version": "4.0.1", @@ -26152,7 +27042,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, "requires": { "clone": "^2.1.1", "clone-buffer": "^1.0.0", @@ -26165,8 +27054,55 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + } + } + }, + "vinyl-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", + "integrity": "sha512-44i5QVLwRPbiRyuiHJ+zJXooNNRXUUifdfYIC1Gm7YTlemMgYQrZ+q1LERS6AYAN8w0xe7n9OgjEYckQjR5+4g==", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.3.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0", + "strip-bom-stream": "^2.0.0", + "vinyl": "^1.1.0" + }, + "dependencies": { + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==" + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha512-Ci3wnR2uuSAWFMSglZuB8Z2apBdtOyz8CV7dC6/U1XbltXBC+IuutUkXQISz01P+US2ouBuesSbV6zILZ6BuzQ==", + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } } } }, diff --git a/package.json b/package.json index 5cb465ead8..31cb4b9254 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "eslint-loader": "^4.0.2", "fs": "0.0.1-security", "gulp": "^4.0.2", - "gulp-autoprefixer": "^7.0.1", "gulp-clean": "^0.4.0", "gulp-cssnano": "^2.1.3", "gulp-notify": "^3.2.0", @@ -82,6 +81,8 @@ "docz": "^2.3.1", "emotion": "^11.0.0", "fs-extra": "^10.0.0", + "gulp-if": "^3.0.0", + "gulp-watch": "^5.0.1", "immutability-helper": "^3.1.1", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.2.2", diff --git a/readme.txt b/readme.txt index 6dd04a3d71..6627128357 100644 --- a/readme.txt +++ b/readme.txt @@ -5,7 +5,7 @@ Tags: lms, course, elearning, education, learning management system Requires at least: 5.3 Tested up to: 6.4 Requires PHP: 7.4 -Stable tag: 2.6.0 +Stable tag: 2.6.1 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -316,6 +316,13 @@ These key integrations with Tutor LMS extend its capabilities for a more powerfu == Changelog == += 2.6.1 - February 19, 2024 + +New: Added API functionality for submitting and retrieving list of quizzes (Pro) +Update: Improved security to ensure safe submission of questions and answers +Update: Improved response data, extendability, and performance across all APIs within the Tutor LMS Free plugin +Fix: Fixed issue causing "Resource not found" error related to ChatGPT (Pro) + = 2.6.0 - January 11, 2024 New: Added Write and Delete permissions in REST API (Pro) diff --git a/restapi/REST_Author.php b/restapi/REST_Author.php index 9a48ac0ae5..27eee61450 100644 --- a/restapi/REST_Author.php +++ b/restapi/REST_Author.php @@ -1,50 +1,76 @@ + * @link https://themeum.com + * @since 1.7.1 + */ + namespace TUTOR; + use WP_REST_Request; -if(!defined( 'ABSPATH' )) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Author + * + * @package Tutor + * @since 1.0.0 + */ class REST_Author { use REST_Response; + /** + * User ID. + * + * @var int $user_id The ID of the user. + */ private $user_id; - /* - *require user id - *return json object with user detail - */ - public function author_detail(WP_REST_Request $request) { - $this->user_id = $request->get_param('id'); - global $wpdb; - $table = $wpdb->prefix."users"; - //author obj - $author = $wpdb->get_row( - $wpdb->prepare( - "SELECT user_email, user_registered, display_name FROM $table WHERE ID = %d", - $this->user_id - )); - - if($author) { - //get author course id - $author->courses = get_user_meta($this->user_id,'_tutor_instructor_course_id',false); + /** + * Retrieve author details via REST API. + * + * @param WP_REST_Request $request The REST request object. + * + * @return mixed + */ + public function author_detail( WP_REST_Request $request ) { + $this->user_id = $request->get_param( 'id' ); + + $user_data = get_userdata( $this->user_id ); + + // Author object. + $author = is_a( $user_data, 'WP_User' ) ? $user_data->data : false; + + if ( $author ) { + // Unset user pass & key. + unset( $author->user_pass ); + unset( $author->user_activation_key ); + + // Get author course ID. + $author->courses = get_user_meta( $this->user_id, '_tutor_instructor_course_id', false ); $response = array( - 'status_code'=> 'success', - 'message'=> __('Author details retrieved successfully','tutor'), - 'data'=> $author + 'status_code' => 'success', + 'message' => __( 'Author details retrieved successfully', 'tutor' ), + 'data' => $author, ); - return self::send($response); + return self::send( $response ); } - + $response = array( - 'status_code'=> 'invalid_id', - 'message'=> __('Author not found','tutor'), - 'data'=> [] + 'status_code' => 'invalid_id', + 'message' => __( 'Author not found', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } } diff --git a/restapi/REST_Course.php b/restapi/REST_Course.php index 5eee138fb4..3e415281d9 100644 --- a/restapi/REST_Course.php +++ b/restapi/REST_Course.php @@ -1,292 +1,403 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + use WP_REST_Request; use WP_Query; -if( !defined ('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} -class REST_Course { - - use REST_Response; +/** + * Rest_Course class + */ +class REST_Course { - private $post_type; + use REST_Response; - private $course_cat_tax = "course-category"; - private $course_tag_tax = "course-tag"; + /** + * The post type associated with the course handler. + * + * @since 1.7.1 + * + * @var string $post_type The post type for courses. + */ + private $post_type; + /** + * The taxonomy for course categories. + * + * @since 1.7.1 + * + * @var string $course_cat_tax The taxonomy for course categories. + */ + private $course_cat_tax = 'course-category'; + + /** + * The taxonomy for course tags. + * + * @since 1.7.1 + * + * @var string $course_tag_tax The taxonomy for course tags. + */ + private $course_tag_tax = 'course-tag'; + + /** + * Constructor for the Tutor_Course_Handler class. + * + * Initializes the post type property. + * + * @since 1.7.1 + */ public function __construct() { $this->post_type = tutor()->course_post_type; } - /* - *require rest request - *return course info - *pagination enable - *category,tags terms included - */ - public function course(WP_REST_Request $request) { - $order = sanitize_text_field($request->get_param('order')); - $orderby = sanitize_text_field($request->get_param('orderby')); - $paged = sanitize_text_field($request->get_param('paged')); + /** + * Course read API handler + * + * Get course list along with pagination, categories, tags + * author details, reviews + * + * @param WP_REST_Request $request request data. + * + * @return WP_REST_Response + */ + public function course( WP_REST_Request $request ) { + $order = sanitize_text_field( $request->get_param( 'order' ) ); + $orderby = sanitize_text_field( $request->get_param( 'orderby' ) ); + $paged = sanitize_text_field( $request->get_param( 'paged' ) ); $args = array( - 'post_type' => $this->post_type, - 'post_status' => 'publish', - 'posts_per_page' => 10, - 'paged' => $paged ? $paged : 1, - 'order' => $order ? $order : 'ASC', - 'orderby' => $orderby ? $orderby :'title' + 'post_type' => $this->post_type, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'paged' => $paged ? $paged : 1, + 'order' => $order ? $order : 'ASC', + 'orderby' => $orderby ? $orderby : 'title', ); - $query = new WP_Query($args); + $args = apply_filters( 'tutor_rest_course_query_args', $args ); + $query = new WP_Query( $args ); - //if post found - if(count($query->posts)>0) { - //unset filter properpty - array_map(function($post){ - unset($post->filter); - }, $query->posts); + // if post found. + if ( count( $query->posts ) > 0 ) { + // unset filter property. + array_map( + function( $post ) { + unset( $post->filter ); + }, + $query->posts + ); - $data = [ - 'posts'=> [], + $data = array( + 'posts' => array(), 'total_course' => $query->found_posts, - 'total_page' => $query->max_num_pages - ]; + 'total_page' => $query->max_num_pages, + ); - foreach($query->posts as $post) { - $category = wp_get_post_terms($post->ID,$this->course_cat_tax); + foreach ( $query->posts as $post ) { + $category = wp_get_post_terms( $post->ID, $this->course_cat_tax ); - $tag = wp_get_post_terms($post->ID,$this->course_tag_tax); + $tag = wp_get_post_terms( $post->ID, $this->course_tag_tax ); + + $author = get_userdata( $post->post_author ); + + if ( $author ) { + // Unset user pass & key. + unset( $author->data->user_pass ); + unset( $author->data->user_activation_key ); + } + + is_a( $author, 'WP_User' ) ? $post->post_author = $author->data : new \stdClass(); + + $thumbnail_size = apply_filters( 'tutor_rest_course_thumbnail_size', 'post-thumbnail' ); + $post->thumbnail_url = get_the_post_thumbnail_url( $post->ID, $thumbnail_size ); + + $post->additional_info = $this->course_additional_info( $post->ID ); + + $post->ratings = tutor_utils()->get_course_rating( $post->ID ); $post->course_category = $category; $post->course_tag = $tag; - array_push($data['posts'], $post); - + $post = apply_filters( 'tutor_rest_course_single_post', $post ); + array_push( $data['posts'], $post ); } $response = array( - 'status_code'=> "success", - "message"=> __('Course retrieved successfully','tutor'), - 'data'=> $data + 'status_code' => 'success', + 'message' => __( 'Course retrieved successfully', 'tutor' ), + 'data' => $data, ); - return self::send($response); + return self::send( $response ); } $response = array( - 'status_code'=> "not_found", - "message"=> __('Course not found','tutor'), - 'data'=> [] + 'status_code' => 'not_found', + 'message' => __( 'Course not found', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } - /* - *require rest request - *return post meta items - */ - function course_detail(WP_REST_Request $request) { - $post_id = $request->get_param('id'); + /** + * Course Details API handler + * + * @since 1.7.1 + * + * @param WP_REST_Request $request request params. + * + * @return WP_REST_Response + */ + public function course_detail( WP_REST_Request $request ) { + $post_id = $request->get_param( 'id' ); + + $detail = $this->course_additional_info( $post_id ); + if ( $detail ) { + $response = array( + 'status_code' => 'course_detail', + 'message' => __( 'Course detail retrieved successfully', 'tutor' ), + 'data' => $detail, + ); + return self::send( $response ); + } + $response = array( + 'status_code' => 'course_detail', + 'message' => __( 'Detail not found for given ID', 'tutor' ), + 'data' => array(), + ); + + return self::send( $response ); + } + /** + * Get course additional info + * + * @since 2.6.1 + * + * @param integer $post_id post id. + * + * @return array + */ + public function course_additional_info( int $post_id ) { $detail = array( - 'course_settings' => get_post_meta($post_id,'_tutor_course_settings',false), + 'course_settings' => get_post_meta( $post_id, '_tutor_course_settings', false ), - 'course_price_type' => get_post_meta($post_id,'_tutor_course_price_type',false), + 'course_price_type' => get_post_meta( $post_id, '_tutor_course_price_type', false ), - 'course_duration' => get_post_meta($post_id,'_course_duration',false), + 'course_duration' => get_post_meta( $post_id, '_course_duration', false ), - 'course_level' => get_post_meta($post_id,'_tutor_course_level',false), + 'course_level' => get_post_meta( $post_id, '_tutor_course_level', false ), - 'course_benefits' => get_post_meta($post_id,'_tutor_course_benefits',false), + 'course_benefits' => get_post_meta( $post_id, '_tutor_course_benefits', false ), - 'course_requirements' => get_post_meta($post_id,'_tutor_course_requirements',false), + 'course_requirements' => get_post_meta( $post_id, '_tutor_course_requirements', false ), - 'course_target_audience' => get_post_meta($post_id,'_tutor_course_target_audience',false), + 'course_target_audience' => get_post_meta( $post_id, '_tutor_course_target_audience', false ), - 'course_material_includes' => get_post_meta($post_id,'_tutor_course_material_includes',false), + 'course_material_includes' => get_post_meta( $post_id, '_tutor_course_material_includes', false ), - 'video' => get_post_meta($post_id,'_video',false), - - 'disable_qa' => get_post_meta($post_id, '_tutor_enable_qa', true)!='yes' + 'video' => get_post_meta( $post_id, '_video', false ), + + 'disable_qa' => get_post_meta( $post_id, '_tutor_enable_qa', true ) != 'yes', ); - if($detail) { - $response = array( - 'status_code' => "course_detail", - "message" => __('Course detail retrieved successfully','tutor'), - 'data' => $detail - ); - return self::send($response); - } - $response = array( - 'status_code' => "course_detail", - "message" => __('Detail not found for given ID','tutor'), - 'data' => [] - ); + return apply_filters( 'tutor_course_additional_info', $detail ); - return self::send($response); } - /* - *return post type terms - */ - public function course_by_terms(WP_REST_Request $request) { - $post_fields = $request->get_params(); - $validate_err = $this->validate_terms($post_fields); - - //check array or not - if(count($validate_err)>0) { + /** + * Get Course by Terms API handler + * + * @since 1.7.1 + * + * @param WP_REST_Request $request request params. + * + * @return WP_REST_Response + */ + public function course_by_terms( WP_REST_Request $request ) { + $post_fields = $request->get_params(); + $validate_err = $this->validate_terms( $post_fields ); + + // check array or not. + if ( count( $validate_err ) > 0 ) { $response = array( - 'status_code'=> "validation_error", - "message"=> $validate_err, - 'data'=> [] - ); + 'status_code' => 'validation_error', + 'message' => $validate_err, + 'data' => array(), + ); - return self::send($response); + return self::send( $response ); } - //sanitize terms + // sanitize terms. $categories = sanitize_term( $request['categories'], $this->course_cat_tax, $context = 'db' ); $tags = sanitize_term( $request['tags'], $this->course_tag_tax, $context = 'db' ); $args = array( - 'post_type' => $this->post_type, - 'tax_query' => array( - 'relation' => 'OR', - array( - 'taxonomy' => $this->course_cat_tax, - 'field' => 'name', - 'terms' => $categories - ), - array( - 'taxonomy' => $this->course_tag_tax, - 'field' => 'name', - 'terms' => $tags - - ) - ) + 'post_type' => $this->post_type, + 'tax_query' => array( + 'relation' => 'OR', + array( + 'taxonomy' => $this->course_cat_tax, + 'field' => 'name', + 'terms' => $categories, + ), + array( + 'taxonomy' => $this->course_tag_tax, + 'field' => 'name', + 'terms' => $tags, + + ), + ), ); - $query = new WP_Query ($args); + $args = apply_filters( 'tutor_rest_course_by_terms_query_args', $args ); + $query = new WP_Query( $args ); - if(count($query->posts)>0) { - //unset filter proterty - array_map(function($post){ - unset($post->filter); - }, $query->posts); + if ( count( $query->posts ) > 0 ) { + // unset filter property. + array_map( + function( $post ) { + unset( $post->filter ); + }, + $query->posts + ); $response = array( - 'status_code'=> "success", - "message"=> __("Course retrieved successfully",'tutor'), - 'data'=> $query->posts - ); + 'status_code' => 'success', + 'message' => __( 'Course retrieved successfully', 'tutor' ), + 'data' => $query->posts, + ); - return self::send($response); + return self::send( $response ); } $response = array( - 'status_code'=> "not_found", - "message"=> __("Course not found for given terms",'tutor'), - 'data'=> [] - ); - return self::send($response); + 'status_code' => 'not_found', + 'message' => __( 'Course not found for given terms', 'tutor' ), + 'data' => array(), + ); + return self::send( $response ); } - /* - *categories array validation - *tags array validation - */ - public function validate_terms(array $post) { + /** + * Validate terms + * + * @since 1.7.1 + * + * @param array $post post array. + * + * @return array validation errors. + */ + public function validate_terms( array $post ) { $categories = $post['categories']; - $tags = $post['tags']; + $tags = $post['tags']; - $error = []; + $error = array(); - if (!is_array($categories)) { - array_push($error,__('Categories field is not an array','tutor')); + if ( ! is_array( $categories ) ) { + array_push( $error, __( 'Categories field is not an array', 'tutor' ) ); } - - if (!is_array($tags)) { - array_push($error,__('Tags field is not an array','tutor')); + + if ( ! is_array( $tags ) ) { + array_push( $error, __( 'Tags field is not an array', 'tutor' ) ); } return $error; } - public function course_sort_by_price(WP_REST_Request $request) { - $order = $request->get_param('order'); - $paged = $request->get_param('page'); - - $order = sanitize_text_field($order); - $paged = sanitize_text_field($paged); + /** + * Course sort by price API handler + * + * @since 1.7.1 + * + * @param WP_REST_Request $request request params. + * + * @return WP_REST_Response + */ + public function course_sort_by_price( WP_REST_Request $request ) { + $order = $request->get_param( 'order' ); + $paged = $request->get_param( 'page' ); + + $order = sanitize_text_field( $order ); + $paged = sanitize_text_field( $paged ); $args = array( - 'post_type'=> 'product', - 'post_status'=> 'publish', - 'posts_per_page' => 10, - 'paged'=> $paged ? $paged : 1, - - 'meta_key'=> '_regular_price', - 'orderby'=> 'meta_value_num', - 'order'=> $order, - 'meta_query'=> array( - 'relation'=>'AND', - array( - 'key'=> '_tutor_product', - 'value'=> "yes" - - ) - ) + 'post_type' => 'product', + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'paged' => $paged ? $paged : 1, + + 'meta_key' => '_regular_price', + 'orderby' => 'meta_value_num', + 'order' => $order, + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => '_tutor_product', + 'value' => 'yes', + + ), + ), ); + $args = apply_filters( 'tutor_rest_course_sort_by_price_args', $args ); $query = new WP_Query( $args ); - if (count($query->posts)>0) { - //unset filter property - array_map(function($post){ - unset($post->filter); - }, $query->posts); + if ( count( $query->posts ) > 0 ) { + // unset filter property. + array_map( + function( $post ) { + unset( $post->filter ); + }, + $query->posts + ); - $posts = []; + $posts = array(); - foreach ($query->posts as $post) { - $post->price = get_post_meta($post->ID,'_regular_price', true); - array_push($posts, $post); + foreach ( $query->posts as $post ) { + $post->price = get_post_meta( $post->ID, '_regular_price', true ); + array_push( $posts, $post ); } $data = array( - 'posts'=> $posts, + 'posts' => $posts, 'total_course' => $query->found_posts, - 'total_page' => $query->max_num_pages + 'total_page' => $query->max_num_pages, ); $response = array( - 'status_code'=> 'success', - 'message'=> __('Course retrieved successfully','tutor'), - 'data'=> $data + 'status_code' => 'success', + 'message' => __( 'Course retrieved successfully', 'tutor' ), + 'data' => $data, ); - return self::send($response); + return self::send( $response ); } - + $response = array( - 'status'=> 'not_found', - 'message'=> __('Course not found','tutor'), - 'data'=> [] + 'status' => 'not_found', + 'message' => __( 'Course not found', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } } diff --git a/restapi/REST_Course_Announcement.php b/restapi/REST_Course_Announcement.php index 1231278f39..6337cc30d2 100644 --- a/restapi/REST_Course_Announcement.php +++ b/restapi/REST_Course_Announcement.php @@ -1,53 +1,81 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + use WP_REST_Request; -if(!defined('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Course_Announcement + * + * @package Tutor + * @since 1.0.0 + */ class REST_Course_Announcement { use REST_Response; + /** + * Post parent ID. + * + * @var int $post_parent The ID of the post parent. + */ private $post_parent; - private $post_type = "tutor_announcements"; - /* - *require rest request - *return accoucement by course id - */ - public function course_annoucement(WP_REST_Request $request) { - $this->post_parent = $request->get_param('id'); + /** + * Post type. + * + * @var string $post_type The post type for announcements. + */ + private $post_type = 'tutor_announcements'; + + /** + * Retrieve announcements by course ID via REST API. + * + * @since 1.7.1 + * + * @param WP_REST_Request $request The REST request object. + * + * @return mixed + */ + public function course_announcement( WP_REST_Request $request ) { + $this->post_parent = $request->get_param( 'id' ); global $wpdb; - $table = $wpdb->prefix."posts"; + $table = $wpdb->prefix . 'posts'; $result = $wpdb->get_results( - $wpdb->prepare("SELECT ID, post_title, post_content, post_name FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent) + $wpdb->prepare( "SELECT ID, post_title, post_content, post_name FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent ) ); - if (count($result)>0) { + if ( count( $result ) > 0 ) { $response = array( - 'status_code'=> "success", - "message"=> __('Announcement retrieved successfully','tutor'), - 'data'=> $result - ); - - return self::send($response); + 'status_code' => 'success', + 'message' => __( 'Announcement retrieved successfully', 'tutor' ), + 'data' => $result, + ); + + return self::send( $response ); } $response = array( - 'status_code'=> "not_found", - "message"=> __('Announcement not found for given ID','tutor'), - 'data'=> [] - ); - - return self::send($response); + 'status_code' => 'not_found', + 'message' => __( 'Announcement not found for given ID', 'tutor' ), + 'data' => array(), + ); + + return self::send( $response ); } } diff --git a/restapi/REST_Lesson.php b/restapi/REST_Lesson.php index 36c80dc54c..70280f80fe 100644 --- a/restapi/REST_Lesson.php +++ b/restapi/REST_Lesson.php @@ -1,68 +1,114 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + +use WP_Query; use WP_REST_Request; -if(!defined('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Lesson + */ class REST_Lesson { use REST_Response; - + + /** + * Post type + * + * @var string $post_type + */ private $post_type; + + /** + * Post parent ID + * + * @var int $post_parent + */ private $post_parent; + /** + * REST_Lesson constructor. + */ public function __construct() { $this->post_type = tutor()->lesson_post_type; } - public function topic_lesson(WP_REST_Request $request) { - $this->post_parent = $request->get_param('id'); - global $wpdb; + /** + * Get lessons for a specific topic. + * + * @param WP_REST_Request $request REST request object. + * + * @return mixed + */ + public function topic_lesson( WP_REST_Request $request ) { + $this->post_parent = $request->get_param( 'id' ); + + $args = array( + 'post_type' => $this->post_type, + 'post_parent' => $this->post_parent, + 'posts_per_page' => -1, + ); - $table = $wpdb->prefix."posts"; + $lessons_query = new WP_Query( $args ); - $lessons = $wpdb->get_results( - $wpdb->prepare("SELECT ID, post_title, post_content, post_name, (SELECT post_parent from {$table} WHERE ID = {$this->post_parent} ) as course_id FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent) - ); - $data = array(); - if(count($lessons)>0) { - foreach ($lessons as $lesson) { - $attachments = []; - $attachments_id = get_post_meta($lesson->ID,'_tutor_attachments',false); + if ( $lessons_query->have_posts() ) { + while ( $lessons_query->have_posts() ) { + $lessons_query->the_post(); + + $lesson = new \stdClass(); + + $lesson->ID = get_the_ID(); + $lesson->post_title = get_the_title(); + $lesson->post_content = get_the_content(); + $lesson->post_name = $post->post_name; + $lesson->course_id = wp_get_post_parent_id( $lesson->ID ); + + $attachments = array(); + $attachments_id = get_post_meta( $lesson->ID, '_tutor_attachments', false ); $attachments_id = $attachments_id[0]; - foreach($attachments_id as $id) { - $guid = get_the_guid($id); - array_push($attachments, $guid); + + foreach ( $attachments_id as $id ) { + $guid = get_the_guid( $id ); + array_push( $attachments, $guid ); } $lesson->attachments = $attachments; - $lesson->thumbnail = get_the_post_thumbnail_url($lesson->ID); - $lesson->video = get_post_meta($lesson->ID, '_video',false); - array_push($data, $lesson); + $lesson->thumbnail = get_the_post_thumbnail_url( $lesson->ID ); + $lesson->video = get_post_meta( $lesson->ID, '_video', false ); + + array_push( $data, $lesson ); } $response = array( - 'status_code'=> "success", - "message"=> __('Lesson retrieved successfully','tutor'), - 'data'=> $data + 'status_code' => 'success', + 'message' => __( 'Lesson retrieved successfully', 'tutor' ), + 'data' => $data, ); - return self::send($response); + return self::send( $response ); } + $response = array( - 'status_code'=> "not_found", - "message"=> __('Lesson not found for given topic ID','tutor'), - 'data'=> [] + 'status_code' => 'not_found', + 'message' => __( 'Lesson not found for the given topic ID', 'tutor' ), + 'data' => array(), ); - return self::send($response); - } + + return self::send( $response ); + } + } diff --git a/restapi/REST_Quiz.php b/restapi/REST_Quiz.php index 4c7f04af40..e3e24f9765 100644 --- a/restapi/REST_Quiz.php +++ b/restapi/REST_Quiz.php @@ -1,210 +1,350 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + +use Themeum\Products\Helpers\QueryHelper; use WP_REST_Request; -if(!defined ('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Quiz + */ class REST_Quiz { use REST_Response; - private $post_type = "tutor_quiz"; + /** + * Quiz post type + * + * @var string The post type for quizzes. + */ + private $post_type = 'tutor_quiz'; + + /** + * Post parent ID + * + * @var int|null The post parent ID. + */ private $post_parent; - private $t_quiz_question = "tutor_quiz_questions"; - private $t_quiz_ques_ans = "tutor_quiz_question_answers"; - private $t_quiz_attempt = "tutor_quiz_attempts"; - private $t_quiz_attempt_ans = "tutor_quiz_attempt_answers"; - public function quiz_with_settings(WP_REST_Request $request) { - $this->post_parent = $request->get_param('id'); + /** + * Quiz questions table name + * + * @var string The table name for quiz questions. + */ + private $t_quiz_question = 'tutor_quiz_questions'; + + /** + * Quiz question answers table name + * + * @var string The table name for quiz question answers. + */ + private $t_quiz_ques_ans = 'tutor_quiz_question_answers'; + + /** + * Quiz question answer options table name + * + * @var string The table name for quiz attempts. + */ + private $t_quiz_attempt = 'tutor_quiz_attempts'; + + /** + * Quiz attempt answers table name + * + * @var string The table name for quiz attempt answers. + */ + private $t_quiz_attempt_ans = 'tutor_quiz_attempt_answers'; + + /** + * Get quiz with settings. + * + * @since 1.7.1 + * + * @param WP_REST_Request $request REST request object. + * + * @return mixed + */ + public function quiz_with_settings( WP_REST_Request $request ) { + $this->post_parent = $request->get_param( 'id' ); global $wpdb; - $table = $wpdb->prefix."posts"; + $table = $wpdb->prefix . 'posts'; $quizs = $wpdb->get_results( - $wpdb->prepare("SELECT ID, post_title, post_content, post_name FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent) + $wpdb->prepare( + "SELECT + ID, + post_title, + post_content, + post_name + FROM $table + WHERE post_type = %s + AND post_parent = %d + ", + $this->post_type, + $this->post_parent + ) ); - $data = []; + $data = array(); - if (count($quizs)>0) { - foreach ($quizs as $quiz) { - $quiz->quiz_settings = get_post_meta($quiz->ID,'tutor_quiz_option',false); + if ( count( $quizs ) > 0 ) { + foreach ( $quizs as $quiz ) { + $quiz->quiz_settings = get_post_meta( $quiz->ID, 'tutor_quiz_option', false ); - array_push($data, $quiz); + array_push( $data, $quiz ); $response = array( - 'status_code'=> 'success', - 'message'=> __("Quiz retrieved successfully",'tutor'), - 'data'=> $data + 'status_code' => 'success', + 'message' => __( 'Quiz retrieved successfully', 'tutor' ), + 'data' => $data, ); } - return self::send($response); - } + return self::send( $response ); + } + $response = array( - 'status_code'=> 'not_found', - 'message'=> __("Quiz not found for given ID",'tutor'), - 'data'=> $data + 'status_code' => 'not_found', + 'message' => __( 'Quiz not found for given ID', 'tutor' ), + 'data' => $data, ); - return self::send($response); + return self::send( $response ); } - public function quiz_question_ans(WP_REST_Request $request) { + /** + * Get quiz question and answers. + * + * @param WP_REST_Request $request REST request object. + * + * @return mixed + */ + public function quiz_question_ans( WP_REST_Request $request ) { global $wpdb; - $this->post_parent = $request->get_param('id'); - + $this->post_parent = $request->get_param( 'id' ); - $q_t = $wpdb->prefix.$this->t_quiz_question;//question table + $q_t = $wpdb->prefix . $this->t_quiz_question; // question table - $q_a_t = $wpdb->prefix.$this->t_quiz_ques_ans;//question answer table + $q_a_t = $wpdb->prefix . $this->t_quiz_ques_ans; // question answer table $quizs = $wpdb->get_results( - $wpdb->prepare("SELECT question_id,question_title, question_description, question_type, question_mark, question_settings FROM $q_t WHERE quiz_id = %d", $this->post_parent) - ); - $data = []; - - if (count($quizs)>0) { + $wpdb->prepare( "SELECT + question_id, + question_title, + question_description, + question_type, + question_mark, + question_settings FROM $q_t + WHERE quiz_id = %d + ", + $this->post_parent + ) + ); + $data = array(); - //get question ans by question_id - foreach ($quizs as $quiz) { - //unserialized question settings - $quiz->question_settings = maybe_unserialize($quiz->question_settings); + if ( count( $quizs ) > 0 ) { + // get question ans by question_id + foreach ( $quizs as $quiz ) { + // un-serialized question settings. + $quiz->question_settings = maybe_unserialize( $quiz->question_settings ); - //question options with correct ans + // question options with correct ans. $options = $wpdb->get_results( - $wpdb->prepare("SELECT answer_title,is_correct FROM $q_a_t WHERE belongs_question_id = %d", $quiz->question_id) + $wpdb->prepare( "SELECT + answer_id, + answer_title, + is_correct FROM $q_a_t + WHERE belongs_question_id = %d + ", + $quiz->question_id + ) ); - //set question_answers as quiz property + // set question_answers as quiz property. $quiz->question_answers = $options; - array_push($data, $quiz); + array_push( $data, $quiz ); } $response = array( - 'status_code'=> 'success', - 'message'=> __('Question retrieved successfully','tutor'), - 'data'=> $data + 'status_code' => 'success', + 'message' => __( 'Question retrieved successfully', 'tutor' ), + 'data' => $data, ); - return self::send($response); + return self::send( $response ); } $response = array( - 'status_code'=> 'not_found', - 'message'=> __('Question not found for given ID','tutor'), - 'data'=> [] + 'status_code' => 'not_found', + 'message' => __( 'Question not found for given ID', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } - public function quiz_attempt_details(WP_REST_Request $request) { - $quiz_id = $request->get_param('id'); - + /** + * Get quiz attempt details. + * + * @since 1.7.1 + * + * @param WP_REST_Request $request REST request object. + * + * @return mixed + */ + public function quiz_attempt_details( WP_REST_Request $request ) { global $wpdb; - $quiz_attempt = $wpdb->prefix.$this->t_quiz_attempt; + + $quiz_id = $request->get_param( 'id' ); + + $quiz_attempt = $wpdb->prefix . $this->t_quiz_attempt; $attempts = $wpdb->get_results( - $wpdb->prepare("SELECT att.user_id,att.total_questions,att.total_answered_questions,att.total_marks,att.earned_marks,att.attempt_info,att.attempt_status,att.attempt_started_at,att.attempt_ended_at,att.is_manually_reviewed,att.manually_reviewed_at FROM $quiz_attempt att WHERE att.quiz_id = %d", $quiz_id) + $wpdb->prepare( + "SELECT + att.user_id, + att.total_questions, + att.total_answered_questions, + att.total_marks, + att.earned_marks, + att.attempt_info, + att.attempt_status, + att.attempt_started_at, + att.attempt_ended_at, + att.is_manually_reviewed, + att.manually_reviewed_at + FROM $quiz_attempt att + WHERE att.quiz_id = %d + ", + $quiz_id + ) ); - - if (count($attempts)>0) { - //unserialize each attempt info - foreach ($attempts as $key => $attempt) { - $attempt->attempt_info = maybe_unserialize($attempt->attempt_info); - //attach attempt ans - $answers = $this->get_quiz_attemp_ans($quiz_id); - - if($answers !==false) - { + + if ( count( $attempts ) > 0 ) { + // unserialize each attempt info. + foreach ( $attempts as $key => $attempt ) { + $attempt->attempt_info = maybe_unserialize( $attempt->attempt_info ); + // attach attempt ans. + $answers = $this->get_quiz_attempt_ans( $quiz_id ); + + if ( false !== $answers ) { $attempt->attempts_answer = $answers; + } else { + $attempt->attempts_answer = array(); } - else - { - $attempt->attempts_answer = []; - } - } $response = array( - 'status_code'=> 'success', - 'message'=> __('Quiz attempts retrieved successfully','tutor'), - 'data'=> $attempts + 'status_code' => 'success', + 'message' => __( 'Quiz attempts retrieved successfully', 'tutor' ), + 'data' => $attempts, ); - return self::send($response); + return self::send( $response ); } + $response = array( - 'status_code'=> 'not_found', - 'message'=> __('Quiz attempts not found for given ID','tutor'), - 'data'=> [] + 'status_code' => 'not_found', + 'message' => __( 'Quiz attempts not found for given ID', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } - /* - *required quiz_id - *return attempts ans - */ - protected function get_quiz_attemp_ans($quiz_id) { + /** + * Get quiz attempt answers. + * + * @since 1.7.1 + * + * @param int $quiz_id quiz id. + * + * @return mixed + */ + protected function get_quiz_attempt_ans( $quiz_id ) { global $wpdb; - $quiz_attempt_ans = $wpdb->prefix.$this->t_quiz_attempt_ans; - $quiz_question = $wpdb->prefix.$this->t_quiz_question; - //get attempt answers + $quiz_attempt_ans = $wpdb->prefix . $this->t_quiz_attempt_ans; + $quiz_question = $wpdb->prefix . $this->t_quiz_question; + + // get attempt answers. $answers = $wpdb->get_results( - $wpdb->prepare("SELECT q.question_title,att_ans.given_answer,att_ans.question_mark,att_ans.achieved_mark,att_ans.minus_mark,att_ans.is_correct FROM $quiz_attempt_ans as att_ans JOIN $quiz_question q ON q.question_id = att_ans.question_id WHERE att_ans.quiz_id = %d",$quiz_id) + $wpdb->prepare( + "SELECT + q.question_title, + att_ans.given_answer, + att_ans.question_mark, + att_ans.achieved_mark, + att_ans.minus_mark, + att_ans.is_correct FROM $quiz_attempt_ans as att_ans + JOIN $quiz_question q ON q.question_id = att_ans.question_id + WHERE att_ans.quiz_id = %d + ", + $quiz_id + ) ); - if (count($answers)>0) { - //unserialize each given answer - foreach ($answers as $key => $answer) { - $answer->given_answer = maybe_unserialize($answer->given_answer); + if ( count( $answers ) > 0 ) { + // unserialize each given answer. + foreach ( $answers as $key => $answer ) { + $answer->given_answer = maybe_unserialize( $answer->given_answer ); - if(is_numeric($answer->given_answer) || is_array($answer->given_answer)) - { - $ids = $answer->given_answer; - $ans_title = $this->answer_titles_by_id($ids); + if ( is_numeric( $answer->given_answer ) || is_array( $answer->given_answer ) ) { + $ids = $answer->given_answer; + $ans_title = $this->answer_titles_by_id( $ids ); $answer->given_answer = $ans_title; } } - return $answers; + return $answers; } return false; } - - /* - *require ids (1,2,3) - *return results containing answer title - */ - protected function answer_titles_by_id($id) { + + /** + * Get answer titles by id. + * + * @since 1.7.1 + * + * @param int $id answer id. + * + * @return mixed + */ + protected function answer_titles_by_id( $id ) { global $wpdb; - $table = $wpdb->prefix.$this->t_quiz_ques_ans; + $table = $wpdb->prefix . $this->t_quiz_ques_ans; - if(is_array($id)) { - $string = implode(',', $id); - $array=array_map('intval', explode(',', $string)); - $array = implode("','",$array); + if ( is_array( $id ) ) { + $array = QueryHelper::prepare_in_clause( $id ); $results = $wpdb->get_results( - "SELECT answer_title FROM $table WHERE answer_id IN ('".$array."')" - ); + "SELECT + answer_title + FROM $table + WHERE + answer_id IN ('" . $array . "')" + ); } else { $results = $wpdb->get_results( - "SELECT answer_title FROM $table WHERE answer_id = {$id}" + "SELECT + answer_title + FROM $table + WHERE answer_id = {$id}" ); } return $results; - } + } } diff --git a/restapi/REST_Rating.php b/restapi/REST_Rating.php index 1528e8e799..1aae3a438b 100644 --- a/restapi/REST_Rating.php +++ b/restapi/REST_Rating.php @@ -1,60 +1,84 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + use WP_REST_Request; -use WP_Comment_Query; -if(!defined( 'ABSPATH' )) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Rating + * + * @package Tutor + * @since 1.0.0 + */ class REST_Rating { + + /** + * Course response trait + * + * @since 1.7.1 + */ use REST_Response; + /** + * Course ID. + * + * @since 1.7.1 + * + * @var int $post_id The ID of the course. + */ private $post_id; - private $post_type = "tutor_course_rating"; - - /* - *require course id - *return comment/review with meta by course id and post type - */ - public function course_rating(WP_REST_Request $request) { - $this->post_id = $request->get_param('id'); - - global $wpdb; - $t_comment = $wpdb->prefix."comments"; - $t_commentmeta = $wpdb->prefix."commentmeta"; - - $ratings = $wpdb->get_results( - $wpdb->prepare( - "SELECT c.comment_author,c.comment_author_email,comment_date, - comment_content,comment_approved, cm.meta_value as rating - FROM $t_comment as c JOIN $t_commentmeta as cm ON cm.comment_id = c.comment_ID - WHERE c.comment_post_ID = %d AND c.comment_type = %s ", - $this->post_id,$this->post_type - )); - - if (count($ratings)>0) { + /** + * Post type for course ratings. + * + * @since 1.7.1 + * + * @var string $post_type The post type for course ratings. + */ + private $post_type = 'tutor_course_rating'; + + /** + * Retrieve course ratings via REST API. + * + * @since 1.7.1 + * + * @param WP_REST_Request $request The REST request object. + * + * @return mixed + */ + public function course_rating( WP_REST_Request $request ) { + $this->post_id = $request->get_param( 'id' ); + + $ratings = tutor_utils()->get_course_rating( $this->post_id ); + + if ( count( $ratings ) > 0 ) { $response = array( - 'status_code'=> 'success', - 'message'=> __('Course rating retrieved successfully','tutor'), - 'data'=> $ratings + 'status_code' => 'success', + 'message' => __( 'Course rating retrieved successfully', 'tutor' ), + 'data' => $ratings, ); - return self::send($response); + return self::send( $response ); } - + $response = array( - 'status_code'=> 'not_found', - 'message'=> __('Rating not found for given ID','tutor'), - 'data'=> [] + 'status_code' => 'not_found', + 'message' => __( 'Rating not found for given ID', 'tutor' ), + 'data' => array(), ); - return self::send($response); + return self::send( $response ); } } diff --git a/restapi/REST_Response.php b/restapi/REST_Response.php index 51ebc5da84..eea2b15eb9 100644 --- a/restapi/REST_Response.php +++ b/restapi/REST_Response.php @@ -1,21 +1,34 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + use WP_REST_Response; -if( ! defined('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} trait REST_Response { - /* - @send WP_REST_Response with - code, message along with data - */ - public static function send(array $response) { - return new WP_REST_Response($response); - } + + /** + * Send response + * + * @since 1.7.1 + * + * @param array $response The response data. + * + * @return WP_REST_Response + */ + public static function send( array $response ) { + $response = new WP_REST_Response( $response ); + return apply_filters( 'tutor_rest_response', $response ); + } } diff --git a/restapi/REST_Topic.php b/restapi/REST_Topic.php index 5e9e021c08..b45f7e6391 100644 --- a/restapi/REST_Topic.php +++ b/restapi/REST_Topic.php @@ -1,52 +1,80 @@ + * @link https://themeum.com + * @since 1.7.1 + */ namespace TUTOR; + use WP_REST_Request; -use WP_Query; -if(!defined('ABSPATH')) -exit; +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +/** + * Class REST_Topic + * + * @package Tutor + * + * @since 1.7.1 + */ class REST_Topic { use REST_Response; + /** + * Post parent ID. + * + * @var int $post_parent The ID of the post parent. + */ private $post_parent; - private $post_type = "topics"; - /* - *require rest request - *return topic by course id - */ - public function course_topic(WP_REST_Request $request) { - $this->post_parent = $request->get_param('id'); + /** + * Post type. + * + * @var string $post_type The post type for topics. + */ + private $post_type = 'topics'; + + /** + * Retrieve topics by course ID via REST API. + * + * @param WP_REST_Request $request The REST request object. + * + * @since 1.7.1 + * + * @return mixed + */ + public function course_topic( WP_REST_Request $request ) { + $this->post_parent = $request->get_param( 'id' ); global $wpdb; - $table = $wpdb->prefix."posts"; + $table = $wpdb->prefix . 'posts'; $result = $wpdb->get_results( - $wpdb->prepare("SELECT ID, post_title, post_content, post_name FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent) + $wpdb->prepare( "SELECT ID, post_title, post_content, post_name FROM $table WHERE post_type = %s AND post_parent = %d", $this->post_type, $this->post_parent ) ); - if (count($result)>0) { + if ( count( $result ) > 0 ) { $response = array( - 'status_code'=> "get_topic", - "message"=> __('Topic retrieved successfully','tutor'), - 'data'=> $result - ); - - return self::send($response); + 'status_code' => 'get_topic', + 'message' => __( 'Topic retrieved successfully', 'tutor' ), + 'data' => $result, + ); + + return self::send( $response ); } $response = array( - 'status_code'=> "not_found", - "message"=> __('Topic not found for given ID','tutor'), - 'data'=> [] - ); - - return self::send($response); + 'status_code' => 'not_found', + 'message' => __( 'Topic not found for given ID', 'tutor' ), + 'data' => array(), + ); + + return self::send( $response ); } } diff --git a/restapi/RestAuth.php b/restapi/RestAuth.php index b3cb2eadda..2df5f59c80 100644 --- a/restapi/RestAuth.php +++ b/restapi/RestAuth.php @@ -153,7 +153,7 @@ public static function update_api_permission() { $info = QueryHelper::get_row( $wpdb->usermeta, array( 'umeta_id' => $meta_id ), 'umeta_id' ); $meta_value = json_decode( $info->meta_value ); - $meta_value->permission = $permission; + $meta_value->permission = $permission; $meta_value->description = $description; // Update user meta. diff --git a/templates/dashboard/purchase_history.php b/templates/dashboard/purchase_history.php index 11768ad28e..35972dad96 100644 --- a/templates/dashboard/purchase_history.php +++ b/templates/dashboard/purchase_history.php @@ -69,6 +69,12 @@ 'filter_calendar' => true, ); +?> +
+ +
+path . 'views/elements/purchase-history-filter.php'; tutor_load_template_from_custom_path( $filter_period_calendar_template, $filter_period_calendar ); diff --git a/templates/dashboard/question-answer.php b/templates/dashboard/question-answer.php index 541c7bc6ef..fab9339442 100644 --- a/templates/dashboard/question-answer.php +++ b/templates/dashboard/question-answer.php @@ -1,6 +1,6 @@ get_qa_question( $question_id ); + $user_id = get_current_user_id(); + + if ( $question && ! Q_and_A::has_qna_access( $user_id, $question->comment_post_ID ) ) { + tutor_utils()->tutor_empty_state( tutor_utils()->error_message() ); + return; + } -if ( isset( $_GET['question_id'] ) ) { tutor_load_template_from_custom_path( tutor()->path . '/views/qna/qna-single.php', array( - 'question_id' => Input::get( 'question_id' ), + 'question_id' => $question_id, 'context' => 'frontend-dashboard-qna-single', ) ); diff --git a/templates/dashboard/settings/reset-password.php b/templates/dashboard/settings/reset-password.php index 7fef834f5b..3af77cc1d8 100644 --- a/templates/dashboard/settings/reset-password.php +++ b/templates/dashboard/settings/reset-password.php @@ -11,6 +11,8 @@ ?> +
+
-

+
diff --git a/templates/dashboard/settings/withdraw-settings.php b/templates/dashboard/settings/withdraw-settings.php index f723e6692e..8eee7ad92f 100644 --- a/templates/dashboard/settings/withdraw-settings.php +++ b/templates/dashboard/settings/withdraw-settings.php @@ -17,6 +17,9 @@ 3 => 'tutor-col-12 tutor-col-lg-4', ); ?> + +
+
-
+
diff --git a/templates/instructor-setting.php b/templates/instructor-setting.php deleted file mode 100644 index 67a2ba7d88..0000000000 --- a/templates/instructor-setting.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @link https://themeum.com - * @since 1.0.0 - */ - -if ( ! defined( 'ABSPATH' ) ) { - exit; -} -?> - -
-
- -
-
-
- url . 'assets/images/instructor-layout/'; - - foreach ( $templates as $template ) { - $img = $url_base . $template . '.jpg'; - $selected_template = tutor_utils()->get_option( 'instructor_list_layout' ); - ?> - - -
-

- -

-
-
- diff --git a/templates/single/assignment/content.php b/templates/single/assignment/content.php index a6358c0ab5..85f54ed15c 100644 --- a/templates/single/assignment/content.php +++ b/templates/single/assignment/content.php @@ -165,11 +165,10 @@ function tutor_assignment_convert_seconds( $seconds ) { $remaining_time && false == $is_submitted ) ) : ?>
diff --git a/tutor.php b/tutor.php index ef3c2203e8..d18722fd30 100644 --- a/tutor.php +++ b/tutor.php @@ -4,7 +4,7 @@ * Plugin URI: https://www.themeum.com/product/tutor-lms/ * Description: Tutor is a complete solution for creating a Learning Management System in WordPress way. It can help you to create small to large scale online education site very conveniently. Power features like report, certificate, course preview, private file sharing make Tutor a robust plugin for any educational institutes. * Author: Themeum - * Version: 2.6.0 + * Version: 2.6.1 * Author URI: https://themeum.com * Requires PHP: 7.4 * Requires at least: 5.3 @@ -24,7 +24,7 @@ /** * Defined the tutor main file */ -define( 'TUTOR_VERSION', '2.6.0' ); +define( 'TUTOR_VERSION', '2.6.1' ); define( 'TUTOR_FILE', __FILE__ ); /** diff --git a/v2-library/_src/scss/main.rtl.scss b/v2-library/_src/scss/main.rtl.scss index 6eb7eb1573..cfecb20164 100644 --- a/v2-library/_src/scss/main.rtl.scss +++ b/v2-library/_src/scss/main.rtl.scss @@ -1,9 +1,3 @@ -* { - // margin: 0; - // padding: 0; - box-sizing: border-box; -} - $is-rtl: true !default; @import './structure/structure.scss'; diff --git a/v2-library/_src/scss/main.scss b/v2-library/_src/scss/main.scss index 02bd678d66..7e256bd04f 100644 --- a/v2-library/_src/scss/main.scss +++ b/v2-library/_src/scss/main.scss @@ -1,9 +1,3 @@ -* { - // margin: 0; - // padding: 0; - box-sizing: border-box; -} - $is-rtl: false !default; @import './structure/structure.scss'; diff --git a/v2-library/_src/scss/tutor-main.scss b/v2-library/_src/scss/tutor-main.scss deleted file mode 100644 index 385b025711..0000000000 --- a/v2-library/_src/scss/tutor-main.scss +++ /dev/null @@ -1,14 +0,0 @@ -// * { -// margin: 0; -// padding: 0; -// } -[class*='tutor-screen-'] { - #wpbody-content { - box-sizing: border-box; - } -} - -$is-rtl: false !default; - -@import './structure/structure.scss'; -@import './main_contents.scss'; diff --git a/views/options/options_generator.php b/views/options/options_generator.php deleted file mode 100644 index cd0dfb82c2..0000000000 --- a/views/options/options_generator.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @link https://themeum.com - * @since 2.0.0 - */ - -?> -
-

- -
- - - options_attr(); - - if ( is_array( $options_attr ) && count( $options_attr ) ) { - $first_item = null; - ?> -
    - array_get( 'tab_page', $_GET ) ); - foreach ( $options_attr as $key => $option_group ) { - if ( empty( $option_group ) ) { - continue; - } - if ( ! $first_item ) { - $first_item = $key; - } - $current_page = ( $first_item === $key ); - $current_class = $current_page ? 'current' : ''; - if ( $tab_page ) { - $current_class = $tab_page === $key ? 'current' : ''; - } - - $nav_url = add_query_arg( array( 'tab_page' => $key ) ); - echo '
  • - ' . - esc_attr( $option_group['label'] ) . - ' -
  • '; - } - ?> -
- - $option_group ) { - if ( empty( $option_group ) ) { - continue; - } - $current_page = ( $first_item === $key ); - if ( $tab_page ) { - $current_page = $tab_page === $key ? 'current' : ''; - } - - ?> - -
- - $field_group ) { - ?> - -
-

-
- - count( $field_group['fields'] ) ) { - foreach ( $field_group['fields'] as $field_key => $field ) { - $field['field_key'] = $field_key; - $this->generate_field( $field ); - } - } - do_action( 'tutor_options_' . esc_attr( $key ) . '_' . esc_attr( $fgKey ) . '_after' ); - } - } - - do_action( 'tutor_options_after_' . esc_attr( $key ) ); - - ?> -
- - -

- -

-
-
diff --git a/views/qna/qna-single.php b/views/qna/qna-single.php index 3deecc1624..2a3bcb4f97 100644 --- a/views/qna/qna-single.php +++ b/views/qna/qna-single.php @@ -132,7 +132,10 @@
- comment_content ) ); ?> + comment_content ); + echo tutor()->has_pro ? wp_kses_post( $content ) : esc_textarea( $content ); + ?>
comment_parent ) : ?>