text: /* eslint-disable no-process-exit */
  require('babel-register');
  require('dotenv').load();
  const adler32 = require('adler32');
  
  const Rx = require('rx');
  const _ = require('lodash');
  const createDebugger = require('debug');
  const utils = require('../server/utils');
  const { getChallenges } = require('@freecodecamp/curriculum');
  const { validateChallenge } = require(
    './schema/challengeSchema'
  );
  const app = require('../server/server');
  
  const log = createDebugger('fcc:seed');
  // force logger to always output
  // this may be brittle
  log.enabled = true;
  
  const dasherize = utils.dasherize;
  const nameify = utils.nameify;
  const Observable = Rx.Observable;
  const Challenge = app.models.Challenge;
  
  const destroyChallenges =
    Observable.fromNodeCallback(Challenge.destroyAll, Challenge);
  const createChallenges =
    Observable.fromNodeCallback(Challenge.create, Challenge);
  
  const Block = app.models.Block;
  const destroyBlocks = Observable.fromNodeCallback(Block.destroyAll, Block);
  const createBlocks = Observable.fromNodeCallback(Block.create, Block);
  const arrToString = arr =>
    Array.isArray(arr) ? arr.join('\n') : _.toString(arr);
  
  Observable.combineLatest(
    destroyChallenges(),
    destroyBlocks()
  )
    .last()
    .flatMap(function() { return Observable.from(getChallenges()); })
    .flatMap(function(challengeSpec) {
      const order = challengeSpec.order;
      const blockName = challengeSpec.name;
      const superBlock = challengeSpec.superBlock;
      const superOrder = challengeSpec.superOrder;
      const isBeta = !!challengeSpec.isBeta;
      const isComingSoon = !!challengeSpec.isComingSoon;
      const fileName = challengeSpec.fileName;
      const helpRoom = challengeSpec.helpRoom || 'Help';
      const time = challengeSpec.time;
      const isLocked = !!challengeSpec.isLocked;
      const message = challengeSpec.message;
      const required = challengeSpec.required || [];
      const template = challengeSpec.template;
      const isPrivate = !!challengeSpec.isPrivate;
  
      log('parsed %s successfully', blockName);
  
      // challenge file has no challenges...
      if (challengeSpec.challenges.length === 0) {
        return Rx.Observable.just([{ block: 'empty ' + blockName }]);
      }
  
      const block = {
        title: blockName,
        name: nameify(blockName),
        dashedName: dasherize(blockName),
        superOrder,
        superBlock,
        superBlockMessage: message,
        order,
        time,
        isLocked,
        isPrivate
      };
  
      return createBlocks(block)
        .map(block => {
          log('successfully created %s block', block.name);
  
          return challengeSpec.challenges
            .map(function(challenge, index) {
              challenge.name = nameify(challenge.title);
  
              challenge.dashedName = dasherize(challenge.title);
  
              challenge.checksum = adler32.sum(
                Buffer(
                  challenge.title +
                  JSON.stringify(challenge.description) +
                  JSON.stringify(challenge.challengeSeed) +
                  JSON.stringify(challenge.tests)
                )
              );
  
              if (challenge.files) {
                challenge.files = _.reduce(challenge.files, (map, file) => {
                  map[file.key] = {
                    ...file,
                    head: arrToString(file.head),
                    contents: arrToString(file.contents),
                    tail: arrToString(file.tail)
                  };
                  return map;
                }, {});
              }
              challenge.fileName = fileName;
              challenge.helpRoom = helpRoom;
              challenge.order = order;
              challenge.suborder = index + 1;
              challenge.block = dasherize(blockName);
              challenge.blockId = '' + block.id;
              challenge.isBeta = challenge.isBeta || isBeta;
              challenge.isComingSoon = challenge.isComingSoon || isComingSoon;
              challenge.isLocked = challenge.isLocked || isLocked;
              challenge.isPrivate = challenge.isPrivate || isPrivate;
              challenge.time = challengeSpec.time;
              challenge.superOrder = superOrder;
              challenge.superBlock = superBlock
                .split('-')
                .map(function(word) {
                  return _.capitalize(word);
                })
                .join(' ');
              challenge.required = (challenge.required || []).concat(required);
              challenge.template = challenge.template || template;
              return _.omit(
                challenge,
                [
                  'betaSolutions',
                  'betaTests',
                  'hints',
                  'MDNlinks',
                  'null',
                  'rawSolutions',
                  'react',
                  'reactRedux',
                  'redux',
                  'releasedOn',
                  'translations',
                  'type'
                ]
              );
            });
        })
        .flatMap(challenges => {
          challenges.forEach(challenge => {
            const result = validateChallenge(challenge);
            if (result.error) {
              console.log(result.value);
              throw new Error(result.error);
            }
          });
          return createChallenges(challenges);
        });
    })
    .subscribe(
      function(challenges) {
        log('%s successfully saved', challenges[0].block);
      },
      function(err) { throw err; },
      function() {
        log('challenge seed completed');
        process.exit(0);
      }
    );
  