text: /* ************************************************************************************************
   *                                                                                                *
   * Plese read the following tutorial before implementing tasks:                                   *
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer *
   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object        *
   *                                                                                                *
   ************************************************************************************************ */
  
  function Rectangle(width, height) {
    return {
      width,
      height,
      getArea() { return width * height; },
    };
  }
  
  function getJSON(obj) {
    return JSON.stringify(obj);
  }
  
  function fromJSON(proto, json) {
    const obj = JSON.parse(json);
    const items = Object.values(obj);
    return new proto.constructor(...items);
  }
  
  
  /**
   * Css selectors builder
   *
   * Each complex selector can consists of type, id, class, attribute, pseudo-class
   * and pseudo-element selectors:
   *
   *    element#id.class[attr]:pseudoClass::pseudoElement
   *              \----/\----/\----------/
   *              Can be several occurences
   *
   * All types of selectors can be combined using the combinators ' ','+','~','>' .
   *
   * The task is to design a single class, independent classes or classes hierarchy
   * and implement the functionality to build the css selectors using the provided cssSelectorBuilder.
   * Each selector should have the stringify() method to output the string repsentation
   * according to css specification.
   *
   * Provided cssSelectorBuilder should be used as facade only to create your own classes,
   * for example the first method of cssSelectorBuilder can be like this:
   *   element: function(value) {
   *       return new MySuperBaseElementSelector(...)...
   *   },
   *
   * The design of class(es) is totally up to you, but try to make it as simple,
   * clear and readable as possible.
   *
   * @example
   *
   *  const builder = cssSelectorBuilder;
   *
   *  builder.id('main').class('container').class('editable').stringify()
   *    => '#main.container.editable'
   *
   *  builder.element('a').attr('href$=".png"').pseudoClass('focus').stringify()
   *    => 'a[href$=".png"]:focus'
   *
   *  builder.combine(
   *      builder.element('div').id('main').class('container').class('draggable'),
   *      '+',
   *      builder.combine(
   *          builder.element('table').id('data'),
   *          '~',
   *           builder.combine(
   *               builder.element('tr').pseudoClass('nth-of-type(even)'),
   *               ' ',
   *               builder.element('td').pseudoClass('nth-of-type(even)')
   *           )
   *      )
   *  ).stringify()
   *    => 'div#main.container.draggable + table#data ~ tr:nth-of-type(even)   td:nth-of-type(even)'
   *
   *  For more examples see unit tests.
   */
  
  // const cssSelectorBuilder = {
  //   item: '',
  //   itemHelp: [],
  //   elementNow: false,
  //   idNow: false,
  //   classNow: false,
  //   attrNow: false,
  //   pseudoClassNow: false,
  //   pseudoElementNow: false,
  //   element(value) {
  //     if (this.elementNow) throw Error('Element, id and pseudo-element
  // should not occur more then one time inside the selector');
  //     this.elementNow = true;
  //     this.itemHelp.push(this.item);
  //     this.item = '';
  //     this.item += value;
  //     return this;
  //   },
  
  //   id(value) {
  //     this.elementNow = false;
  //     if (this.item.split('').indexOf('#') !== -1) throw Error('Elem
  // ent, id and pseudo-element should not occur more then one time inside the selector');
  //     this.item += `#${value}`;
  //     return this;
  //   },
  
  //   class(value) {
  //     this.elementNow = false;
  //     this.item += `.${value}`;
  //     return this;
  //   },
  
  //   attr(value) {
  //     this.elementNow = false;
  //     this.item += `[${value}]`;
  //     return this;
  //   },
  
  //   pseudoClass(value) {
  //     this.elementNow = false;
  //     this.item += `:${value}`;
  //     return this;
  //   },
  
  //   pseudoElement(value) {
  //     if (this.item.split('::').indexOf('after') !== -1 || th
  // is.item.split('::').indexOf('before') !== -1) {
  //       throw Error('Element, id and pseudo-element should not
  //  occur more then one time inside the selector');
  //     }
  //     this.item += `::${value}`;
  //     return this;
  //   },
  
  //   // eslint-disable-next-line
  //   combine(selector1, combinator, selector2) {
  //     this.item = `${this.itemHelp.pop()} ${combinator} ${this.item}`;
  //     return this;
  //   },
  
  //   stringify() {
  //     this.elementNow = false;
  //     const str = this.item;
  //     this.item = '';
  //     return str;
  //   },
  // };
  const cssSelectorBuilder = {
    element(/* value */) {
      throw new Error('Not implemented');
    },
  
    id(/* value */) {
      throw new Error('Not implemented');
    },
  
    class(/* value */) {
      throw new Error('Not implemented');
    },
  
    attr(/* value */) {
      throw new Error('Not implemented');
    },
  
    pseudoClass(/* value */) {
      throw new Error('Not implemented');
    },
  
    pseudoElement(/* value */) {
      throw new Error('Not implemented');
    },
  
    combine(/* selector1, combinator, selector2 */) {
      throw new Error('Not implemented');
    },
  };
  
  module.exports = {
    Rectangle,
    getJSON,
    fromJSON,
    cssSelectorBuilder,
  };
  