$(document).ready(function() {
  const common = window.common;
  const { Observable } = window.Rx;
  const { challengeName, challengeType, challengeTypes } = common;

  common.init.forEach(function(init) {
    init($);
  });

  // only run if editor present
  if (common.editor.getValue) {
    const code$ = common.editorKeyUp$
      .debounce(750)
      .map(() => common.editor.getValue())
      .distinctUntilChanged()
      .shareReplay();

    // update storage
    code$.subscribe(
        code => {
          common.codeStorage.updateStorage(common.challengeName, code);
          common.codeUri.querify(code);
        },
        err => console.error(err)
      );

    code$
      // only run for HTML
      .filter(() => common.challengeType === challengeTypes.HTML)
      .flatMap(code => {
        if (
          common.hasJs(code)
        ) {
          return common.detectUnsafeCode$(code)
            .flatMap(code => common.detectLoops$(code))
            .flatMap(
              ({ err }) => err ? Observable.throw(err) : Observable.just(code)
            );
        }
        return Observable.just(code);
      })
      .flatMap(code => common.updatePreview$(code))
      .catch(err => Observable.just({ err }))
      .subscribe(
        ({ err }) => {
          if (err) {
            return console.error(err);
          }
        },
        err => console.error(err)
      );

  }

  common.resetBtn$
    .doOnNext(() => {
      common.editor.setValue(common.replaceSafeTags(common.seed));
    })
    .flatMap(() => {
      return common.executeChallenge$();
    })
    .subscribe(
      ({ output, original }) => {
        common.codeStorage.updateStorage(challengeName, original);
        common.updateOutputDisplay('' + output);
      },
      ({ err }) => {
        if (err.stack) {
          console.error(err);
        }
        common.updateOutputDisplay('' + err);
      }
    );

  Observable.merge(
    common.editorExecute$,
    common.submitBtn$
  )
    .flatMap(() => {
      common.appendToOutputDisplay('\n// testing challenge...');
      return common.executeChallenge$()
        .map(({ tests, ...rest }) => {
          const solved = tests.every(test => !test.err);
          return { ...rest, tests, solved };
        })
        .catch(err => Observable.just(err));
    })
    .subscribe(
      ({ err, solved, output, tests }) => {
        if (err) {
          console.error(err);
          if (common.challengeType === common.challengeTypes.HTML) {
            return common.updatePreview$(`
              <h1>${err}</h1>
            `).subscribe(() => {});
          }
          return common.updateOutputDisplay('' + err);
        }
        common.updateOutputDisplay(output);
        common.displayTestResults(tests);
        if (solved) {
          common.showCompletion();
        }
      },
      ({ err }) => {
        console.error(err);
        common.updateOutputDisplay('' + err);
      }
    );

  // initial challenge run to populate tests
  if (challengeType === challengeTypes.HTML) {
    var $preview = $('#preview');
    return Observable.fromCallback($preview.ready, $preview)()
      .delay(500)
      .flatMap(() => common.executeChallenge$())
      .catch(err => Observable.just({ err }))
      .subscribe(
        ({ err, tests }) => {
          if (err) {
            console.error(err);
            if (common.challengeType === common.challengeTypes.HTML) {
              return common.updatePreview$(`
                <h1>${err}</h1>
              `).subscribe(() => {});
            }
            return common.updateOutputDisplay('' + err);
          }
          common.displayTestResults(tests);
        },
        ({ err }) => {
          console.error(err);
        }
      );
  }

  if (
    challengeType === challengeTypes.BONFIRE ||
    challengeType === challengeTypes.JS
  ) {
    Observable.just({})
      .delay(500)
      .flatMap(() => common.executeChallenge$())
      .catch(err => Observable.just({ err }))
      .subscribe(
        ({ err, original, tests }) => {
          if (err) {
            console.error(err);
            return common.updateOutputDisplay('' + err);
          }
          common.codeStorage.updateStorage(challengeName, original);
          common.displayTestResults(tests);
        },
        (err) => {
          console.error(err);
          common.updateOutputDisplay('' + err);
        }
      );
  }
});

@@ -1062,24 +1062,134 @@
            )
+%0A            .flatMap(code =%3E common.updatePreview$(code))%0A            .catch(err =%3E Observable.just(%7B err %7D))
 ;%0A        %7D%0A
@@ -1228,19 +1228,13 @@
 ode)
-;
 %0A    
-  %7D)%0A
     
@@ -1279,32 +1279,36 @@
 w$(code))%0A      
+ 
+   
 .catch(err =%3E Ob
@@ -1322,32 +1322,42 @@
 e.just(%7B err %7D))
+;%0A      %7D)
 %0A      .subscrib
@@ -1415,23 +1415,16 @@
         
-return 
 console.
@@ -1427,32 +1427,141 @@
 ole.error(err);%0A
+            return common.updatePreview$(%60%0A              %3Ch1%3E$%7Berr%7D%3C/h1%3E%0A            %60).subscribe(() =%3E %7B%7D);%0A
           %7D%0A    
@@ -1791,16 +1791,64 @@
 lenge$()
+%0A        .catch(err =%3E Observable.just(%7B err %7D))
 ;%0A    %7D)
@@ -1872,16 +1872,21 @@
       (%7B
+ err,
  output,
@@ -1895,32 +1895,146 @@
 riginal %7D) =%3E %7B%0A
+        if (err) %7B%0A          console.error(err);%0A          return common.updateOutputDisplay('' + err);%0A        %7D%0A
         common.c
@@ -2141,39 +2141,35 @@
       %7D,%0A      (
-%7B 
 err
- %7D
 ) =%3E %7B%0A        i
@@ -2178,14 +2178,8 @@
 (err
-.stack
 ) %7B%0A
@@ -2669,19 +2669,23 @@
 le.just(
+%7B 
 err
+ %7D
 ));%0A    

Fix errors breaking pipe