<commit_before>var CodeOceanEditor = {
  ACE_FILES_PATH: '/assets/ace/',
  ADEQUATE_PERCENTAGE: 50,
  ALT_1_KEY_CODE: 161,
  ALT_2_KEY_CODE: 8220,
  ALT_3_KEY_CODE: 182,
  ALT_4_KEY_CODE: 162,
  ALT_R_KEY_CODE: 174,
  ALT_S_KEY_CODE: 8218,
  ALT_T_KEY_CODE: 8224,
  FILENAME_URL_PLACEHOLDER: '{filename}',
  SUCCESSFULL_PERCENTAGE: 90,
  THEME: 'ace/theme/textmate',
  REMEMBER_TAB: false,
  AUTOSAVE_INTERVAL: 15 * 1000,
  REQUEST_FOR_COMMENTS_DELAY: 3 * 60 * 1000,
  NONE: 0,
  WEBSOCKET: 1,
  SERVER_SEND_EVENT: 2,

  editors: [],
  editor_for_file: new Map(),
  regex_for_language: new Map(),
  tracepositions_regex: undefined,

  active_file: undefined,
  active_frame: undefined,
  running: false,
  qa_api: undefined,
  output_mode_is_streaming: true,
  runmode: this.NONE,

  numMessages: 0,
  prompt: $('#prompt'),
  lastCopyText: null,

  autosaveTimer: null,
  autosaveLabel: $("#autosave-label span"),

  ENTER_KEY_CODE: 13,

  QaApiOutputBuffer: {'stdout': '', 'stderr': ''},
  flowrResultHtml: '<div class="panel panel-default"><div id="{{headingId}}" role="tab" class="panel-heading"><h4 class="panel-title"><a data-toggle="collapse" data-parent="#flowrHint" href="#{{collapseId}}" aria-expanded="true" aria-controls="{{collapseId}}"></a></h4></div><div id="{{collapseId}}" role="tabpanel" aria-labelledby="{{headingId}}" class="panel-collapse collapse"><div class="panel-body"></div></div></div>',


  configureEditors: function () {
    _.each(['modePath', 'themePath', 'workerPath'], function (attribute) {
      ace.config.set(attribute, this.ACE_FILES_PATH);
    }.bind(this));
  },

  confirmDestroy: function (event) {
    event.preventDefault();
    if (confirm($(this).data('message-confirm'))) {
      this.destroyFile();
    }
  },


  confirmReset: function (event) {
    event.preventDefault();
    if (confirm($('#start-over').data('message-confirm'))) {
      this.resetCode();
    }
  },

  fileActionsAvailable: function () {
    return this.isActiveFileRenderable() || this.isActiveFileRunnable() || this.isActiveFileStoppable() || this.isActiveFileTestable();
  },

  findOrCreateOutputElement: function (index) {
    if ($('#output-' + index).isPresent()) {
      return $('#output-' + index);
    } else {
      var element = $('<pre>').attr('id', 'output-' + index);
      $('#output').append(element);
      return element;
    }
  },

  findOrCreateRenderElement: function (index) {
    if ($('#render-' + index).isPresent()) {
      return $('#render-' + index);
    } else {
      var element = $('<div>').attr('id', 'render-' + index);
      $('#render').append(element);
      return element;
    }
  },

  getPanelClass: function (result) {
    if (result.stderr && !result.score) {
      return 'panel-danger';
    } else if (result.score < 1) {
      return 'panel-warning';
    } else {
      return 'panel-success';
    }
  },

  showOutput: function(event) {
    event.preventDefault();
    this.showTab(1);
    $('#output').scrollTo($(this).attr('href'));
  },

  renderProgressBar: function(score, maximum_score) {
    var percentage = score / maximum_score * 100;
    var progress_bar = $('#score .progress-bar');
    progress_bar.removeClass().addClass(this.getProgressBarClass(percentage));
    progress_bar.attr({
      'aria-valuemax': maximum_score,
      'aria-valuemin': 0,
      'aria-valuenow': score
    });
    progress_bar.css('width', percentage + '%');
  },

  showFirstFile: function() {
    var frame = $('.frame[data-role="main_file"]').isPresent() ? $('.frame[data-role="main_file"]') : $('.frame').first();
    var file_id = frame.find('.editor').data('file-id');
    this.setActiveFile(frame.data('filename'), file_id);
    $('#files').jstree().select_node(file_id);
    this.showFrame(frame);
    this.toggleButtonStates();
  },

  showFrame: function(frame) {
    this.active_frame = frame;
    $('.frame').hide();
    frame.show();
  },

  getProgressBarClass: function (percentage) {
    if (percentage < this.ADEQUATE_PERCENTAGE) {
      return 'progress-bar progress-bar-striped progress-bar-danger';
    } else if (percentage < this.SUCCESSFULL_PERCENTAGE) {
      return 'progress-bar progress-bar-striped progress-bar-warning';
    } else {
      return 'progress-bar progress-bar-striped progress-bar-success';
    }
  },

  handleKeyPress: function (event) {
    if (event.which === this.ALT_1_KEY_CODE) {
      this.showWorkspaceTab(event);
    } else if (event.which === this.ALT_2_KEY_CODE) {
      this.showTab(1);
    } else if (event.which === this.ALT_3_KEY_CODE) {
      this.showTab(2);
    } else if (event.which === this.ALT_R_KEY_CODE) {
      $('#run').trigger('click');
    } else if (event.which === this.ALT_S_KEY_CODE) {
      $('#assess').trigger('click');
    } else if (event.which === this.ALT_T_KEY_CODE) {
      $('#test').trigger('click');
    } else {
      return;
    }
    event.preventDefault();
  },

  handleCopyEvent: function (text) {
    this.lastCopyText = text;
  },

  handlePasteEvent: function (pasteObject) {
    var same = (this.lastCopyText === pasteObject.text);

    // if the text is not copied from within the editor (from any file), send an event to lanalytics
    if (!same) {
      this.publishCodeOceanEvent("codeocean_editor_paste", {
        text: pasteObject.text,
        exercise: $('#editor').data('exercise-id'),
        file_id: "1"

      });
    }
  },

  hideSpinner: function () {
    $('button i.fa').show();
    $('button i.fa-spin').hide();
  },

  resetSaveTimer: function () {
    clearTimeout(this.autosaveTimer);
    this.autosaveTimer = setTimeout(this.autosave.bind(this), this.AUTOSAVE_INTERVAL);
  },

  autosave: function () {
    var date = new Date();
    this.autosaveLabel.parent().css("visibility", "visible");
    this.autosaveLabel.text(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds());
    this.autosaveLabel.text(date.toLocaleTimeString());
    this.autosaveTimer = null;
    this.createSubmission($('#autosave'), null);
  },

  initializeEditors: function () {
    $('.editor').each(function (index, element) {
      var editor = ace.edit(element);

      if (this.qa_api) {
        editor.getSession().on("change", function (deltaObject) {
          this.qa_api.executeCommand('syncEditor', [this.active_file, deltaObject]);
        }.bind(this));
      }

      var document = editor.getSession().getDocument();
      // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added
      var file_id = $(element).data('file-id');
      var content = $('.editor-content[data-file-id=' + file_id + ']');
      this.setActiveFile($(element).parent().data('filename'), file_id);

      document.insertLines(0, content.text().split(/\n/));
      // remove last (empty) that is there by default line
      document.removeLines(document.getLength() - 1, document.getLength() - 1);
      editor.setReadOnly($(element).data('read-only') !== undefined);
      editor.setShowPrintMargin(false);
      editor.setTheme(this.THEME);
      editor.commands.bindKey("ctrl+alt+0", null);
      this.editors.push(editor);
      this.editor_for_file.set($(element).parent().data('filename'), editor);
      var session = editor.getSession();
      session.setMode($(element).data('mode'));
      session.setTabSize($(element).data('indent-size'));
      session.setUseSoftTabs(true);
      session.setUseWrapMode(true);

      // set regex for parsing error traces based on the mode of the main file.
      if ($(element).parent().data('role') == "main_file") {
        this.tracepositions_regex = this.regex_for_language.get($(element).data('mode'));
      }

      var file_id = $(element).data('id');

      /*
       * Register event handlers
       */

      // editor itself
      editor.on("paste", this.handlePasteEvent.bind(this));
      editor.on("copy", this.handleCopyEvent.bind(this));

      // listener for autosave
      session.on("change", function (deltaObject) {
        this.resetSaveTimer();
      }.bind(this));
    }.bind(this));
  },

  initializeEventHandlers: function () {
    $(document).on('click', '#results a', this.showOutput.bind(this));
    $(document).on('keypress', this.handleKeyPress.bind(this));
    $('a[data-toggle="tab"]').on('show.bs.tab', this.storeTab.bind(this));
    this.initializeFileTreeButtons();
    this.initializeWorkflowButtons();
    this.initializeWorkspaceButtons();
    this.initializeRequestForComments()
  },

  initializeFileTree: function () {
    $('#files').jstree($('#files').data('entries'));
    $('#files').on('click', 'li.jstree-leaf', function () {
      active_file = {
        filename: $(this).text(),
        id: parseInt($(this).attr('id'))
      };
      var frame = $('[data-file-id="' + active_file.id + '"]').parent();
      this.showFrame(frame);
      this.toggleButtonStates();
    });
  },

  initializeFileTreeButtons: function () {
    $('#create-file').on('click', this.showFileDialog.bind(this));
    $('#destroy-file').on('click', this.confirmDestroy.bind(this));
    $('#download').on('click', this.downloadCode.bind(this));
    $('#request-for-comments').on('click', this.requestComments.bind(this));
  },

  initializeRegexes: function () {
    this.regex_for_language.set("ace/mode/python", /File "(.+?)", line (\d+)/g);
    this.regex_for_language.set("ace/mode/java", /(.*\.java):(\d+):/g);
  },

  initializeTooltips: function () {
    $('[data-tooltip]').tooltip();
  },

  initializeWorkflowButtons: function () {
    $('#start').on('click', this.showWorkspaceTab.bind(this));
    $('#submit').on('click', this.submitCode.bind(this));
  },

  initializeWorkspaceButtons: function () {
    $('#assess').on('click', this.scoreCode.bind(this));
    $('#dropdown-render, #render').on('click', this.renderCode.bind(this));
    $('#dropdown-run, #run').on('click', this.runCode.bind(this));
    $('#dropdown-stop, #stop').on('click', this.stopCode.bind(this));
    $('#dropdown-test, #test').on('click', this.testCode.bind(this));
    $('#save').on('click', this.saveCode.bind(this));
    $('#start-over').on('click', this.confirmReset.bind(this));
  },

  initializeRequestForComments: function () {
    var button = $('.requestCommentsButton');
    button.hide();
    button.on('click', function () {
      $('#comment-modal').modal('show');
    });

    $('#askForCommentsButton').on('click', this.requestComments);

    setTimeout(function () {
      button.fadeIn();
    }, this.REQUEST_FOR_COMMENTS_DELAY);
  },

  isActiveFileRenderable: function () {
    return 'renderable' in this.active_frame.data();
  },

  isActiveFileRunnable: function () {
    return this.isActiveFileExecutable() && ['main_file', 'user_defined_file'].includes(this.active_frame.data('role'));
  },

  isActiveFileStoppable: function () {
    return this.isActiveFileRunnable() && this.running;
  },

  isActiveFileSubmission: function () {
    return ['Submission'].includes(this.active_frame.data('contextType'));
  },

  isActiveFileTestable: function () {
    return this.isActiveFileExecutable() && ['teacher_defined_test', 'user_defined_test'].includes(this.active_frame.data('role'));
  },

  isBrowserSupported: function () {
    //  websockets is used for run, score and test
    return Modernizr.websockets;
  },

  populatePanel: function (panel, result, index) {
    panel.removeClass('panel-default').addClass(this.getPanelClass(result));
    panel.find('.panel-title .filename').text(result.filename);
    panel.find('.panel-title .number').text(index + 1);
    panel.find('.row .col-sm-9').eq(0).find('.number').eq(0).text(result.passed);
    panel.find('.row .col-sm-9').eq(0).find('.number').eq(1).text(result.count);
    panel.find('.row .col-sm-9').eq(1).find('.number').eq(0).text((result.score * result.weight).toFixed(2));
    panel.find('.row .col-sm-9').eq(1).find('.number').eq(1).text(result.weight);
    panel.find('.row .col-sm-9').eq(2).text(result.message);
    if (result.error_messages) panel.find('.row .col-sm-9').eq(3).text(result.error_messages.join(', '));
    panel.find('.row .col-sm-9').eq(4).find('a').attr('href', '#output-' + index);
  },

  publishCodeOceanEvent: function (eventName, contextData) {
    var payload = {
      user: {
        type: 'User',
        uuid: $('#editor').data('user-id')
      },
      verb: {
        type: eventName
      },
      resource: {
        type: 'page',
        uuid: document.location.href
      },
      timestamp: new Date().toISOString(),
      with_result: {},
      in_context: contextData
    };

    $.ajax("https://open.hpi.de/lanalytics/log", {
      type: 'POST',
      cache: false,
      dataType: 'JSON',
      data: payload,
      success: {},
      error: {}
    })
  },

  sendError: function (message, submission_id) {
    this.showSpinner($('#render'));
    var jqxhr = this.ajax({
      data: {
        error: {
          message: message,
          submission_id: submission_id
        }
      },
      url: $('#editor').data('errors-url')
    });
    jqxhr.always(this.hideSpinner);
    jqxhr.success(this.renderHint);
  },

  toggleButtonStates: function () {
    $('#destroy-file').prop('disabled', this.active_frame.data('role') !== 'user_defined_file');
    $('#dropdown-render').toggleClass('disabled', !this.isActiveFileRenderable());
    $('#dropdown-run').toggleClass('disabled', !this.isActiveFileRunnable() || this.running);
    $('#dropdown-stop').toggleClass('disabled', !this.isActiveFileStoppable());
    $('#dropdown-test').toggleClass('disabled', !this.isActiveFileTestable());
    $('#dummy').toggle(!this.fileActionsAvailable());
    $('#editor-buttons .dropdown-toggle').toggle(this.fileActionsAvailable());
    $('#render').toggle(this.isActiveFileRenderable());
    $('#run').toggle(this.isActiveFileRunnable() && !this.running);
    $('#stop').toggle(this.isActiveFileStoppable());
    $('#test').toggle(this.isActiveFileTestable());
  },

  jumpToSourceLine: function (event) {
    var file = $(event.target).data('file');
    var line = $(event.target).data('line');

    this.showWorkspaceTab(null);
    // set active file ?!?!

    var frame = $('div.frame[data-filename="' + file + '"]');
    this.showFrame(frame);

    var editor = this.editor_for_file.get(file);
    editor.gotoLine(line, 0);

  },

  augmentStacktraceInOutput: function () {
    if (this.tracepositions_regex) {
      var element = $('#output>pre');
      var text = element.text();
      element.on("click", "a", this.jumpToSourceLine.bind(this));

      var matches;

      while (matches = this.tracepositions_regex.exec(text)) {
        var frame = $('div.frame[data-filename="' + matches[1] + '"]')

        if (frame.length > 0) {
          element.html(text.replace(matches[0], "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>"));
        }
      }
    }
  },

  storeTab: function (event) {
    localStorage.tab = $(event.target).parent().index();
  },

  resetOutputTab: function () {
    this.clearOutput();
    $('#hint').fadeOut();
    $('#flowrHint').fadeOut();
    this.showTab(1);
  },

  isActiveFileBinary: function () {
    return 'binary' in this.active_frame.data();
  },

  isActiveFileExecutable: function () {
    return 'executable' in this.active_frame.data();
  },

  setActiveFile: function (filename, fileId) {
    this.active_file = {
      filename: filename,
      id: fileId
    };
  },

  showRequestedTab: function() {
    if(this.REMEMBER_TAB){
      var regexp = /tab=(\d+)/;
      if (regexp.test(window.location.search)) {
        var index = regexp.exec(window.location.search)[1] - 1;
      } else {
        var index = this.localStorage.tab;
      }
    } else {
      // else start with first tab.
      var index = 0;
    }
    this.showTab(index);
  },

  showSpinner: function(initiator) {
    $(initiator).find('i.fa').hide();
    $(initiator).find('i.fa-spin').show();
  },

  showStatus: function(output) {
    if (output.status === 'timeout') {
      this.showTimeoutMessage();
    } else if (output.status === 'container_depleted') {
      this.showContainerDepletedMessage();
    } else if (output.stderr) {
      $.flash.danger({
        icon: ['fa', 'fa-bug'],
        text: $('#run').data('message-failure')
      });
    }
  },

  showContainerDepletedMessage: function() {
    $.flash.danger({
      icon: ['fa', 'fa-clock-o'],
      text: $('#editor').data('message-depleted')
    });
  },

  showTab: function(index) {
    $('a[data-toggle="tab"]').eq(index || 0).tab('show');
  },

  showTimeoutMessage: function() {
    $.flash.info({
      icon: ['fa', 'fa-clock-o'],
      text: $('#editor').data('message-timeout')
    });
  },

  showWebsocketError: function() {
    $.flash.danger({
      text: $('#flash').data('message-failure')
    });
  },

  showWorkspaceTab: function(event) {
    if(event){
      event.preventDefault();
    }
    this.showTab(0);
  },

  showFileDialog: function(event) {
    event.preventDefault();
    this.createSubmission('#create-file', null, function(response) {
      $('#code_ocean_file_context_id').val(response.id);
      $('#modal-file').modal('show');
    });
  },

  initializeEverything: function() {
    this.initializeRegexes();
    this.initializeCodePilot();
    $('.score, #development-environment').show();
    this.configureEditors();
    this.initializeEditors();
    this.initializeEventHandlers();
    this.initializeFileTree();
    this.initializeTooltips();
    this.initPrompt();
    this.renderScore();
    this.showFirstFile();
    this.showRequestedTab();

    $(window).on("beforeunload", function() {
      if(this.autosaveTimer != null){
        this.autosave();
      }
    }.bind(this));
  }
};<commit_msg>Fixed autosavelabel.<commit_after>var CodeOceanEditor = {
  ACE_FILES_PATH: '/assets/ace/',
  ADEQUATE_PERCENTAGE: 50,
  ALT_1_KEY_CODE: 161,
  ALT_2_KEY_CODE: 8220,
  ALT_3_KEY_CODE: 182,
  ALT_4_KEY_CODE: 162,
  ALT_R_KEY_CODE: 174,
  ALT_S_KEY_CODE: 8218,
  ALT_T_KEY_CODE: 8224,
  FILENAME_URL_PLACEHOLDER: '{filename}',
  SUCCESSFULL_PERCENTAGE: 90,
  THEME: 'ace/theme/textmate',
  REMEMBER_TAB: false,
  AUTOSAVE_INTERVAL: 15 * 1000,
  REQUEST_FOR_COMMENTS_DELAY: 3 * 60 * 1000,
  NONE: 0,
  WEBSOCKET: 1,
  SERVER_SEND_EVENT: 2,

  editors: [],
  editor_for_file: new Map(),
  regex_for_language: new Map(),
  tracepositions_regex: undefined,

  active_file: undefined,
  active_frame: undefined,
  running: false,
  qa_api: undefined,
  output_mode_is_streaming: true,
  runmode: this.NONE,

  numMessages: 0,
  prompt: $('#prompt'),
  lastCopyText: null,

  autosaveTimer: null,
  autosaveLabel: "#autosave-label span",

  ENTER_KEY_CODE: 13,

  QaApiOutputBuffer: {'stdout': '', 'stderr': ''},
  flowrResultHtml: '<div class="panel panel-default"><div id="{{headingId}}" role="tab" class="panel-heading"><h4 class="panel-title"><a data-toggle="collapse" data-parent="#flowrHint" href="#{{collapseId}}" aria-expanded="true" aria-controls="{{collapseId}}"></a></h4></div><div id="{{collapseId}}" role="tabpanel" aria-labelledby="{{headingId}}" class="panel-collapse collapse"><div class="panel-body"></div></div></div>',


  configureEditors: function () {
    _.each(['modePath', 'themePath', 'workerPath'], function (attribute) {
      ace.config.set(attribute, this.ACE_FILES_PATH);
    }.bind(this));
  },

  confirmDestroy: function (event) {
    event.preventDefault();
    if (confirm($(this).data('message-confirm'))) {
      this.destroyFile();
    }
  },


  confirmReset: function (event) {
    event.preventDefault();
    if (confirm($('#start-over').data('message-confirm'))) {
      this.resetCode();
    }
  },

  fileActionsAvailable: function () {
    return this.isActiveFileRenderable() || this.isActiveFileRunnable() || this.isActiveFileStoppable() || this.isActiveFileTestable();
  },

  findOrCreateOutputElement: function (index) {
    if ($('#output-' + index).isPresent()) {
      return $('#output-' + index);
    } else {
      var element = $('<pre>').attr('id', 'output-' + index);
      $('#output').append(element);
      return element;
    }
  },

  findOrCreateRenderElement: function (index) {
    if ($('#render-' + index).isPresent()) {
      return $('#render-' + index);
    } else {
      var element = $('<div>').attr('id', 'render-' + index);
      $('#render').append(element);
      return element;
    }
  },

  getPanelClass: function (result) {
    if (result.stderr && !result.score) {
      return 'panel-danger';
    } else if (result.score < 1) {
      return 'panel-warning';
    } else {
      return 'panel-success';
    }
  },

  showOutput: function(event) {
    event.preventDefault();
    this.showTab(0);
    this.showOutputBar();
    $('#output').scrollTo($(this).attr('href'));
  },

  renderProgressBar: function(score, maximum_score) {
    var percentage = score / maximum_score * 100;
    var progress_bar = $('#score .progress-bar');
    progress_bar.removeClass().addClass(this.getProgressBarClass(percentage));
    progress_bar.attr({
      'aria-valuemax': maximum_score,
      'aria-valuemin': 0,
      'aria-valuenow': score
    });
    progress_bar.css('width', percentage + '%');
  },

  showFirstFile: function() {
    var frame = $('.frame[data-role="main_file"]').isPresent() ? $('.frame[data-role="main_file"]') : $('.frame').first();
    var file_id = frame.find('.editor').data('file-id');
    this.setActiveFile(frame.data('filename'), file_id);
    $('#files').jstree().select_node(file_id);
    this.showFrame(frame);
    this.toggleButtonStates();
  },

  showFrame: function(frame) {
    this.active_frame = frame;
    $('.frame').hide();
    frame.show();
  },

  getProgressBarClass: function (percentage) {
    if (percentage < this.ADEQUATE_PERCENTAGE) {
      return 'progress-bar progress-bar-striped progress-bar-danger';
    } else if (percentage < this.SUCCESSFULL_PERCENTAGE) {
      return 'progress-bar progress-bar-striped progress-bar-warning';
    } else {
      return 'progress-bar progress-bar-striped progress-bar-success';
    }
  },

  handleKeyPress: function (event) {
    if (event.which === this.ALT_1_KEY_CODE) {
      this.showWorkspaceTab(event);
    } else if (event.which === this.ALT_3_KEY_CODE) {
      this.showTab(1);
    } else if (event.which === this.ALT_R_KEY_CODE) {
      $('#run').trigger('click');
    } else if (event.which === this.ALT_S_KEY_CODE) {
      $('#assess').trigger('click');
    } else if (event.which === this.ALT_T_KEY_CODE) {
      $('#test').trigger('click');
    } else {
      return;
    }
    event.preventDefault();
  },

  handleCopyEvent: function (text) {
    this.lastCopyText = text;
  },

  handlePasteEvent: function (pasteObject) {
    var same = (this.lastCopyText === pasteObject.text);

    // if the text is not copied from within the editor (from any file), send an event to lanalytics
    if (!same) {
      this.publishCodeOceanEvent("codeocean_editor_paste", {
        text: pasteObject.text,
        exercise: $('#editor').data('exercise-id'),
        file_id: "1"

      });
    }
  },

  hideSpinner: function () {
    $('button i.fa').show();
    $('button i.fa-spin').hide();
  },

  resetSaveTimer: function () {
    clearTimeout(this.autosaveTimer);
    this.autosaveTimer = setTimeout(this.autosave.bind(this), this.AUTOSAVE_INTERVAL);
  },

  autosave: function () {
    var date = new Date();
    var autosaveLabel = $(this.autosaveLabel);
    autosaveLabel.parent().css("visibility", "visible");
    autosaveLabel.text(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds());
    autosaveLabel.text(date.toLocaleTimeString());
    this.autosaveTimer = null;
    this.createSubmission($('#autosave'), null);
  },

  initializeEditors: function () {
    $('.editor').each(function (index, element) {
      var editor = ace.edit(element);

      if (this.qa_api) {
        editor.getSession().on("change", function (deltaObject) {
          this.qa_api.executeCommand('syncEditor', [this.active_file, deltaObject]);
        }.bind(this));
      }

      var document = editor.getSession().getDocument();
      // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added
      var file_id = $(element).data('file-id');
      var content = $('.editor-content[data-file-id=' + file_id + ']');
      this.setActiveFile($(element).parent().data('filename'), file_id);

      document.insertLines(0, content.text().split(/\n/));
      // remove last (empty) that is there by default line
      document.removeLines(document.getLength() - 1, document.getLength() - 1);
      editor.setReadOnly($(element).data('read-only') !== undefined);
      editor.setShowPrintMargin(false);
      editor.setTheme(this.THEME);
      editor.commands.bindKey("ctrl+alt+0", null);
      this.editors.push(editor);
      this.editor_for_file.set($(element).parent().data('filename'), editor);
      var session = editor.getSession();
      session.setMode($(element).data('mode'));
      session.setTabSize($(element).data('indent-size'));
      session.setUseSoftTabs(true);
      session.setUseWrapMode(true);

      // set regex for parsing error traces based on the mode of the main file.
      if ($(element).parent().data('role') == "main_file") {
        this.tracepositions_regex = this.regex_for_language.get($(element).data('mode'));
      }

      var file_id = $(element).data('id');

      /*
       * Register event handlers
       */

      // editor itself
      editor.on("paste", this.handlePasteEvent.bind(this));
      editor.on("copy", this.handleCopyEvent.bind(this));

      // listener for autosave
      session.on("change", function (deltaObject) {
        this.resetSaveTimer();
      }.bind(this));
    }.bind(this));
  },

  initializeEventHandlers: function () {
    $(document).on('click', '#results a', this.showOutput.bind(this));
    $(document).on('keypress', this.handleKeyPress.bind(this));
    $('a[data-toggle="tab"]').on('show.bs.tab', this.storeTab.bind(this));
    this.initializeFileTreeButtons();
    this.initializeWorkflowButtons();
    this.initializeWorkspaceButtons();
    this.initializeRequestForComments()
  },

  initializeFileTree: function () {
    $('#files').jstree($('#files').data('entries'));
    $('#files').on('click', 'li.jstree-leaf', function () {
      active_file = {
        filename: $(this).text(),
        id: parseInt($(this).attr('id'))
      };
      var frame = $('[data-file-id="' + active_file.id + '"]').parent();
      this.showFrame(frame);
      this.toggleButtonStates();
    }.bind(this));
  },

  initializeFileTreeButtons: function () {
    $('#create-file').on('click', this.showFileDialog.bind(this));
    $('#create-file-collapsed').on('click', this.showFileDialog.bind(this));
    $('#destroy-file').on('click', this.confirmDestroy.bind(this));
    $('#destroy-file-collapsed').on('click', this.confirmDestroy.bind(this));
    $('#download').on('click', this.downloadCode.bind(this));
    $('#download-collapsed').on('click', this.downloadCode.bind(this));
    $('#request-for-comments').on('click', this.requestComments.bind(this));
  },

  initializeSideBarCollapse: function() {
    $('#sidebar-collapsed').addClass('hidden');
    $('#sidebar-collapse-collapsed').on('click',this.handleSideBarToggle.bind(this));
    $('#sidebar-collapse').on('click',this.handleSideBarToggle.bind(this))
  },

  handleSideBarToggle: function() {
    $('#sidebar').toggleClass('sidebar-col').toggleClass('sidebar-col-collapsed');/**
    $('#frames').toggleClass('editor-col')
    if (main_area.hasClass('col-sm-10')) {
      main_area.removeClass('col-sm-10').addClass('col-sm-11');
    } else if (main_area.hasClass('col-sm-11')) {
      main_area.removeClass('col-sm-11').addClass('col-sm-10');
    }*/
    $('#sidebar-collapsed').toggleClass('hidden');
    $('#sidebar-uncollapsed').toggleClass('hidden');
  },

  initializeRegexes: function () {
    this.regex_for_language.set("ace/mode/python", /File "(.+?)", line (\d+)/g);
    this.regex_for_language.set("ace/mode/java", /(.*\.java):(\d+):/g);
  },

  initializeTooltips: function () {
    $('[data-tooltip]').tooltip();
  },

  initializeWorkflowButtons: function () {
    $('#start').on('click', this.showWorkspaceTab.bind(this));
    $('#submit').on('click', this.submitCode.bind(this));
  },

  initializeWorkspaceButtons: function () {
    $('#assess').on('click', this.scoreCode.bind(this));
    $('#dropdown-render, #render').on('click', this.renderCode.bind(this));
    $('#dropdown-run, #run').on('click', this.runCode.bind(this));
    $('#dropdown-stop, #stop').on('click', this.stopCode.bind(this));
    $('#dropdown-test, #test').on('click', this.testCode.bind(this));
    $('#save').on('click', this.saveCode.bind(this));
    $('#start-over').on('click', this.confirmReset.bind(this));
  },

  initializeRequestForComments: function () {
    var button = $('.requestCommentsButton');
    button.hide();
    button.on('click', function () {
      $('#comment-modal').modal('show');
    });

    $('#askForCommentsButton').on('click', this.requestComments);

    setTimeout(function () {
      button.fadeIn();
    }, this.REQUEST_FOR_COMMENTS_DELAY);
  },

  isActiveFileRenderable: function () {
    return 'renderable' in this.active_frame.data();
  },

  isActiveFileRunnable: function () {
    return this.isActiveFileExecutable() && ['main_file', 'user_defined_file'].includes(this.active_frame.data('role'));
  },

  isActiveFileStoppable: function () {
    return this.isActiveFileRunnable() && this.running;
  },

  isActiveFileSubmission: function () {
    return ['Submission'].includes(this.active_frame.data('contextType'));
  },

  isActiveFileTestable: function () {
    return this.isActiveFileExecutable() && ['teacher_defined_test', 'user_defined_test'].includes(this.active_frame.data('role'));
  },

  isBrowserSupported: function () {
    //  websockets is used for run, score and test
    return Modernizr.websockets;
  },

  populatePanel: function (panel, result, index) {
    panel.removeClass('panel-default').addClass(this.getPanelClass(result));
    panel.find('.panel-title .filename').text(result.filename);
    panel.find('.panel-title .number').text(index + 1);
    panel.find('.row .col-sm-9').eq(0).find('.number').eq(0).text(result.passed);
    panel.find('.row .col-sm-9').eq(0).find('.number').eq(1).text(result.count);
    panel.find('.row .col-sm-9').eq(1).find('.number').eq(0).text((result.score * result.weight).toFixed(2));
    panel.find('.row .col-sm-9').eq(1).find('.number').eq(1).text(result.weight);
    panel.find('.row .col-sm-9').eq(2).text(result.message);
    if (result.error_messages) panel.find('.row .col-sm-9').eq(3).text(result.error_messages.join(', '));
    panel.find('.row .col-sm-9').eq(4).find('a').attr('href', '#output-' + index);
  },

  publishCodeOceanEvent: function (eventName, contextData) {
    var payload = {
      user: {
        type: 'User',
        uuid: $('#editor').data('user-id')
      },
      verb: {
        type: eventName
      },
      resource: {
        type: 'page',
        uuid: document.location.href
      },
      timestamp: new Date().toISOString(),
      with_result: {},
      in_context: contextData
    };

    $.ajax("https://open.hpi.de/lanalytics/log", {
      type: 'POST',
      cache: false,
      dataType: 'JSON',
      data: payload,
      success: {},
      error: {}
    })
  },

  sendError: function (message, submission_id) {
    this.showSpinner($('#render'));
    var jqxhr = this.ajax({
      data: {
        error: {
          message: message,
          submission_id: submission_id
        }
      },
      url: $('#editor').data('errors-url')
    });
    jqxhr.always(this.hideSpinner);
    jqxhr.success(this.renderHint);
  },

  toggleButtonStates: function () {
    $('#destroy-file').prop('disabled', this.active_frame.data('role') !== 'user_defined_file');
    $('#dropdown-render').toggleClass('disabled', !this.isActiveFileRenderable());
    $('#dropdown-run').toggleClass('disabled', !this.isActiveFileRunnable() || this.running);
    $('#dropdown-stop').toggleClass('disabled', !this.isActiveFileStoppable());
    $('#dropdown-test').toggleClass('disabled', !this.isActiveFileTestable());
    $('#dummy').toggle(!this.fileActionsAvailable());
    $('#editor-buttons .dropdown-toggle').toggle(this.fileActionsAvailable());
    $('#render').toggle(this.isActiveFileRenderable());
    $('#run').toggle(this.isActiveFileRunnable() && !this.running);
    $('#stop').toggle(this.isActiveFileStoppable());
    $('#test').toggle(this.isActiveFileTestable());
  },

  jumpToSourceLine: function (event) {
    var file = $(event.target).data('file');
    var line = $(event.target).data('line');

    this.showWorkspaceTab(null);
    // set active file ?!?!

    var frame = $('div.frame[data-filename="' + file + '"]');
    this.showFrame(frame);

    var editor = this.editor_for_file.get(file);
    editor.gotoLine(line, 0);

  },

  augmentStacktraceInOutput: function () {
    if (this.tracepositions_regex) {
      var element = $('#output>pre');
      var text = element.text();
      element.on("click", "a", this.jumpToSourceLine.bind(this));

      var matches;

      while (matches = this.tracepositions_regex.exec(text)) {
        var frame = $('div.frame[data-filename="' + matches[1] + '"]')

        if (frame.length > 0) {
          element.html(text.replace(matches[0], "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>"));
        }
      }
    }
  },

  storeTab: function (event) {
    localStorage.tab = $(event.target).parent().index();
  },

  resetOutputTab: function () {
    this.clearOutput();
    $('#hint').fadeOut();
    $('#flowrHint').fadeOut();
    this.showTab(0);
    this.showOutputBar();
  },

  isActiveFileBinary: function () {
    return 'binary' in this.active_frame.data();
  },

  isActiveFileExecutable: function () {
    return 'executable' in this.active_frame.data();
  },

  setActiveFile: function (filename, fileId) {
    this.active_file = {
      filename: filename,
      id: fileId
    };
  },

  showRequestedTab: function() {
    if(this.REMEMBER_TAB){
      var regexp = /tab=(\d+)/;
      if (regexp.test(window.location.search)) {
        var index = regexp.exec(window.location.search)[1] - 1;
      } else {
        var index = this.localStorage.tab;
      }
    } else {
      // else start with first tab.
      var index = 0;
    }
    this.showTab(index);
  },

  showSpinner: function(initiator) {
    $(initiator).find('i.fa').hide();
    $(initiator).find('i.fa-spin').show();
  },

  showStatus: function(output) {
    if (output.status === 'timeout') {
      this.showTimeoutMessage();
    } else if (output.status === 'container_depleted') {
      this.showContainerDepletedMessage();
    } else if (output.stderr) {
      $.flash.danger({
        icon: ['fa', 'fa-bug'],
        text: $('#run').data('message-failure')
      });
    }
  },

  showContainerDepletedMessage: function() {
    $.flash.danger({
      icon: ['fa', 'fa-clock-o'],
      text: $('#editor').data('message-depleted')
    });
  },

  showTab: function(index) {
    $('a[data-toggle="tab"]').eq(index || 0).tab('show');
  },

  showTimeoutMessage: function() {
    $.flash.info({
      icon: ['fa', 'fa-clock-o'],
      text: $('#editor').data('message-timeout')
    });
  },

  showWebsocketError: function() {
    $.flash.danger({
      text: $('#flash').data('message-failure')
    });
  },

  showWorkspaceTab: function(event) {
    if(event){
      event.preventDefault();
    }
    this.showTab(0);
  },

  showFileDialog: function(event) {
    event.preventDefault();
    this.createSubmission('#create-file', null, function(response) {
      $('#code_ocean_file_context_id').val(response.id);
      $('#modal-file').modal('show');
    });
  },

  initializeOutputBarToggle: function() {
    $('#toggle-sidebar-output').on('click',this.hideOutputBar.bind(this));
    $('#toggle-sidebar-output-collapsed').on('click',this.showOutputBar.bind(this));
  },

  showOutputBar: function() {
    if ($('#sidebar').hasClass('sidebar-col')) {
      this.handleSideBarToggle();
    }
    $('#output_sidebar_collapsed').addClass('hidden');
    $('#output_sidebar_uncollapsed').removeClass('hidden');
    $('#output_sidebar').removeClass('output-col-collapsed').addClass('output-col');
  },

  hideOutputBar: function() {
    $('#output_sidebar_collapsed').removeClass('hidden');
    $('#output_sidebar_uncollapsed').addClass('hidden');
    $('#output_sidebar').removeClass('output-col').addClass('output-col-collapsed');
  },

  initializeEverything: function() {
    this.initializeRegexes();
    this.initializeCodePilot();
    $('.score, #development-environment').show();
    this.configureEditors();
    this.initializeEditors();
    this.initializeEventHandlers();
    this.initializeFileTree();
    this.initializeSideBarCollapse();
    this.initializeOutputBarToggle();
    this.initializeTooltips();
    this.initPrompt();
    this.renderScore();
    this.showFirstFile();
    this.showRequestedTab();

    $(window).on("beforeunload", function() {
      if(this.autosaveTimer != null){
        this.autosave();
      }
    }.bind(this));
  }
};
{'fraction_non_alphanumeric': 0.19271376259588913, 'fraction_numerical': 0.005719936920321814, 'mean_word_length': 3.5180533751962324, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2129014', 'n_tokens_mistral': 12224, 'n_tokens_neox': 11910, 'n_words': 1859}