<commit_before>import { observable, computed, action } from 'mobx';
import studentDataSorter from './student-data-sorter';
import WindowSize from '../../models/window-size';
import WeightsUX from './weights-ux';
import UiSettings from 'shared/model/ui-settings';
import Courses from '../../models/courses-map';
import {
  find, first, pick, pickBy, mapValues,
  groupBy, flow, map, partial, uniq, some, keys, isEmpty, isNil,
  filter, sortBy, maxBy, minBy, orderBy,
} from 'lodash';
import S from '../../helpers/string';

const NOT_AVAILABLE_AVERAGE = 'n/a';
const PENDING_AVERAGE = '---';

const scoreKeyToType = (key) => (key.match(/(course_average|homework|reading)/)[0]);

export default class GradeBookUX {

  windowSize = new WindowSize();

  @observable isNameInverted = true;
  @observable showAverageInfoModal = false;
  @observable isReady = false;
  @observable currentPeriodScores;
  @observable props = {}

  @observable sortIndex;
  @observable rowSort = { key: this.isNameInverted ? 'last_name' : 'first_name', asc: true, dataType: 'score' };
  @observable weights = new WeightsUX(this);

  @observable searchingMatcher = null;

  @UiSettings.decorate('gb.sap') displayScoresAsPercent = false;
  @UiSettings.decorate('gp.cbt') arrangeColumnsByType = false;
  @UiSettings.decorate('gp.cbp') arrangeColumnsByPoints = false;
  @UiSettings.decorate('gp.sds') showDroppedStudents = false;

  constructor(props) {
    this.initialize(props);
    this.props = props;
  }

  async initialize({
    courseId,
    course = Courses.get(courseId),
  }) {
    this.course = course;
    this.currentPeriodScores = find(this.course.scores.periods.array, s => s.period_id === first(this.course.periods.active).id);
    await this.course.scores.fetch();
    this.isReady = true;
  }

  @action.bound onSelectPeriod(period) {
    this.currentPeriodScores = find(this.course.scores.periods.array, s => s.period_id === period.id);
  }

  @computed get pageTitle() {
    return this.isTeacher ? 'Student Scores' : 'Scores';
  }

  @action.bound onSearchStudentChange({ target: { value } }) {
    this.searchingMatcher = value ? RegExp(value, 'i') : null;
  }

  @computed get isTeacher() {
    return this.course.currentRole.isTeacher;
  }

  @computed get scores() {
    return this.course.scores;
  }

  @action.bound changeRowSortingOrder(key, dataType) {
    this.rowSort.asc = this.rowSort.key === key ? (!this.rowSort.asc) : false;
    this.rowSort.key = key;
    this.rowSort.dataType = dataType;
  }

  sortForColumn(sortKey, dataType) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType) ? this.rowSort : false;
  }

  isRowSortedBy({ sortKey, dataType }) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType);
  }

  @computed get studentRowSorter() {
    return studentDataSorter.rows({ sort: this.rowSort, displayAs: this.displayAs });
  }

  @computed get columnSorter() {
    const sorter = studentDataSorter.columns;
    if (this.arrangeColumnsByType) {
      if (this.arrangeColumnsByPoints) {
        return sorter.type_and_points;
      }
      return sorter.type;
    } else if (this.arrangeColumnsByPoints) {
      return sorter.points;
    }
    return sorter.date;
  }

  @computed get headings() {
    return orderBy(this.currentPeriodScores.data_headings, this.columnSorter.headings, 'desc');
  }

  studentTasks(student) {
    return orderBy(student.data, this.columnSorter.tasks, 'desc');
  }


  @computed get period() {
    return this.scores.periods.get(this.coursePeriod.id);
  }

  @computed get students() {
    const students = sortBy(
      filter(this.currentPeriodScores.students, s => !s.is_dropped),
      this.studentRowSorter,
    );
    if (!this.rowSort.asc) {
      students.reverse();
    }
    if (this.showDroppedStudents) {
      students.push(...this.droppedStudents);
    }
    if (!this.searchingMatcher) {
      return students;
    }
    return filter(students, s => s.name.match(this.searchingMatcher));
  }

  @computed get droppedStudents() {
    return sortBy(
      filter(this.currentPeriodScores.students, 'is_dropped'),
      this.studentRowSorter,
    );<commit_msg>checking for empty array in currentPeriodScores<commit_after>import { observable, computed, action } from 'mobx';
import studentDataSorter from './student-data-sorter';
import WindowSize from '../../models/window-size';
import WeightsUX from './weights-ux';
import UiSettings from 'shared/model/ui-settings';
import Courses from '../../models/courses-map';
import {
  find, first, pick, pickBy, mapValues,
  groupBy, flow, map, partial, uniq, some, keys, isEmpty, isNil,
  filter, sortBy, maxBy, minBy, orderBy,
} from 'lodash';
import S from '../../helpers/string';

const NOT_AVAILABLE_AVERAGE = 'n/a';
const PENDING_AVERAGE = '---';

const scoreKeyToType = (key) => (key.match(/(course_average|homework|reading)/)[0]);

export default class GradeBookUX {

  windowSize = new WindowSize();

  @observable isNameInverted = true;
  @observable showAverageInfoModal = false;
  @observable isReady = false;
  @observable currentPeriodScores;
  @observable props = {}

  @observable sortIndex;
  @observable rowSort = { key: this.isNameInverted ? 'last_name' : 'first_name', asc: true, dataType: 'score' };
  @observable weights = new WeightsUX(this);

  @observable searchingMatcher = null;

  @UiSettings.decorate('gb.sap') displayScoresAsPercent = false;
  @UiSettings.decorate('gp.cbt') arrangeColumnsByType = false;
  @UiSettings.decorate('gp.cbp') arrangeColumnsByPoints = false;
  @UiSettings.decorate('gp.sds') showDroppedStudents = false;

  constructor(props) {
    this.initialize(props);
    this.props = props;
  }

  async initialize({
    courseId,
    course = Courses.get(courseId),
  }) {
    this.course = course;
    this.currentPeriodScores = find(this.course.scores.periods.array, s => s.period_id === first(this.course.periods.active).id);
    await this.course.scores.fetch();
    this.isReady = true;
  }

  @action.bound onSelectPeriod(period) {
    this.currentPeriodScores = find(this.course.scores.periods.array, s => s.period_id === period.id);
  }

  @computed get pageTitle() {
    return this.isTeacher ? 'Student Scores' : 'Scores';
  }

  @action.bound onSearchStudentChange({ target: { value } }) {
    this.searchingMatcher = value ? RegExp(value, 'i') : null;
  }

  @computed get isTeacher() {
    return this.course.currentRole.isTeacher;
  }

  @computed get scores() {
    return this.course.scores;
  }

  @action.bound changeRowSortingOrder(key, dataType) {
    this.rowSort.asc = this.rowSort.key === key ? (!this.rowSort.asc) : false;
    this.rowSort.key = key;
    this.rowSort.dataType = dataType;
  }

  sortForColumn(sortKey, dataType) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType) ? this.rowSort : false;
  }

  isRowSortedBy({ sortKey, dataType }) {
    return (this.rowSort.key === sortKey) && (this.rowSort.dataType === dataType);
  }

  @computed get studentRowSorter() {
    return studentDataSorter.rows({ sort: this.rowSort, displayAs: this.displayAs });
  }

  @computed get columnSorter() {
    const sorter = studentDataSorter.columns;
    if (this.arrangeColumnsByType) {
      if (this.arrangeColumnsByPoints) {
        return sorter.type_and_points;
      }
      return sorter.type;
    } else if (this.arrangeColumnsByPoints) {
      return sorter.points;
    }
    return sorter.date;
  }

  @computed get headings() {
    return this.currentPeriodScores
      ? orderBy(this.currentPeriodScores.data_headings, this.columnSorter.headings, 'desc')
      : [];
  }

  studentTasks(student) {
    return orderBy(student.data, this.columnSorter.tasks, 'desc');
  }


  @computed get period() {
    return this.scores.periods.get(this.coursePeriod.id);
  }

  @computed get students() {
    if(!this.currentPeriodScores) return [];
    
    const students = sortBy(
      filter(this.currentPeriodScores.students, s => !s.is_dropped),
      this.studentRowSorter,
    );
    if (!this.rowSort.asc) {
      students.reverse();
    }
    if (this.showDroppedStudents) {
      students.push(...this.droppedStudents);
    }
    if (!this.searchingMatcher) {
      return students;
    }
    return filter(students, s => s.name.match(this.searchingMatcher));
  }

  @computed get droppedStudents() {
    return sortBy(
      filter(this.currentPeriodScores.students, 'is_dropped'),
      this.studentRowSorter,
    );
{'fraction_non_alphanumeric': 0.13848327837965144, 'fraction_numerical': 0.00023551577955723034, 'mean_word_length': 3.6974557522123894, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1060110', 'n_tokens_mistral': 2875, 'n_tokens_neox': 2788, 'n_words': 556}