diff --git a/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx b/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx
index 719687f45c14ade3a21a723e8492a1eec3200026..075851d0350c2cffd136d0f4e4d5f578e599d16c 100644
--- a/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx
+++ b/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx
@@ -20,6 +20,7 @@ import {setHideErrorOutputLines, setHideExpectedOutputLines} from '../../../../s
 import Logger from '../../../../helpers/logger'
 import {RunnableCustomProjectTestFrontendExclusive} from '../../../../types/customProjects'
 import {RunnableExerciseTestFrontendExclusive} from '../../../../types/exerciseEditor'
+import {copyToClipboard} from '../../../../helpers/clipboard';
 
 //const css = require('./styles.styl');
 
@@ -84,16 +85,113 @@ class ConsolePanelView extends React.Component<Props, any> {
     }
   }
 
-  render(): JSX.Element {
+  copyTestResultInputToClipboard(): void {
+    let protocolItemsCopy = this.getProtocolItemsSortedCopy()
 
-    if (!this.props.test && !this.props.protocolItems) {
-      //if we clear the console view we set both to null...
-      //Logger.error('console panel view can only use test or protocolItems property')
-      return null
+    const inputString = protocolItemsCopy
+      .filter(p => p.type === TestProtocolType.isInput)
+      .map(p => p.content)
+      .join('\n')
+      .toString()
+
+    copyToClipboard(inputString)
+  }
+  copyTestResultOutputToClipboard(): void {
+    //the current visible state is copied
+    //e.g. if debug output and if expected output
+    let outputString = ""
+
+    //TODO compare test result handling might be incorrect...
+
+    //we need to get the test protocol items sorted because some e.g. expected return code not guaranteed to be the first item
+    let protocolItemsCopy = this.getProtocolItemsSortedCopy()
+      .filter(p => p.type === TestProtocolType.isOutput
+        || p.type === TestProtocolType.isError
+        || p.type === TestProtocolType.isExpectedOutput
+        || p.type === TestProtocolType.isCompareTestResultOk
+        || p.type === TestProtocolType.isCompareTestResultFile1NotFound
+        || p.type === TestProtocolType.isCompareTestResultFile2NotFound
+        || p.type === TestProtocolType.isCompareTestResultExpected
+        || p.type === TestProtocolType.isCompareTestResultActual
+        || p.type === TestProtocolType.isCompareTestResultFile2EOF
+      )
+
+    for (let i = 0; i < protocolItemsCopy.length; i++) {
+      let protocolItem = protocolItemsCopy[i]
+
+      if (this.props.hideExpectedOutputLines && (
+        protocolItem.type === TestProtocolType.isExpectedOutput
+        || protocolItem.type === TestProtocolType.isCompareTestResultExpected
+        )
+      ) {
+        continue
+      }
+
+      if (this.props.hideErrorOutputLines && (
+        protocolItem.type === TestProtocolType.isError
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile1NotFound
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile2NotFound
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile2EOF
+        )
+      ) {
+        continue
+      }
+
+      outputString += protocolItem.content + '\n'
     }
 
-    //don't add this in the mapStateToProps else we already concat a new instance thus the shallow compare from redux is false
-    //because we already create a new entry (with the same values but other identity)
+    copyToClipboard(outputString)
+  }
+  copyTestResultInputAndOutputToClipboard(): void {
+    //the current visible state is copied
+    //e.g. if debug output and if expected output
+    let outputString = ""
+
+    //we need to get the test protocol items sorted because some e.g. expected return code not guaranteed to be the first item
+    let protocolItemsCopy = this.getProtocolItemsSortedCopy()
+      .filter(p => p.type === TestProtocolType.isInput
+        || p.type === TestProtocolType.isOutput
+        || p.type === TestProtocolType.isError
+        || p.type === TestProtocolType.isExpectedOutput
+        || p.type === TestProtocolType.isCompareTestResultOk
+        || p.type === TestProtocolType.isCompareTestResultFile1NotFound
+        || p.type === TestProtocolType.isCompareTestResultFile2NotFound
+        || p.type === TestProtocolType.isCompareTestResultExpected
+        || p.type === TestProtocolType.isCompareTestResultActual
+        || p.type === TestProtocolType.isCompareTestResultFile2EOF
+      )
+
+    for (let i = 0; i < protocolItemsCopy.length; i++) {
+      let protocolItem = protocolItemsCopy[i]
+
+      if (this.props.hideExpectedOutputLines && (
+        protocolItem.type === TestProtocolType.isExpectedOutput
+        || protocolItem.type === TestProtocolType.isCompareTestResultExpected
+      )
+      ) {
+        continue
+      }
+
+      if (this.props.hideErrorOutputLines && (
+        protocolItem.type === TestProtocolType.isError
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile1NotFound
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile2NotFound
+        || protocolItem.type === TestProtocolType.isCompareTestResultFile2EOF
+      )
+      ) {
+        continue
+      }
+
+      outputString += protocolItem.content + '\n'
+    }
+
+    copyToClipboard(outputString)
+
+  }
+
+  //copy to not mutate...
+  getProtocolItemsSortedCopy(): ReadonlyArray<TestProtocolItem> {
+
     const allTestTypes = this.props.testTypes.concat([{
       id: -1,
       displayName: 'Just Run Program',
@@ -114,18 +212,10 @@ class ConsolePanelView extends React.Component<Props, any> {
     }
 
     if (!protocolItems) {
-        return null
+      return []
     }
 
-    //only allow if we have expected output lines
-    //maybe this is too strange because you cannot toggle the item and then one might forget to uncheck it...
-    const canHideExpectedOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isExpectedOutput)
-    const canHideErrorOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isError)
-
-
-    //maybe not sort here but search for the items?? but we could have more than one...
-    //performance could be better
-
+    //make a copy because we sort/mutate
     //make sure exit code is always 1.
     //expected always 2.
     //args 3.
@@ -152,6 +242,40 @@ class ConsolePanelView extends React.Component<Props, any> {
       return 0
 
     })
+    return protocolItemsSorted as ReadonlyArray<TestProtocolItem>
+  }
+
+  render(): JSX.Element {
+
+    if (!this.props.test && !this.props.protocolItems) {
+      //if we clear the console view we set both to null...
+      //Logger.error('console panel view can only use test or protocolItems property')
+      return null
+    }
+
+    //don't add this in the mapStateToProps else we already concat a new instance thus the shallow compare from redux is false
+    //because we already create a new entry (with the same values but other identity)
+    const allTestTypes = this.props.testTypes.concat([{
+      id: -1,
+      displayName: 'Just Run Program',
+      internalName: KnownInternalTestTypes.justRunTest
+    }])
+
+    //only allow if we have expected output lines
+    //maybe this is too strange because you cannot toggle the item and then one might forget to uncheck it...
+    const canHideExpectedOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isExpectedOutput)
+    const canHideErrorOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isError)
+
+
+    //maybe not sort here but search for the items?? but we could have more than one...
+    //performance could be better
+
+    //make sure exit code is always 1.
+    //expected always 2.
+    //args 3.
+    //because this looks better
+    // tslint:disable-next-line
+    let protocolItemsSorted = this.getProtocolItemsSortedCopy()
 
     // tslint:disable-next-line
     let expectedExitCode: number | null = null
@@ -178,12 +302,13 @@ class ConsolePanelView extends React.Component<Props, any> {
         <List divided relaxed>
           {
             //only display header if we have some normal output... (or just don't display headers if all items are errors)
-            (protocolItems && protocolItems.some(p => p.type !== TestProtocolType.isError)) &&
+            (protocolItemsSorted && protocolItemsSorted.some(p => p.type !== TestProtocolType.isError)) &&
             <div className="console-input-output-line-header">
               <div className="input-part">
                 <div className="flexed-well-spaced">
 
                   <div className="flexed">
+                    <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultInputToClipboard()} />
                     <div className="mar-right-half">
                       {
                         getI18n(this.props.langId, 'Input')
@@ -206,6 +331,9 @@ class ConsolePanelView extends React.Component<Props, any> {
 
                 <div className="absolute-centered flexed">
 
+                  <div className="mar-right-half">
+                    <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultInputAndOutputToClipboard()} />
+                  </div>
 
                   {
                     canHideErrorOutputLines && this.props.displayFilterConsoleItemsOptions &&
@@ -280,6 +408,7 @@ class ConsolePanelView extends React.Component<Props, any> {
                   <Icon className="not-important-colored" name="chevron right"/>
 
                   <div className="flexed">
+                    <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultOutputToClipboard()} />
                     <div className="mar-right-half">
                       {
                         getI18n(this.props.langId, 'Output')
diff --git a/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx b/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx
index 24e57f428f247f7c6e704891a4236e333faf904a..377627e4c99451f41c7d154ca8afb3b308fc0641 100644
--- a/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx
+++ b/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx
@@ -357,7 +357,7 @@ class exerciseEditorSite extends React.Component<Props & RouteComponentProps<Mat
                 return {
                   id: p.id,
                   originalName: p.displayName,
-                  sizeInBytes: p.content.length,
+                  sizeInBytes: p.content?.length,
                   mimeType: p.mimeType
                 }
               })}
diff --git a/src/constants.ts b/src/constants.ts
index d2f1caf8ace7e8c607120c07941d849e96721168..21e188e577e4e5d303ae596e67f03569c771c51e 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -13,7 +13,7 @@ import Logger from './helpers/logger'
  * y - breaking changes / new features
  * z - fixes, small changes
  */
-export const versionString = '2.16.0'
+export const versionString = '2.17.0'
 
 
 export const supportMail = 'yapex@informatik.uni-halle.de'
diff --git a/src/types/testResults.ts b/src/types/testResults.ts
index 7e40d24fbecfe03c642c5e386d2f7672027a8eca..dd11ba6de7e25780db98ceddb7f9469d13a78f92 100644
--- a/src/types/testResults.ts
+++ b/src/types/testResults.ts
@@ -313,6 +313,9 @@ export enum TestProtocolType {
   isCompareTestResultFile1NotFound,
   isCompareTestResultFile2NotFound,
   isCompareTestResultExpected,
+  /**
+   * actual file content (line)
+   */
   isCompareTestResultActual,
   isCompareTestResultFile2EOF,