let ComponentsOfProduct;
quizTypes.checkbox = [ ComponentsOfProduct = {
    probability: 10,
    correct: {min: 2, max: 4},
    wrong: {min: 1, max: 4},
    answers: {min: 3, max: 6},

    doNotLogUnique: true,
    questionCmpAmount: 2,
    type: 'Select components of product',
    products: {from: 3, to: 7},
    minSimilarTags: 1,
    from: qB.prebuild.similarTaggedProducts.fn,
    question(income, log){
      return `Какие ингредиенты входят в продукт ${lapk(income.correct.title)}`
    },
    answer(income, log){
      const correct = shuffle(income.allUniq)
          .slice(0, rand(this.correct.min, this.correct.max))
          .map(i=>new Answer.Correct(textFormat(i.name))),

        componentsNotInCorrect = qB.getComponentsNotInCorrect(income),

        maxWrongs = Math.min(this.wrong.max, this.answers.max-correct.length),

        wrongCount = rand(this.wrong.min,  maxWrongs),

        wrongs = componentsNotInCorrect
          .slice(0, wrongCount)
          .map(i=>new Answer.Wrong(textFormat(i.name)));

      log.push('');
      log.push(`Took ${correct.length} correct:`);
      correct.forEach(a=>log.push(`  > ${a.text}`))

      log.push('');
      log.push(`And ${wrongs.length} wrong:`);
      wrongs.forEach(a=>log.push(`  > ${a.text}`))

      return shuffle(correct.concat(wrongs));
    }
  },
  Object.assign({}, ComponentsOfProduct, {
    probability: 4,
    correct: {min: 2, max: 4},
    wrong: {min: 2, max: 4},
    answers: {min: 4, max: 8},
    realMaxAnswers: 6,
    question(income, log){
      return `Какие ингредиенты НЕ входят в продукт ${lapk(income.correct.title)}`
    },
    answer(income, log){
      log.push('Generate Answers by `Select components of product` subroutine');
      const result = ComponentsOfProduct.answer.call(this, income, log);
      log.push('Reversing');

      const reversed = result
        .map(a=>a instanceof Answer.Correct ? new Answer.Wrong(a.text) : new Answer.Correct(a.text));

      const right = reversed.filter(a=>a instanceof Answer.Correct),
            wrong = reversed.filter(a=>a instanceof Answer.Wrong);

      return shuffle(right.concat(wrong.slice(0, Math.min(this.wrong.max, this.realMaxAnswers - right.length))));
    }
  }),
  {
    probability: 10,
    correct: {min: 2, max: 4},
    wrong: {min: 1, max: 3},
    answers: {min: 4, max: 6},

    doNotLogUnique: true,
    questionCmpAmount: 2,
    type: 'Select components of product',
    products: {from: 2, to: 4},
    minSimilarTags: 1,
    from(log){
      const products = qB.randomProduct({
          minComponents: 1,
          amount: this.products,
          connectedByTags: true,
          minSimilarTags: this.minSimilarTags,
          doNotTrim: true
        }, log),

        componentsWithProducts = qB.getComponentsWithSharedProducts(products, 2);

      log.push('Shared products count: '+componentsWithProducts.length);

      if(componentsWithProducts.length === 0)
        return false;

      const bounded = componentsWithProducts.filter(cp=>
        cp.products.length >= this.correct.min &&
        products.length - cp.products.length >= this.wrong.min
      );

      log.push('After bounding by correct/wrong/full count '+bounded.length+' left');

      if(bounded.length === 0){
        log.push('Does not meet count criteria');
        return false;
      }

      const chosen = rand(bounded);
      log.push('Chosen component: '+chosen.component.name);
      
      return {
        baseProduct: chosen.products[0],
        component: chosen.component,
        correct: chosen.products,
        wrong: products.filter(p=>chosen.products.indexOf(p)===-1)
      };
    },
    question(income, log){
      return `В какие продукты входит следующий ингредиент ${lapk(textFormat(income.component.name))}`
    },
    answer(income, log){
      const correct = income.correct
          .slice(0, rand(this.correct))
          .map(p=>new Answer.Correct(p.title)),

        wrong = income.wrong
          .slice(0, Math.min(rand(this.wrong), this.answers.max - correct.length))
          .map(p=>new Answer.Wrong(p.title));

      log.push('');
      log.push(`Get ${correct.length} correct products:`);
      correct.map(c=>log.push(`  > ${c.text}`));

      log.push('');
      log.push(`Get ${correct.length} wrong products:`);
      wrong.map(c=>log.push(`  > ${c.text}`));

      return shuffle(correct.concat(wrong));
    }

  }

];