() => {
         comp.allowFreeText = true;
         comp.items = [];
         fixture.detectChanges();

         comp.innerInputContent = 'fake value';
         const input = fixture.debugElement.query(By.css('.st-tag-input__text.inner-input'));
         const enterKeyDownEventObj = {
            keyCode: 13, preventDefault: () => {
            }
         };
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual('fake value');

         comp.allowFreeText = false;
         comp.items = [];

         fixture.detectChanges();

         input.triggerEventHandler('keydown', enterKeyDownEventObj);
         fixture.detectChanges();

         expect(comp.items.length).toBe(0);
      }


() => {
      it('it is displayed by default if item list is empty when it is initialized', () => {
         comp.infoMessage = fakeInfoMessage;

         comp.writeValue(_cloneDeep(simpleTags));
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();
      });

      it('it is displayed (if it exists) until user adds a tag', () => {
         comp.infoMessage = undefined;
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();

         comp.infoMessage = fakeInfoMessage;
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).not.toBeNull();
         expect(fixture.nativeElement.querySelector('.info-message').innerHTML).toEqual(fakeInfoMessage);

         comp.innerInputContent = 'New tag';
         const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
         input.triggerEventHandler('keydown', {
            keyCode: 9, preventDefault: () => {
            }
         });
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();
      });
   }


() => {
         comp.infoMessage = fakeInfoMessage;

         comp.writeValue(_cloneDeep(simpleTags));
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();
      }


() => {
         comp.infoMessage = undefined;
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();

         comp.infoMessage = fakeInfoMessage;
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).not.toBeNull();
         expect(fixture.nativeElement.querySelector('.info-message').innerHTML).toEqual(fakeInfoMessage);

         comp.innerInputContent = 'New tag';
         const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
         input.triggerEventHandler('keydown', {
            keyCode: 9, preventDefault: () => {
            }
         });
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();
      }


() => {
      comp.infoMessage = undefined;
      fixture.detectChanges();

      expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();

      comp.infoMessage = fakeInfoMessage;
      fixture.detectChanges();

      expect(fixture.nativeElement.querySelector('.info-message').innerHTML).toEqual(fakeInfoMessage);

      comp.innerInputContent = 'New tag';
      const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
      input.triggerEventHandler('keydown', {
         keyCode: 9, preventDefault: () => {
         }
      });
      fixture.detectChanges();

      expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();

   }


() => {
      let input: DebugElement;
      let enterKeyDownEventObj: any;

      beforeEach(() => {
         fixture.detectChanges();
         input = fixture.debugElement.query(By.css('.st-tag-input__text.inner-input'));
         enterKeyDownEventObj = {
            keyCode: 13, preventDefault: () => {
            }
         };
      });

      it('by default type of items is text', () => {
         comp.onInputText('New Tag');

         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual('New Tag');
      });

      it('if type is number, model will be an array of numbers', () => {
         comp.type = 'number';

         comp.onInputText('56');

         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(56);

         comp.onInputText('100.54');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(100.54);
      });

      it('if type is integer, model will be an array of integers', () => {
         comp.type = 'integer';
         comp.onInputText('567');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(567);
      });

      it('When type is integer and user types and invalid integer, it wont be added', () => {
         comp.items = [];
         comp.type = 'integer';
         comp.onInputText('invalid integer');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(0);

         comp.onInputText('58.2');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toBe(58);

         comp.onInputText('62');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toBe(62);
      });

      it('When type is number and user types and invalid number, it wont be added', () => {
         comp.items = [];
         comp.type = 'integer';
         comp.onInputText('invalid integer');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(0);

         comp.onInputText('56&notANumber');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(1);
         expect(comp.items[comp.items.length - 1]).toEqual(56);

         comp.onInputText('&notANumber56');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(1);

         comp.onInputText('58');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(2);
         expect(comp.items[comp.items.length - 1]).toEqual(58);

         comp.onInputText('74.2');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(74);
      });
   }


() => {
         fixture.detectChanges();
         input = fixture.debugElement.query(By.css('.st-tag-input__text.inner-input'));
         enterKeyDownEventObj = {
            keyCode: 13, preventDefault: () => {
            }
         };
      }


() => {
         comp.onInputText('New Tag');

         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual('New Tag');
      }


() => {
         comp.type = 'number';

         comp.onInputText('56');

         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(56);

         comp.onInputText('100.54');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(100.54);
      }


() => {
         comp.type = 'integer';
         comp.onInputText('567');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(567);
      }


() => {
         comp.items = [];
         comp.type = 'integer';
         comp.onInputText('invalid integer');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(0);

         comp.onInputText('58.2');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toBe(58);

         comp.onInputText('62');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toBe(62);
      }


() => {
         comp.items = [];
         comp.type = 'integer';
         comp.onInputText('invalid integer');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(0);

         comp.onInputText('56&notANumber');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(1);
         expect(comp.items[comp.items.length - 1]).toEqual(56);

         comp.onInputText('&notANumber56');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(1);

         comp.onInputText('58');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items.length).toBe(2);
         expect(comp.items[comp.items.length - 1]).toEqual(58);

         comp.onInputText('74.2');
         input.triggerEventHandler('keydown', enterKeyDownEventObj);

         expect(comp.items[comp.items.length - 1]).toEqual(74);
      }


() => {
         TestBed.configureTestingModule({
            imports: [FormsModule, ReactiveFormsModule, StTagInputModule, StClickOutsideModule],
            declarations: [StTagInputTestReactiveComponent]
         })
            .overrideComponent(StTagInputComponent, {
               set: { changeDetection: ChangeDetectionStrategy.Default }
            })
            .compileComponents();  // compile template and css
      }


() => {
         fixture = TestBed.createComponent(StTagInputTestReactiveComponent);
         comp = fixture.componentInstance;
         compTagInput = comp.tagInput;
         fixture.detectChanges();
      }


() => {
         fixture.destroy();
      }


() => {
         fixture.detectChanges();
         expect(compTagInput.items).toEqual([]);

         comp.reactiveForm.get('tags').setValue(simpleTags);
         fixture.detectChanges();
         expect(compTagInput.items).toEqual(simpleTags);
      }


() => {
         compTagInput.infoMessage = fakeInfoMessage;
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).not.toBeNull();

         comp.reactiveForm.get('tags').setValue(simpleTags);
         fixture.detectChanges();

         expect(fixture.nativeElement.querySelector('.info-message')).toBeNull();
      }


() => {
         const responseFunction = jasmine.createSpy('response');
         comp.reactiveForm.get('tags').valueChanges.subscribe(responseFunction);
         fixture.detectChanges();

         const id: string = 'test-id';
         (fixture.elementRef.nativeElement as HTMLElement).id = id;
         compTagInput.label = 'Test';
         compTagInput.innerInputContent = 'New Tag';
         fixture.detectChanges();

         const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
         input.triggerEventHandler('keydown', {
            keyCode: 188, preventDefault: () => {
            }
         });
         fixture.detectChanges();

         expect(compTagInput.items.length).toEqual(1);
         expect(compTagInput.innerInputContent).toEqual('');

         expect(comp.reactiveForm.valid).toBeTruthy();
         expect(comp.reactiveForm.value.tags).toEqual(compTagInput.items);
         expect(comp.reactiveForm.value.tags[0]).toEqual('New Tag');
         expect(responseFunction).toHaveBeenCalled();
         expect(responseFunction).toHaveBeenCalledWith(compTagInput.items);
      }


() => {
         comp.reactiveForm.get('tags').setValue([]);
         fixture.detectChanges();
         expect(comp.reactiveForm.valid).toBeFalsy();

         comp.reactiveForm.get('tags').setValue(['New Tag']);
         fixture.detectChanges();
         expect(comp.reactiveForm.valid).toBeTruthy();
      }


() => {
         compTagInput.type = 'text';
         compTagInput.regularExpression = ipFormat;
         compTagInput.ngOnInit();
         fixture.detectChanges();

         compTagInput.innerInputContent = 'New Tag';
         fixture.detectChanges();

         const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
         input.triggerEventHandler('keydown', {
            keyCode: 188, preventDefault: () => {
            }
         });
         fixture.detectChanges();

         expect(compTagInput.items.length).toEqual(0);

         compTagInput.innerInputContent = '192.168.1.1';
         fixture.detectChanges();

         input.triggerEventHandler('keydown', {
            keyCode: 188, preventDefault: () => {
            }
         });
         fixture.detectChanges();

         expect(compTagInput.items.length).toEqual(1);
      }


() => {
         beforeEach(() => {
            compTagInput.type = 'number';
            compTagInput.ngOnInit();
            fixture.detectChanges();
         });

         it('and user types a text with letters and other symbols different to a dot, it wont be added', () => {
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56fg';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.items[0]).toEqual(34.56);
         });

         it('if form control has invalid values, only will be added the valid numbers', () => {
            (<any> comp.reactiveForm.controls).tags.setValue(['text', 2, 6.67]);
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(2);
            expect(compTagInput.items).toEqual([2, 6.67]);
         });
      }


() => {
            compTagInput.type = 'number';
            compTagInput.ngOnInit();
            fixture.detectChanges();
         }


() => {
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56fg';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.items[0]).toEqual(34.56);
         }


() => {
            (<any> comp.reactiveForm.controls).tags.setValue(['text', 2, 6.67]);
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(2);
            expect(compTagInput.items).toEqual([2, 6.67]);
         }


() => {
         beforeEach(() => {
            compTagInput.type = 'integer';
            compTagInput.ngOnInit();
            fixture.detectChanges();
         });

         it('and user types a text with characters different to numbers, it wont be added', () => {
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56fg';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.items[0]).toEqual(56);
         });

         it('if form control has invalid values, only will be added the valid integers', () => {
            (<any> comp.reactiveForm.controls).tags.setValue(['text', 78, 6]);
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(2);
            expect(compTagInput.items).toEqual([78, 6]);
         });
      }


() => {
            compTagInput.type = 'integer';
            compTagInput.ngOnInit();
            fixture.detectChanges();
         }


() => {
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56fg';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '34.56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(0);

            compTagInput.innerInputContent = '56';
            fixture.detectChanges();

            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.items[0]).toEqual(56);
         }


() => {
            (<any> comp.reactiveForm.controls).tags.setValue(['text', 78, 6]);
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(2);
            expect(compTagInput.items).toEqual([78, 6]);
         }


() => {
   describe('Template form instance', () => {
      let fixture: ComponentFixture<StTagInputTestTemplateComponent>;
      let comp: StTagInputTestTemplateComponent;
      let compTagInput: StTagInputComponent;

      beforeEach(async(() => {
         TestBed.configureTestingModule({
            imports: [FormsModule, StTagInputModule],
            declarations: [StTagInputTestTemplateComponent]
         }).compileComponents();  // compile template and css
      }));

      beforeEach(() => {
         fixture = TestBed.createComponent(StTagInputTestTemplateComponent);
         comp = fixture.componentInstance;
         compTagInput = comp.tagInput;
      });

      afterEach(() => {
         fixture.destroy();
      });

      it('Should change value from formControl', async(() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            expect(compTagInput.items).toEqual([]);

            comp.templateDrivenForm.form.get('tags').setValue(simpleTags);
            fixture.detectChanges();
            expect(compTagInput.items).toEqual(simpleTags);
         });
      }));

      it('Should change model when add tag', async(() => {
         const responseFunction = jasmine.createSpy('response');
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').valueChanges.subscribe(responseFunction);

            const id: string = 'test-id';
            (fixture.elementRef.nativeElement as HTMLElement).id = id;
            compTagInput.label = 'Test';
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.innerInputContent).toEqual('');

            expect(comp.templateDrivenForm.valid).toBeTruthy();
            expect(comp.templateDrivenForm.value.tags).toEqual(compTagInput.items);
            expect(comp.templateDrivenForm.value.tags[0]).toEqual('New Tag');
            expect(responseFunction).toHaveBeenCalled();
            expect(responseFunction).toHaveBeenCalledWith(compTagInput.items);
         });
      }));

      it('Should validate required status', async(() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').setValue([]);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeFalsy();

            comp.templateDrivenForm.form.get('tags').setValue(['New Tag']);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeTruthy();
         });
      }));

      describe('should be able to not allow user types a forbidden value if there are', () => {
         it('if a forbidden value list is not introduced as input, user can introduce whatever he wants', async(() => {
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'new tag 2';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
            });
         }));

         it('if a forbidden value list is introduced as input and user introduces a forbidden value, tag is not added to model', async(() => {
            compTagInput.forbiddenValues = ['forbidden value'];
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'forbidden value';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1); // is not added the forbidden value
            });
         }));
      });

      it('if regular expression is introduced as input, only values that match it will be valid', (done) => {
         compTagInput.regularExpression = ipFormat;
         fixture.detectChanges();

         fixture.whenStable().then(() => { // Form generation it's asynchronous
            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = '1.1.1.1';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'invalid ip';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = '192.168.1.1';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
               done();
            });
         });
      });
   });
}


() => {
      let fixture: ComponentFixture<StTagInputTestTemplateComponent>;
      let comp: StTagInputTestTemplateComponent;
      let compTagInput: StTagInputComponent;

      beforeEach(async(() => {
         TestBed.configureTestingModule({
            imports: [FormsModule, StTagInputModule],
            declarations: [StTagInputTestTemplateComponent]
         }).compileComponents();  // compile template and css
      }));

      beforeEach(() => {
         fixture = TestBed.createComponent(StTagInputTestTemplateComponent);
         comp = fixture.componentInstance;
         compTagInput = comp.tagInput;
      });

      afterEach(() => {
         fixture.destroy();
      });

      it('Should change value from formControl', async(() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            expect(compTagInput.items).toEqual([]);

            comp.templateDrivenForm.form.get('tags').setValue(simpleTags);
            fixture.detectChanges();
            expect(compTagInput.items).toEqual(simpleTags);
         });
      }));

      it('Should change model when add tag', async(() => {
         const responseFunction = jasmine.createSpy('response');
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').valueChanges.subscribe(responseFunction);

            const id: string = 'test-id';
            (fixture.elementRef.nativeElement as HTMLElement).id = id;
            compTagInput.label = 'Test';
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.innerInputContent).toEqual('');

            expect(comp.templateDrivenForm.valid).toBeTruthy();
            expect(comp.templateDrivenForm.value.tags).toEqual(compTagInput.items);
            expect(comp.templateDrivenForm.value.tags[0]).toEqual('New Tag');
            expect(responseFunction).toHaveBeenCalled();
            expect(responseFunction).toHaveBeenCalledWith(compTagInput.items);
         });
      }));

      it('Should validate required status', async(() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').setValue([]);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeFalsy();

            comp.templateDrivenForm.form.get('tags').setValue(['New Tag']);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeTruthy();
         });
      }));

      describe('should be able to not allow user types a forbidden value if there are', () => {
         it('if a forbidden value list is not introduced as input, user can introduce whatever he wants', async(() => {
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'new tag 2';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
            });
         }));

         it('if a forbidden value list is introduced as input and user introduces a forbidden value, tag is not added to model', async(() => {
            compTagInput.forbiddenValues = ['forbidden value'];
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'forbidden value';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1); // is not added the forbidden value
            });
         }));
      });

      it('if regular expression is introduced as input, only values that match it will be valid', (done) => {
         compTagInput.regularExpression = ipFormat;
         fixture.detectChanges();

         fixture.whenStable().then(() => { // Form generation it's asynchronous
            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = '1.1.1.1';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'invalid ip';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = '192.168.1.1';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
               done();
            });
         });
      });
   }


() => {
         TestBed.configureTestingModule({
            imports: [FormsModule, StTagInputModule],
            declarations: [StTagInputTestTemplateComponent]
         }).compileComponents();  // compile template and css
      }


() => {
         fixture = TestBed.createComponent(StTagInputTestTemplateComponent);
         comp = fixture.componentInstance;
         compTagInput = comp.tagInput;
      }


() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            expect(compTagInput.items).toEqual([]);

            comp.templateDrivenForm.form.get('tags').setValue(simpleTags);
            fixture.detectChanges();
            expect(compTagInput.items).toEqual(simpleTags);
         });
      }


() => { // Form generation it's asynchronous
            expect(compTagInput.items).toEqual([]);

            comp.templateDrivenForm.form.get('tags').setValue(simpleTags);
            fixture.detectChanges();
            expect(compTagInput.items).toEqual(simpleTags);
         }


() => {
         const responseFunction = jasmine.createSpy('response');
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').valueChanges.subscribe(responseFunction);

            const id: string = 'test-id';
            (fixture.elementRef.nativeElement as HTMLElement).id = id;
            compTagInput.label = 'Test';
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.innerInputContent).toEqual('');

            expect(comp.templateDrivenForm.valid).toBeTruthy();
            expect(comp.templateDrivenForm.value.tags).toEqual(compTagInput.items);
            expect(comp.templateDrivenForm.value.tags[0]).toEqual('New Tag');
            expect(responseFunction).toHaveBeenCalled();
            expect(responseFunction).toHaveBeenCalledWith(compTagInput.items);
         });
      }


() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').valueChanges.subscribe(responseFunction);

            const id: string = 'test-id';
            (fixture.elementRef.nativeElement as HTMLElement).id = id;
            compTagInput.label = 'Test';
            compTagInput.innerInputContent = 'New Tag';
            fixture.detectChanges();

            const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
            input.triggerEventHandler('keydown', {
               keyCode: 188, preventDefault: () => {
               }
            });
            fixture.detectChanges();

            expect(compTagInput.items.length).toEqual(1);
            expect(compTagInput.innerInputContent).toEqual('');

            expect(comp.templateDrivenForm.valid).toBeTruthy();
            expect(comp.templateDrivenForm.value.tags).toEqual(compTagInput.items);
            expect(comp.templateDrivenForm.value.tags[0]).toEqual('New Tag');
            expect(responseFunction).toHaveBeenCalled();
            expect(responseFunction).toHaveBeenCalledWith(compTagInput.items);
         }


() => {
         fixture.detectChanges();
         fixture.whenStable().then(() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').setValue([]);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeFalsy();

            comp.templateDrivenForm.form.get('tags').setValue(['New Tag']);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeTruthy();
         });
      }


() => { // Form generation it's asynchronous
            comp.templateDrivenForm.form.get('tags').setValue([]);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeFalsy();

            comp.templateDrivenForm.form.get('tags').setValue(['New Tag']);
            fixture.detectChanges();
            expect(comp.templateDrivenForm.valid).toBeTruthy();
         }


() => {
         it('if a forbidden value list is not introduced as input, user can introduce whatever he wants', async(() => {
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'new tag 2';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
            });
         }));

         it('if a forbidden value list is introduced as input and user introduces a forbidden value, tag is not added to model', async(() => {
            compTagInput.forbiddenValues = ['forbidden value'];
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'forbidden value';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1); // is not added the forbidden value
            });
         }));
      }


() => {
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'new tag 2';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
            });
         }


() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'new tag 2';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
            }


() => {
            compTagInput.forbiddenValues = ['forbidden value'];
            fixture.detectChanges();

            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'forbidden value';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1); // is not added the forbidden value
            });
         }


() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = 'New Tag';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'forbidden value';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1); // is not added the forbidden value
            }


(done) => {
         compTagInput.regularExpression = ipFormat;
         fixture.detectChanges();

         fixture.whenStable().then(() => { // Form generation it's asynchronous
            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = '1.1.1.1';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'invalid ip';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = '192.168.1.1';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
               done();
            });
         });
      }


() => { // Form generation it's asynchronous
            fixture.whenStable().then(() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = '1.1.1.1';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'invalid ip';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = '192.168.1.1';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
               done();
            });
         }


() => { // Form generation it's asynchronous
               compTagInput.innerInputContent = '1.1.1.1';
               fixture.detectChanges();

               const input: DebugElement = fixture.debugElement.query(By.css('.inner-input'));
               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();
               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = 'invalid ip';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(1);

               compTagInput.innerInputContent = '192.168.1.1';
               fixture.detectChanges();

               input.triggerEventHandler('keydown', {
                  keyCode: 188, preventDefault: () => {
                  }
               });
               fixture.detectChanges();

               expect(compTagInput.items.length).toEqual(2);
               done();
            }


@Component({
   template: `
      <form [formGroup]="reactiveForm" novalidate autocomplete="off">
         <st-tag-input #tagInput
            name="tags"
            formControlName="tags"
            placeholder="placeholder"
            label="Test"
            tooltip="Test Help"
            id="test"
            [errorMessage]="errorMessage"
            class="st-form-field">
         </st-tag-input>
      </form>
   `
})
class StTagInputTestReactiveComponent {
   errorMessage: string | undefined = null;
   reactiveForm: FormGroup;
   model: string[] = [];

   @ViewChild('tagInput') tagInput: StTagInputComponent;

   constructor(private _fb: FormBuilder) {
      this.reactiveForm = this._fb.group({
         tags: [this.model, [Validators.required]]
      });
   }
}


@Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
   template: `
      <form #templateDrivenForm="ngForm" novalidate autocomplete="off">
         <st-tag-input #tagInput
            class="st-form-field"
            id="test"
            placeholder="placeholder"
            name="tags"
            label="Test"
            tooltip="Test Help"
            required
            [errorMessage]="errorMessage"
            [(ngModel)]="model"
         >
         </st-tag-input>
      </form>
      `
})
class StTagInputTestTemplateComponent {
   errorMessage: string | undefined = null;
   model: string[] = [];

   @ViewChild('tagInput') tagInput: StTagInputComponent;
   @ViewChild('templateDrivenForm') templateDrivenForm: NgForm;
}


() => {
  let component: RingComponent;
  let fixture: ComponentFixture<RingComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ RingComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(RingComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
}


() => {
    TestBed.configureTestingModule({
      declarations: [ RingComponent ]
    })
    .compileComponents();
  }


() => {
    fixture = TestBed.createComponent(RingComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }


() => {
      for (const scenario of this.suite.scenarios) {
        describe(scenario.name, () => {
          let containerBuilder: ContainerBuilder
          let container: Container
          before("before scenario", async () => {
            if (this.before) {
              await this.before()
            }
          })
          before("create the container builder", async () => {
            containerBuilder = this.provide()
          })
          before("configure the builder with executor configuration", async () => {
            if (this.configure) {
              await Promise.resolve(this.configure(containerBuilder))
            }
          })
          before("configure the builder with scenario configuration", async () => {
            if (scenario.configure) {
              await Promise.resolve(scenario.configure(containerBuilder))
            }
          })
          before("initialize the container", async () => {
            container = await containerBuilder.build().initialize()
          })
          before("before execution", async () => {
            if (scenario.before) {
              await scenario.before(container)
            }
          })
          it("execution", async () => {
            await scenario.execute(container)
          })
          after("after execution", async () => {
            if (scenario.after) {
              await scenario.after(container)
            }
          })
          after("dispose the container", async () => {
            await container.dispose()
          })
          after("after scenario", async () => {
            if (this.after) {
              await this.after()
            }
          })
        })
      }
    }


() => {
          let containerBuilder: ContainerBuilder
          let container: Container
          before("before scenario", async () => {
            if (this.before) {
              await this.before()
            }
          })
          before("create the container builder", async () => {
            containerBuilder = this.provide()
          })
          before("configure the builder with executor configuration", async () => {
            if (this.configure) {
              await Promise.resolve(this.configure(containerBuilder))
            }
          })
          before("configure the builder with scenario configuration", async () => {
            if (scenario.configure) {
              await Promise.resolve(scenario.configure(containerBuilder))
            }
          })
          before("initialize the container", async () => {
            container = await containerBuilder.build().initialize()
          })
          before("before execution", async () => {
            if (scenario.before) {
              await scenario.before(container)
            }
          })
          it("execution", async () => {
            await scenario.execute(container)
          })
          after("after execution", async () => {
            if (scenario.after) {
              await scenario.after(container)
            }
          })
          after("dispose the container", async () => {
            await container.dispose()
          })
          after("after scenario", async () => {
            if (this.after) {
              await this.after()
            }
          })
        }


async () => {
            if (this.before) {
              await this.before()
            }
          }


async () => {
            containerBuilder = this.provide()
          }


async () => {
            if (this.configure) {
              await Promise.resolve(this.configure(containerBuilder))
            }
          }


async () => {
            if (scenario.configure) {
              await Promise.resolve(scenario.configure(containerBuilder))
            }
          }


async () => {
            container = await containerBuilder.build().initialize()
          }


async () => {
            if (scenario.before) {
              await scenario.before(container)
            }
          }


async () => {
            await scenario.execute(container)
          }


async () => {
            if (scenario.after) {
              await scenario.after(container)
            }
          }


async () => {
            await container.dispose()
          }


async () => {
            if (this.after) {
              await this.after()
            }
          }


/**
 * An implementation of {@link AbstractTestSuiteExecutor} dedicated for Mocha.
 *
 * Instances should be created using the builder {@link MochaTestSuiteExecutorBuilder}.
 */
export class MochaTestSuiteExecutor extends AbstractTestSuiteExecutor<Suite> {
  constructor(
    suite: TestSuite,
    before?: Callback,
    provider?: ContainerBuilderProvider,
    configurer?: CallbackWithContainerBuilder,
    after?: Callback
  ) {
    super(suite, before, provider, configurer, after)
  }

  execute(): Suite {
    return describe(this.suite.name, () => {
      for (const scenario of this.suite.scenarios) {
        describe(scenario.name, () => {
          let containerBuilder: ContainerBuilder
          let container: Container
          before("before scenario", async () => {
            if (this.before) {
              await this.before()
            }
          })
          before("create the container builder", async () => {
            containerBuilder = this.provide()
          })
          before("configure the builder with executor configuration", async () => {
            if (this.configure) {
              await Promise.resolve(this.configure(containerBuilder))
            }
          })
          before("configure the builder with scenario configuration", async () => {
            if (scenario.configure) {
              await Promise.resolve(scenario.configure(containerBuilder))
            }
          })
          before("initialize the container", async () => {
            container = await containerBuilder.build().initialize()
          })
          before("before execution", async () => {
            if (scenario.before) {
              await scenario.before(container)
            }
          })
          it("execution", async () => {
            await scenario.execute(container)
          })
          after("after execution", async () => {
            if (scenario.after) {
              await scenario.after(container)
            }
          })
          after("dispose the container", async () => {
            await container.dispose()
          })
          after("after scenario", async () => {
            if (this.after) {
              await this.after()
            }
          })
        })
      }
    })
  }
}


/**
 * An extension of {@link AbstractTestSuiteExecutorBuilder} dedicated for Mocha.
 *
 * @example run a test suite with an dummy scenario
 * ```typescript
 * import {TestScenarioBuilder, TestSuiteBuilder} from "@tmorin/ceb-inversion-testing-core";
 * import {MochaTestSuiteExecutor} from "@tmorin/ceb-inversion-testing-mocha"
 * MochaTestSuiteExecutorBuilder.get(
 *  TestSuiteBuilder.get("test suite").scenario(
 *      TestScenarioBuilder.get("test scenario")
 *  )
 * ).test()
 * ```
 */
export class MochaTestSuiteExecutorBuilder extends AbstractTestSuiteExecutorBuilder<Suite> {
  private constructor(suite: TestSuite) {
    super(suite)
  }

  /**
   * Create a builder.
   * @param suite the suite
   */
  static get(suite: TestSuite | TestSuiteBuilder) {
    if (suite instanceof TestSuiteBuilder) {
      return new MochaTestSuiteExecutorBuilder(suite.build())
    }
    return new MochaTestSuiteExecutorBuilder(suite)
  }

  /**
   * Build the executor.
   */
  build(): TestSuiteExecutor<Suite> {
    return new MochaTestSuiteExecutor(this._suite, this._before, this._provider, this._configurer, this._after)
  }
}


execute(): Suite {
    return describe(this.suite.name, () => {
      for (const scenario of this.suite.scenarios) {
        describe(scenario.name, () => {
          let containerBuilder: ContainerBuilder
          let container: Container
          before("before scenario", async () => {
            if (this.before) {
              await this.before()
            }
          })
          before("create the container builder", async () => {
            containerBuilder = this.provide()
          })
          before("configure the builder with executor configuration", async () => {
            if (this.configure) {
              await Promise.resolve(this.configure(containerBuilder))
            }
          })
          before("configure the builder with scenario configuration", async () => {
            if (scenario.configure) {
              await Promise.resolve(scenario.configure(containerBuilder))
            }
          })
          before("initialize the container", async () => {
            container = await containerBuilder.build().initialize()
          })
          before("before execution", async () => {
            if (scenario.before) {
              await scenario.before(container)
            }
          })
          it("execution", async () => {
            await scenario.execute(container)
          })
          after("after execution", async () => {
            if (scenario.after) {
              await scenario.after(container)
            }
          })
          after("dispose the container", async () => {
            await container.dispose()
          })
          after("after scenario", async () => {
            if (this.after) {
              await this.after()
            }
          })
        })
      }
    })
  }


/**
   * Create a builder.
   * @param suite the suite
   */
static get(suite: TestSuite | TestSuiteBuilder) {
    if (suite instanceof TestSuiteBuilder) {
      return new MochaTestSuiteExecutorBuilder(suite.build())
    }
    return new MochaTestSuiteExecutorBuilder(suite)
  }


/**
   * Build the executor.
   */
build(): TestSuiteExecutor<Suite> {
    return new MochaTestSuiteExecutor(this._suite, this._before, this._provider, this._configurer, this._after)
  }


() => {
  beforeEach(() => TestBed.configureTestingModule({}));

  it('should be created', () => {
    const service: ConfigurationService = TestBed.inject(ConfigurationService);
    expect(service).toBeTruthy();
  });
}


() => {
    const service: ConfigurationService = TestBed.inject(ConfigurationService);
    expect(service).toBeTruthy();
  }


(
  name: BlockName,
  parent?: DescribeBlock,
  mode?: BlockMode,
): DescribeBlock => {
  let _mode = mode;
  if (parent && !mode) {
    // If not set explicitly, inherit from the parent describe.
    _mode = parent.mode;
  }

  return {
    children: [],
    hooks: [],
    mode: _mode,
    name: convertDescriptorToString(name),
    parent,
    tests: [],
  };
}


(
  fn: TestFn | undefined,
  mode: TestMode,
  name: TestName,
  parent: DescribeBlock,
  timeout: number | undefined,
  asyncError: Exception,
): TestEntry => ({
  asyncError,
  duration: null,
  errors: [],
  fn,
  invocations: 0,
  mode,
  name: convertDescriptorToString(name),
  parent,
  startedAt: null,
  status: null,
  timeout,
})


(describeBlock: DescribeBlock): boolean => {
  const {hasFocusedTests, testNamePattern} = getState();
  const hasOwnEnabledTests = describeBlock.tests.some(
    test =>
      !(
        test.mode === 'skip' ||
        (hasFocusedTests && test.mode !== 'only') ||
        (testNamePattern && !testNamePattern.test(getTestID(test)))
      ),
  );

  return hasOwnEnabledTests || describeBlock.children.some(hasEnabledTest);
}


test =>
      !(
        test.mode === 'skip' ||
        (hasFocusedTests && test.mode !== 'only') ||
        (testNamePattern && !testNamePattern.test(getTestID(test)))
      )


(describe: DescribeBlock) => {
  const result: {
    beforeAll: Array<Hook>;
    afterAll: Array<Hook>;
  } = {
    afterAll: [],
    beforeAll: [],
  };

  if (hasEnabledTest(describe)) {
    for (const hook of describe.hooks) {
      switch (hook.type) {
        case 'beforeAll':
          result.beforeAll.push(hook);
          break;
        case 'afterAll':
          result.afterAll.push(hook);
          break;
      }
    }
  }

  return result;
}


(test: TestEntry) => {
  const result: {
    beforeEach: Array<Hook>;
    afterEach: Array<Hook>;
  } = {afterEach: [], beforeEach: []};
  let block: DescribeBlock | undefined | null = test.parent;

  do {
    const beforeEachForCurrentBlock = [];
    for (const hook of block.hooks) {
      switch (hook.type) {
        case 'beforeEach':
          beforeEachForCurrentBlock.push(hook);
          break;
        case 'afterEach':
          result.afterEach.push(hook);
          break;
      }
    }
    // 'beforeEach' hooks are executed from top to bottom, the opposite of the
    // way we traversed it.
    result.beforeEach = [...beforeEachForCurrentBlock, ...result.beforeEach];
  } while ((block = block.parent));
  return result;
}


(describe: DescribeBlock): boolean =>
  describe.tests.length > 0 || describe.children.some(describeBlockHasTests)


(timeout: number, isHook: boolean) =>
  `Exceeded timeout of ${timeout}ms for a ${
    isHook ? 'hook' : 'test'
  }.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.`


(
  fn: AsyncFn,
  testContext: TestContext | undefined,
  {isHook, timeout}: {isHook?: boolean | null; timeout: number},
): Promise<any> => {
  let timeoutID: NodeJS.Timeout;

  return new Promise((resolve, reject) => {
    timeoutID = setTimeout(
      () => reject(_makeTimeoutMessage(timeout, !!isHook)),
      timeout,
    );

    // If this fn accepts `done` callback we return a promise that fulfills as
    // soon as `done` called.
    if (fn.length) {
      const done = (reason?: Error | string): void => {
        const isError =
          reason && (reason as Error).message && (reason as Error).stack;
        return reason
          ? reject(
              isError
                ? reason
                : new Error(`Failed: ${prettyFormat(reason, {maxDepth: 3})}`),
            )
          : resolve();
      };

      return fn.call(testContext, done);
    }

    let returnedValue;
    if (isGeneratorFn(fn)) {
      returnedValue = co.wrap(fn).call({});
    } else {
      try {
        returnedValue = fn.call(testContext);
      } catch (error) {
        return reject(error);
      }
    }

    // If it's a Promise, return it. Test for an object with a `then` function
    // to support custom Promise implementations.
    if (
      typeof returnedValue === 'object' &&
      returnedValue !== null &&
      typeof returnedValue.then === 'function'
    ) {
      return returnedValue.then(resolve, reject);
    }

    if (!isHook && returnedValue !== void 0) {
      return reject(
        new Error(
          `
      test functions can only return Promise or undefined.
      Returned value: ${String(returnedValue)}
      `,
        ),
      );
    }

    // Otherwise this test is synchronous, and if it didn't throw it means
    // it passed.
    return resolve();
  })
    .then(() => {
      // If timeout is not cleared/unrefed the node process won't exit until
      // it's resolved.
      timeoutID.unref && timeoutID.unref();
      clearTimeout(timeoutID);
    })
    .catch(error => {
      timeoutID.unref && timeoutID.unref();
      clearTimeout(timeoutID);
      throw error;
    });
}


(resolve, reject) => {
    timeoutID = setTimeout(
      () => reject(_makeTimeoutMessage(timeout, !!isHook)),
      timeout,
    );

    // If this fn accepts `done` callback we return a promise that fulfills as
    // soon as `done` called.
    if (fn.length) {
      const done = (reason?: Error | string): void => {
        const isError =
          reason && (reason as Error).message && (reason as Error).stack;
        return reason
          ? reject(
              isError
                ? reason
                : new Error(`Failed: ${prettyFormat(reason, {maxDepth: 3})}`),
            )
          : resolve();
      };

      return fn.call(testContext, done);
    }

    let returnedValue;
    if (isGeneratorFn(fn)) {
      returnedValue = co.wrap(fn).call({});
    } else {
      try {
        returnedValue = fn.call(testContext);
      } catch (error) {
        return reject(error);
      }
    }

    // If it's a Promise, return it. Test for an object with a `then` function
    // to support custom Promise implementations.
    if (
      typeof returnedValue === 'object' &&
      returnedValue !== null &&
      typeof returnedValue.then === 'function'
    ) {
      return returnedValue.then(resolve, reject);
    }

    if (!isHook && returnedValue !== void 0) {
      return reject(
        new Error(
          `
      test functions can only return Promise or undefined.
      Returned value: ${String(returnedValue)}
      `,
        ),
      );
    }

    // Otherwise this test is synchronous, and if it didn't throw it means
    // it passed.
    return resolve();
  }


() => reject(_makeTimeoutMessage(timeout, !!isHook))


(reason?: Error | string): void => {
        const isError =
          reason && (reason as Error).message && (reason as Error).stack;
        return reason
          ? reject(
              isError
                ? reason
                : new Error(`Failed: ${prettyFormat(reason, {maxDepth: 3})}`),
            )
          : resolve();
      }


() => {
      // If timeout is not cleared/unrefed the node process won't exit until
      // it's resolved.
      timeoutID.unref && timeoutID.unref();
      clearTimeout(timeoutID);
    }


error => {
      timeoutID.unref && timeoutID.unref();
      clearTimeout(timeoutID);
      throw error;
    }


(test: TestEntry): number | null => {
  const {startedAt} = test;
  return typeof startedAt === 'number' ? Date.now() - startedAt : null;
}


(
  describeBlock: DescribeBlock,
  unhandledErrors: Array<Error>,
): RunResult => ({
  testResults: makeTestResults(describeBlock),
  unhandledErrors: unhandledErrors.map(_formatError),
})


(describeBlock: DescribeBlock): TestResults => {
  const {includeTestLocationInResult} = getState();
  let testResults: TestResults = [];
  for (const test of describeBlock.tests) {
    const testPath = [];
    let parent: TestEntry | DescribeBlock = test;
    do {
      testPath.unshift(parent.name);
    } while ((parent = parent.parent));

    const {status} = test;

    if (!status) {
      throw new Error('Status should be present after tests are run.');
    }

    let location = null;
    if (includeTestLocationInResult) {
      const stackLine = test.asyncError.stack.split('\n')[1];
      const parsedLine = stackUtils.parseLine(stackLine);
      if (
        parsedLine &&
        typeof parsedLine.column === 'number' &&
        typeof parsedLine.line === 'number'
      ) {
        location = {
          column: parsedLine.column,
          line: parsedLine.line,
        };
      }
    }

    testResults.push({
      duration: test.duration,
      errors: test.errors.map(_formatError),
      invocations: test.invocations,
      location,
      status,
      testPath,
    });
  }

  for (const child of describeBlock.children) {
    testResults = testResults.concat(makeTestResults(child));
  }

  return testResults;
}


(test: TestEntry) => {
  const titles = [];
  let parent: TestEntry | DescribeBlock = test;
  do {
    titles.unshift(parent.name);
  } while ((parent = parent.parent));

  titles.shift(); // remove TOP_DESCRIBE_BLOCK_NAME
  return titles.join(' ');
}


(
  errors?: Exception | [Exception | undefined, Exception],
): string => {
  let error;
  let asyncError;

  if (Array.isArray(errors)) {
    error = errors[0];
    asyncError = errors[1];
  } else {
    error = errors;
    asyncError = new Error();
  }

  if (error) {
    if (error.stack) {
      return error.stack;
    }
    if (error.message) {
      return error.message;
    }
  }

  asyncError.message = `thrown: ${prettyFormat(error, {maxDepth: 3})}`;

  return asyncError.stack;
}


(
  describeBlock: DescribeBlock,
  error: Exception,
  asyncError: Exception,
) => {
  for (const test of describeBlock.tests) {
    test.errors.push([error, asyncError]);
  }

  for (const child of describeBlock.children) {
    addErrorToEachTestUnderDescribe(child, error, asyncError);
  }
}


(condition: unknown, message?: string) => {
  if (!condition) {
    throw new Error(message);
  }
}


@ObjectType()
export class Company implements CompanyInterface {
    @Field()
    id: string;

    @Field()
    name: string;

    @Field({ nullable: true })
    description?: string;

    @Field()
    active: boolean;

    @Field()
    plan: number;
}


@Component({
  selector: 'foundation-6-framework',
  template: `
    <select-widget-widget
      [layoutNode]="layoutNode"
      [dataIndex]="dataIndex"
      [layoutIndex]="layoutIndex"></select-widget-widget>`,
})
export class Foundation6Component implements OnInit, OnChanges {
  @Input() layoutNode: any;
  @Input() layoutIndex: number[];
  @Input() dataIndex: number[];

  constructor(
    private changeDetector: ChangeDetectorRef,
    private jsf: JsonSchemaFormService
  ) { }

  ngOnInit() { }

  ngOnChanges() { }
}


ngOnChanges() { }


/**
 * Android Policy entity for Intune MAM.
 */
export function getAndroidMAMPolicyByName(args: GetAndroidMAMPolicyByNameArgs, opts?: pulumi.InvokeOptions): Promise<GetAndroidMAMPolicyByNameResult> {
    if (!opts) {
        opts = {}
    }

    if (!opts.version) {
        opts.version = utilities.getVersion();
    }
    return pulumi.runtime.invoke("azure-nextgen:intune/v20150114preview:getAndroidMAMPolicyByName", {
        "hostName": args.hostName,
        "policyName": args.policyName,
        "select": args.select,
    }, opts);
}


export interface GetAndroidMAMPolicyByNameArgs {
    /**
     * Location hostName for the tenant
     */
    readonly hostName: string;
    /**
     * Unique name for the policy
     */
    readonly policyName: string;
    /**
     * select specific fields in entity.
     */
    readonly select?: string;
}


/**
 * Android Policy entity for Intune MAM.
 */
export interface GetAndroidMAMPolicyByNameResult {
    readonly accessRecheckOfflineTimeout?: string;
    readonly accessRecheckOnlineTimeout?: string;
    readonly appSharingFromLevel?: string;
    readonly appSharingToLevel?: string;
    readonly authentication?: string;
    readonly clipboardSharingLevel?: string;
    readonly dataBackup?: string;
    readonly description?: string;
    readonly deviceCompliance?: string;
    readonly fileEncryption?: string;
    readonly fileSharingSaveAs?: string;
    readonly friendlyName: string;
    readonly groupStatus: string;
    /**
     * Resource Id
     */
    readonly id: string;
    readonly lastModifiedTime: string;
    /**
     * Resource Location
     */
    readonly location?: string;
    readonly managedBrowser?: string;
    /**
     * Resource name
     */
    readonly name: string;
    readonly numOfApps: number;
    readonly offlineWipeTimeout?: string;
    readonly pin?: string;
    readonly pinNumRetry?: number;
    readonly screenCapture?: string;
    /**
     * Resource Tags
     */
    readonly tags?: {[key: string]: string};
    /**
     * Resource type
     */
    readonly type: string;
}


// tslint:disable-next-line:cyclomatic-complexity
export default function targetInstancesByTimeZone(
  instance: any,
  targets: { [index: string]: any }
): boolean {
  if (!instance) {
    return false;
  }

  if (!targets) {
    return true;
  }

  const instanceTimeZone = instance.targets &&
                            instance.targets.Timezone &&
                            instance.targets.Timezone.timezone;

  const campaign = instance.campaign;
  const campaignTimeZone = targets[campaign] &&
                            targets[campaign].Timezone &&
                            targets[campaign].Timezone.timezone;

  const currentDate = new Date();

  if (instanceTimeZone && instanceTimeZone !== String(currentDate.getTimezoneOffset())) {
    return false;
  }

  if (campaignTimeZone && campaignTimeZone !== String(currentDate.getTimezoneOffset())) {
    return false;
  }

  return true;
}


export default class Terminal extends S22 {

  render() {
    return
Complete!

  }
}


render() {
    return
Complete!

  }


data => {
          if (data.msgRet == "1") {
            this.toastService.addSingle("error", "", "شما در سیستم احراز هویت نشده اید")
            this.router.navigate(['/otp']);
          }
          else if (data.msgRet == "2") {
            this.toastService.addSingle("error", "", "چنین کاربری در سیستم تعریف نشده است با مسئول سیستم تماس حاصل نمایید(4144)")
          }
          else {
            var mes = "همکار گرامی گذرواژه شما برای ورود به " + environment.appName + " " + this.randomPass;
            let d = { Mobile: data.Mobile, Message: mes }
            this.smsService.SendSms(d)

            this.toastService.addSingle("success", "", "کاربر گرامی گذرواژه به تلفن همراه ثبت شده در سیستم ارسال گردید")
            this.router.navigate(['/login']);
          }
        }


err => { console.log(err) }


@Component({
  selector: 'app-recover-password',
  templateUrl: './recover-password.component.html',
  styleUrls: ['./recover-password.component.css']
})
export class RecoverPasswordComponent implements OnInit {

  userform: FormGroup;
  currentUser;
  version: string;

  constructor(private smsService: SmsService, private userService: AuthenticationService, private router: Router, private fb: FormBuilder, private toastService: ToastService) { }

  ngOnInit() {
    this.currentUser = this.userService.getcurrentUser;
    //console.log(this.currentUser)
    this.userform = this.fb.group({
      //'Mobile': new FormControl('', Validators.required),
      'NatioalCode': new FormControl('', Validators.compose([Validators.required, Validators.minLength(10), Validators.maxLength(10)]))
    }
    );

    this.version = environment.version;
  }

  checkNationalCode() {
    if (this.userform.controls["NatioalCode"].value != undefined && this.userform.controls["NatioalCode"].value.length == 10) {
      if (this.userform.controls["NatioalCode"].value == '0000000000' || this.userform.controls["NatioalCode"].value == '1111111111' || this.userform.controls["NatioalCode"].value == '2222222222' || this.userform.controls["NatioalCode"].value == '3333333333' || this.userform.controls["NatioalCode"].value == '4444444444' || this.userform.controls["NatioalCode"].value == '5555555555' || this.userform.controls["NatioalCode"].value == '6666666666' || this.userform.controls["NatioalCode"].value == '7777777777' || this.userform.controls["NatioalCode"].value == '8888888888' || this.userform.controls["NatioalCode"].value == '9999999999') {
        this.userform.get('NatioalCode').setErrors({ invalidNumber: { message: 'کد ملی صحیح نمیباشد' } })
      } else {
        var c = parseInt(this.userform.controls["NatioalCode"].value.charAt(9));
        var n = parseInt(this.userform.controls["NatioalCode"].value.charAt(0)) * 10 + parseInt(this.userform.controls["NatioalCode"].value.charAt(1)) * 9 + parseInt(this.userform.controls["NatioalCode"].value.charAt(2)) * 8 + parseInt(this.userform.controls["NatioalCode"].value.charAt(3)) * 7 + parseInt(this.userform.controls["NatioalCode"].value.charAt(4)) * 6 + parseInt(this.userform.controls["NatioalCode"].value.charAt(5)) * 5 + parseInt(this.userform.controls["NatioalCode"].value.charAt(6)) * 4 + parseInt(this.userform.controls["NatioalCode"].value.charAt(7)) * 3 + parseInt(this.userform.controls["NatioalCode"].value.charAt(8)) * 2;
        var r = n - Math.floor(n / 11) * 11;// n - parseInt(n / 11) * 11;
        if ((r == 0 && r == c) || (r == 1 && c == 1) || (r > 1 && c == 11 - r)) {
          console.log('sahih ast');
          this.userform.get('NatioalCode').setErrors(null)
        }
        else {
          console.log('sahih nist');
          this.userform.get('NatioalCode').setErrors({ invalidNumber: { message: 'کد ملی صحیح نمیباشد' } })
        }
      }
    }
    else {

      //this.userform.controls["NatioalCode"].setErrors({ 'invalidNumber': true });
    }
  }

  private randomPass: string;
  onClickChangePassword() {
    this.checkNationalCode();
    if (this.userform.valid) {
      this.randomPass = (Math.floor(Math.random() * (999999 - 100000)) + 100000).toString();
      this.userService.recoverpassword(this.userform.controls["NatioalCode"].value, this.randomPass, environment.appId).subscribe(
        data => {
          if (data.msgRet == "1") {
            this.toastService.addSingle("error", "", "شما در سیستم احراز هویت نشده اید")
            this.router.navigate(['/otp']);
          }
          else if (data.msgRet == "2") {
            this.toastService.addSingle("error", "", "چنین کاربری در سیستم تعریف نشده است با مسئول سیستم تماس حاصل نمایید(4144)")
          }
          else {
            var mes = "همکار گرامی گذرواژه شما برای ورود به " + environment.appName + " " + this.randomPass;
            let d = { Mobile: data.Mobile, Message: mes }
            this.smsService.SendSms(d)

            this.toastService.addSingle("success", "", "کاربر گرامی گذرواژه به تلفن همراه ثبت شده در سیستم ارسال گردید")
            this.router.navigate(['/login']);
          }
        },
        err => { console.log(err) }
      );
    }
    // if (isRegistered) {
    //   this.router.navigate(['/login']);
    //   this.toastService.addSingle("success", "", "User registered.")
    //}
  }

  onClickGoToLogin() {
    this.router.navigate(['/main/dashboard']);
  }

  isClickCapcha:boolean=false
  showResponse(event) {
    this.isClickCapcha = true

}

}


ngOnInit() {
    this.currentUser = this.userService.getcurrentUser;
    //console.log(this.currentUser)
    this.userform = this.fb.group({
      //'Mobile': new FormControl('', Validators.required),
      'NatioalCode': new FormControl('', Validators.compose([Validators.required, Validators.minLength(10), Validators.maxLength(10)]))
    }
    );

    this.version = environment.version;
  }


checkNationalCode() {
    if (this.userform.controls["NatioalCode"].value != undefined && this.userform.controls["NatioalCode"].value.length == 10) {
      if (this.userform.controls["NatioalCode"].value == '0000000000' || this.userform.controls["NatioalCode"].value == '1111111111' || this.userform.controls["NatioalCode"].value == '2222222222' || this.userform.controls["NatioalCode"].value == '3333333333' || this.userform.controls["NatioalCode"].value == '4444444444' || this.userform.controls["NatioalCode"].value == '5555555555' || this.userform.controls["NatioalCode"].value == '6666666666' || this.userform.controls["NatioalCode"].value == '7777777777' || this.userform.controls["NatioalCode"].value == '8888888888' || this.userform.controls["NatioalCode"].value == '9999999999') {
        this.userform.get('NatioalCode').setErrors({ invalidNumber: { message: 'کد ملی صحیح نمیباشد' } })
      } else {
        var c = parseInt(this.userform.controls["NatioalCode"].value.charAt(9));
        var n = parseInt(this.userform.controls["NatioalCode"].value.charAt(0)) * 10 + parseInt(this.userform.controls["NatioalCode"].value.charAt(1)) * 9 + parseInt(this.userform.controls["NatioalCode"].value.charAt(2)) * 8 + parseInt(this.userform.controls["NatioalCode"].value.charAt(3)) * 7 + parseInt(this.userform.controls["NatioalCode"].value.charAt(4)) * 6 + parseInt(this.userform.controls["NatioalCode"].value.charAt(5)) * 5 + parseInt(this.userform.controls["NatioalCode"].value.charAt(6)) * 4 + parseInt(this.userform.controls["NatioalCode"].value.charAt(7)) * 3 + parseInt(this.userform.controls["NatioalCode"].value.charAt(8)) * 2;
        var r = n - Math.floor(n / 11) * 11;// n - parseInt(n / 11) * 11;
        if ((r == 0 && r == c) || (r == 1 && c == 1) || (r > 1 && c == 11 - r)) {
          console.log('sahih ast');
          this.userform.get('NatioalCode').setErrors(null)
        }
        else {
          console.log('sahih nist');
          this.userform.get('NatioalCode').setErrors({ invalidNumber: { message: 'کد ملی صحیح نمیباشد' } })
        }
      }
    }
    else {

      //this.userform.controls["NatioalCode"].setErrors({ 'invalidNumber': true });
    }
  }


onClickChangePassword() {
    this.checkNationalCode();
    if (this.userform.valid) {
      this.randomPass = (Math.floor(Math.random() * (999999 - 100000)) + 100000).toString();
      this.userService.recoverpassword(this.userform.controls["NatioalCode"].value, this.randomPass, environment.appId).subscribe(
        data => {
          if (data.msgRet == "1") {
            this.toastService.addSingle("error", "", "شما در سیستم احراز هویت نشده اید")
            this.router.navigate(['/otp']);
          }
          else if (data.msgRet == "2") {
            this.toastService.addSingle("error", "", "چنین کاربری در سیستم تعریف نشده است با مسئول سیستم تماس حاصل نمایید(4144)")
          }
          else {
            var mes = "همکار گرامی گذرواژه شما برای ورود به " + environment.appName + " " + this.randomPass;
            let d = { Mobile: data.Mobile, Message: mes }
            this.smsService.SendSms(d)

            this.toastService.addSingle("success", "", "کاربر گرامی گذرواژه به تلفن همراه ثبت شده در سیستم ارسال گردید")
            this.router.navigate(['/login']);
          }
        },
        err => { console.log(err) }
      );
    }
    // if (isRegistered) {
    //   this.router.navigate(['/login']);
    //   this.toastService.addSingle("success", "", "User registered.")
    //}
  }


onClickGoToLogin() {
    this.router.navigate(['/main/dashboard']);
  }


showResponse(event) {
    this.isClickCapcha = true

}


class TestController extends Controller {
	protected index(request: Request, params: NodeJS.Dict<string>) {
		return this.response("HELLO 2!");
	}
}


protected index(request: Request, params: NodeJS.Dict<string>) {
		return this.response("HELLO 2!");
	}


() => {
  let component: GraphContainerComponent;
  let fixture: ComponentFixture<GraphContainerComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [GraphContainerComponent]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(GraphContainerComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should be created', () => {
    expect(component).toBeTruthy();
  });
}


() => {
    TestBed.configureTestingModule({
      declarations: [GraphContainerComponent]
    })
      .compileComponents();
  }


() => {
    fixture = TestBed.createComponent(GraphContainerComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }


export function isPromiseCompletionSource<T>(obj: any): obj is PromiseCompletionSource<T> {
    return obj.promise
        && obj.resolve
        && obj.reject;
}


(resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        }


() => {
                const i = this.eventSubscribers.indexOf(observer);
                if (i >= 0) {
                    this.eventSubscribers.splice(i, 1);
                }
            }


export class PromiseCompletionSource<T> {
    private _resolve: (value: T) => void = () => { };
    private _reject: (reason: any) => void = () => { };
    readonly promise: Promise<T>;

    constructor() {
        this.promise = new Promise<T>((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });
    }

    resolve(value: T) {
        this._resolve(value);
    }

    reject(reason: any) {
        this._reject(reason);
    }
}


export class GenericChannel implements contracts.KernelCommandAndEventChannel {

    private stillRunning: PromiseCompletionSource<number>;
    private commandHandler: contracts.KernelCommandEnvelopeHandler = () => Promise.resolve();
    private eventSubscribers: Array<contracts.KernelEventEnvelopeObserver> = [];

    constructor(private readonly messageSender: (message: contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope) => Promise<void>, private readonly messageReceiver: () => Promise<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope>) {

        this.stillRunning = new PromiseCompletionSource<number>();
    }

    dispose(): void {
        this.stop();
    }

    async run(): Promise<void> {
        while (true) {
            let message = await Promise.race([this.messageReceiver(), this.stillRunning.promise]);
            if (typeof message === 'number') {
                return;
            }
            if (utilities.isKernelCommandEnvelope(message)) {
                this.commandHandler(message);
            } else if (utilities.isKernelEventEnvelope(message)) {
                for (let i = this.eventSubscribers.length - 1; i >= 0; i--) {
                    this.eventSubscribers[i](message);
                }
            }
        }
    }

    stop() {
        this.stillRunning.resolve(-1);
    }

    submitCommand(commandEnvelope: contracts.KernelCommandEnvelope): Promise<void> {
        return this.messageSender(commandEnvelope);
    }

    publishKernelEvent(eventEnvelope: contracts.KernelEventEnvelope): Promise<void> {
        return this.messageSender(eventEnvelope);
    }

    subscribeToKernelEvents(observer: contracts.KernelEventEnvelopeObserver): contracts.DisposableSubscription {
        this.eventSubscribers.push(observer);
        return {
            dispose: () => {
                const i = this.eventSubscribers.indexOf(observer);
                if (i >= 0) {
                    this.eventSubscribers.splice(i, 1);
                }
            }
        };
    }

    setCommandHandler(handler: contracts.KernelCommandEnvelopeHandler) {
        this.commandHandler = handler;
    }
}


export class CommandAndEventReceiver {
    private _waitingOnMessages: PromiseCompletionSource<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope> | null = null;
    private readonly _envelopeQueue: (contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope)[] = [];

    public delegate(commandOrEvent: contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope) {
        if (this._waitingOnMessages) {
            let capturedMessageWaiter = this._waitingOnMessages;
            this._waitingOnMessages = null;

            capturedMessageWaiter.resolve(commandOrEvent);
        } else {

            this._envelopeQueue.push(commandOrEvent);
        }
    }

    public read(): Promise<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope> {
        let envelope = this._envelopeQueue.shift();
        if (envelope) {
            return Promise.resolve<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope>(envelope);
        }
        else {
            Logger.default.info(`channel building promise awaiter`);
            this._waitingOnMessages = new PromiseCompletionSource<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope>();
            return this._waitingOnMessages.promise;
        }
    }
}


resolve(value: T) {
        this._resolve(value);
    }


reject(reason: any) {
        this._reject(reason);
    }


dispose(): void {
        this.stop();
    }


async run(): Promise<void> {
        while (true) {
            let message = await Promise.race([this.messageReceiver(), this.stillRunning.promise]);
            if (typeof message === 'number') {
                return;
            }
            if (utilities.isKernelCommandEnvelope(message)) {
                this.commandHandler(message);
            } else if (utilities.isKernelEventEnvelope(message)) {
                for (let i = this.eventSubscribers.length - 1; i >= 0; i--) {
                    this.eventSubscribers[i](message);
                }
            }
        }
    }


stop() {
        this.stillRunning.resolve(-1);
    }


submitCommand(commandEnvelope: contracts.KernelCommandEnvelope): Promise<void> {
        return this.messageSender(commandEnvelope);
    }


publishKernelEvent(eventEnvelope: contracts.KernelEventEnvelope): Promise<void> {
        return this.messageSender(eventEnvelope);
    }


subscribeToKernelEvents(observer: contracts.KernelEventEnvelopeObserver): contracts.DisposableSubscription {
        this.eventSubscribers.push(observer);
        return {
            dispose: () => {
                const i = this.eventSubscribers.indexOf(observer);
                if (i >= 0) {
                    this.eventSubscribers.splice(i, 1);
                }
            }
        };
    }


setCommandHandler(handler: contracts.KernelCommandEnvelopeHandler) {
        this.commandHandler = handler;
    }


public delegate(commandOrEvent: contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope) {
        if (this._waitingOnMessages) {
            let capturedMessageWaiter = this._waitingOnMessages;
            this._waitingOnMessages = null;

            capturedMessageWaiter.resolve(commandOrEvent);
        } else {

            this._envelopeQueue.push(commandOrEvent);
        }
    }


public read(): Promise<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope> {
        let envelope = this._envelopeQueue.shift();
        if (envelope) {
            return Promise.resolve<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope>(envelope);
        }
        else {
            Logger.default.info(`channel building promise awaiter`);
            this._waitingOnMessages = new PromiseCompletionSource<contracts.KernelCommandEnvelope | contracts.KernelEventEnvelope>();
            return this._waitingOnMessages.promise;
        }
    }


(resolve: Function, reject: Function) => {
      sequelize.transaction((t: Transaction) => {
        return models.Product.create(productAttributes).then((product: ProductInstance) => {
          logger.info(`Created product with name ${productAttributes.name}.`);
          resolve(product);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      });
    }


(t: Transaction) => {
        return models.Product.create(productAttributes).then((product: ProductInstance) => {
          logger.info(`Created product with name ${productAttributes.name}.`);
          resolve(product);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      }


(product: ProductInstance) => {
          logger.info(`Created product with name ${productAttributes.name}.`);
          resolve(product);
        }


(error: Error) => {
          logger.error(error.message);
          reject(error);
        }


(resolve: Function, reject: Function) => {
      sequelize.transaction((t: Transaction) => {
        return models.Product.findOne({where: {name: name}}).then((product: ProductInstance) => {
          if (product) {
            logger.info(`Retrieved product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(product);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      });
    }


(t: Transaction) => {
        return models.Product.findOne({where: {name: name}}).then((product: ProductInstance) => {
          if (product) {
            logger.info(`Retrieved product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(product);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      }


(product: ProductInstance) => {
          if (product) {
            logger.info(`Retrieved product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(product);
        }


(resolve: Function, reject: Function) => {
      sequelize.transaction((t: Transaction) => {
        return models.Product.findAll().then((products: Array<ProductInstance>) => {
          logger.info("Retrieved all products.");
          console.log("Retrieved all products.");
          resolve(products);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      });
    }


(t: Transaction) => {
        return models.Product.findAll().then((products: Array<ProductInstance>) => {
          logger.info("Retrieved all products.");
          console.log("Retrieved all products.");
          resolve(products);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      }


(products: Array<ProductInstance>) => {
          logger.info("Retrieved all products.");
          console.log("Retrieved all products.");
          resolve(products);
        }


(resolve: Function, reject: Function) => {
      sequelize.transaction((t: Transaction) => {
        return models.Product.update(productAttributes, {where: {name: name}})
          .then((results: [number, Array<ProductInstance>]) => {
          if (results.length > 0) {
            logger.info(`Updated product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      });
    }


(t: Transaction) => {
        return models.Product.update(productAttributes, {where: {name: name}})
          .then((results: [number, Array<ProductInstance>]) => {
          if (results.length > 0) {
            logger.info(`Updated product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      }


(results: [number, Array<ProductInstance>]) => {
          if (results.length > 0) {
            logger.info(`Updated product with name ${name}.`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }


(resolve: Function, reject: Function) => {
      sequelize.transaction((t: Transaction) => {
        return models.Product.destroy({where: {name: name}}).then((afffectedRows: number) => {
          if (afffectedRows > 0) {
            logger.info(`Deleted product with name ${name}`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      });
    }


(t: Transaction) => {
        return models.Product.destroy({where: {name: name}}).then((afffectedRows: number) => {
          if (afffectedRows > 0) {
            logger.info(`Deleted product with name ${name}`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }).catch((error: Error) => {
          logger.error(error.message);
          reject(error);
        });
      }


(afffectedRows: number) => {
          if (afffectedRows > 0) {
            logger.info(`Deleted product with name ${name}`);
          } else {
            logger.info(`Product with name ${name} does not exist.`);
          }
          resolve(null);
        }