<repo_name>Z0neNp/maxim_chanturiay<file_sep>/frontend/src/app/education/education.component.spec.ts
import { DebugNode } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { environment } from "../../environments/environment";
import { AppModule } from "../app.module";
import { EducationComponent } from "./education.component";
import { EducationRsmElDirective } from "./rsm-el.directive";
import { EducationRsmElTitleDirective } from "./rsm-el-title.directive";

describe('EducationComponent', () => {
  let component: EducationComponent;
  let fixture: ComponentFixture<EducationComponent>;
  let educationRsmElTitleDirectiveQueryResponse: DebugNode[];
  let educationRsmElDirectiveQueryResponse: DebugNode[];

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ EducationComponent, EducationRsmElDirective, EducationRsmElTitleDirective ],
      imports: [ AppModule ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(EducationComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    educationRsmElTitleDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(EducationRsmElTitleDirective)
    );
    educationRsmElDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(EducationRsmElDirective)
    )
  });

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

  it("should have as title \"Education\"", () => {
    expect(component.title).toEqual('Education');
  });

  it("should contain the directives", () => {
    expect(educationRsmElTitleDirectiveQueryResponse).toHaveSize(1);
    expect(educationRsmElDirectiveQueryResponse).toHaveSize(1);
  });

  it("should render the EducationRsmElTitleDirective with default style", () => {
    let directive: DebugNode = educationRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    expect(el.innerHTML).toContain("Education");
    expect(el.classList).toContain("rsm-el-title");
  });

  it("should show EducationRsmElTitleDirective as pressed when touch starts", () => {
    let directive: DebugNode = educationRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    el.dispatchEvent(new Event("touchstart"));
    expect(el.classList).toContain("pressed");
  });

  it("should show EducationRsmElTitleDirective as non pressed when touch ends", (done) => {
    let directive: DebugNode = educationRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    el.dispatchEvent(new Event("touchstart"));
    el.dispatchEvent(new Event("touchend"));
    setTimeout(() => {
      expect(el.classList).not.toContain("pressed");
      done();
    }, environment.event.rendered_delay);
  });

  it(
    "should show EducationRsmElDirective when EducationRsmElTitleDirective touch ends",
    (done) => {
      let directive: DebugNode = educationRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      directive = educationRsmElDirectiveQueryResponse[0];
      el = directive.nativeNode;
      setTimeout(() => {
        expect(el.classList).toContain("rsm-el-shown");
        expect(el.classList).not.toContain("rsm-el-not-shown");
        done();
      }, environment.event.rendered_delay);
    }
  );
});
<file_sep>/README.md
# About
This is the source code for my interactive resume.
You can visit it at http://172.16.31.10
<file_sep>/frontend/src/app/reusable-directives/rsm-el-title.directive.ts
import { Directive, ElementRef, HostListener, OnInit } from '@angular/core';

import { environment } from '../../environments/environment';

import { AppModule } from '../app.module';

import { LoggerService } from '../reusable-services/logger.service';

@Directive()
export class RsmElTitleDirective implements OnInit {

  protected logger: LoggerService;

  constructor(private el: ElementRef) {
    this.logger = AppModule.injector.get(LoggerService);
  }

  ngOnInit(): void {
    this.defaultStyle();
  }

  @HostListener('touchend')
  onTouchEnd() {
    this.showNonPressed();
  }

  @HostListener('touchstart')
  onTouchStart() {
    this.showPressed();
  }

  protected defaultStyle() {
    this.el.nativeElement.classList.add("rsm-el-title");
  }

  protected showNonPressed() {
    setTimeout(() => {
      this.el.nativeElement.classList.remove("pressed");
      this.el.nativeElement.scrollIntoView();
    }, environment.event.pressed_delay);
  }

  protected showPressed() {
    this.el.nativeElement.classList.add("pressed");
  }
}
<file_sep>/frontend/src/app/contact-info/chip.spec.ts
import { Chip } from './chip';

describe('Chip', () => {
  it('should create an instance', () => {
    expect(new Chip()).toBeTruthy();
  });
});
<file_sep>/frontend/src/app/contact-info/contact-info.component.spec.ts
import { DebugNode } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { environment } from "../../environments/environment";
import { AppModule } from "../app.module";
import { ContactInfoComponent } from './contact-info.component';
import { ContactInfoRsmElTitleDirective } from './rsm-el-title.directive';
import { ContactInfoRsmElDirective } from './rsm-el.directive';

describe('ContactInfoComponent', () => {
  let component: ContactInfoComponent;
  let fixture: ComponentFixture<ContactInfoComponent>;
  let contactInfoRsmElTitleDirectiveQueryResponse: DebugNode[];
  let contactInfoRsmElDirectiveQueryResponse: DebugNode[];

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [
        ContactInfoComponent, ContactInfoRsmElTitleDirective, ContactInfoRsmElDirective
      ],
      imports: [ AppModule ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(ContactInfoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    contactInfoRsmElTitleDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(ContactInfoRsmElTitleDirective)
    );
    contactInfoRsmElDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(ContactInfoRsmElDirective)
    )
  });

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

  it("should have as title \"Contact Details\"", () => {
    expect(component.title).toEqual('Contact Details');
  });

  it("should contain the directives", () => {
    expect(contactInfoRsmElTitleDirectiveQueryResponse).toHaveSize(1);
    expect(contactInfoRsmElDirectiveQueryResponse).toHaveSize(1);
  });

  it("should render the ContactInfoRsmElTitleDirective with default style", () => {
    let directive: DebugNode = contactInfoRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    expect(el.innerHTML).toContain("Contact Details");
    expect(el.classList).toContain("rsm-el-title");
  });

  it("should show ContactInfoRsmElTitleDirective as pressed when touch starts", () => {
    let directive: DebugNode = contactInfoRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    el.dispatchEvent(new Event("touchstart"));
    expect(el.classList).toContain("pressed");
  });

  it(
    "should show ContactInfoRsmElTitleDirective as non pressed when touch ends",
    (done) => {
      let directive: DebugNode = contactInfoRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      setTimeout(() => {
        expect(el.classList).not.toContain("pressed");
        done();
      }, environment.event.rendered_delay);
    }
  );

  it(
    "should show ContactInfoRsmElDirective when ContactInfoRsmElTitleDirective touch ends",
    (done) => {
      let directive: DebugNode = contactInfoRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      directive = contactInfoRsmElDirectiveQueryResponse[0];
      el = directive.nativeNode;
      setTimeout(() => {
        expect(el.classList).toContain("rsm-el-shown");
        expect(el.classList).not.toContain("rsm-el-not-shown");
        done();
      }, environment.event.rendered_delay);
    }
  );

});
<file_sep>/frontend/src/app/enterprise-experience/software-tool.ts
import { Icon } from "./icon";

export class SoftwareTool {

  icon: Icon;
  link: string;
  name: string;

  constructor(src: string, alt: string, link: string, name: string) {
    this.icon = new Icon(src, alt);
    this.link = link;
    this.name = name;
  }
}
<file_sep>/frontend/src/app/reusable-directives/rsm-el.directive.ts
import { Directive, ElementRef, Inject, OnInit } from '@angular/core';

import { environment } from '../../environments/environment';

import { AppModule } from '../app.module';

import { LoggerService } from '../reusable-services/logger.service';

@Directive()
export class RsmElDirective implements OnInit {
  
  protected logger: LoggerService;

  constructor(private el: ElementRef) {
    this.logger = AppModule.injector.get(LoggerService);
  }

  ngOnInit(): void {
    if (window.innerWidth < 1024)
      this.doNotShowDirective();
  }

  protected doNotShowDirective(): void {
    this.el.nativeElement.classList.remove("rsm-el-shown");
    this.el.nativeElement.classList.add("rsm-el-not-shown");
    setTimeout(() => {
      this.el.nativeElement.classList.remove("rendered");
      this.el.nativeElement.classList.add("not-rendered");
    }, environment.event.rendered_delay);
  }

  protected showDirective(): void {
    this.el.nativeElement.classList.remove("not-rendered");
    this.el.nativeElement.classList.add("rendered");
    setTimeout(() => {
      this.el.nativeElement.classList.remove("rsm-el-not-shown");
      this.el.nativeElement.classList.add("rsm-el-shown");
    }, environment.event.rendered_delay);
  }
}
<file_sep>/frontend/src/environments/environment.prod.ts
export const environment = {
  event: {
    pressed_delay: 100,
    rendered_delay: 70
  },
  logger: {
    debug: false
  },
  production: true
};
<file_sep>/frontend/src/app/reusable-services/logger.service.ts
import { Injectable } from '@angular/core';

import { environment } from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class LoggerService {

  constructor() {}

  public debug(class_name: String, method_name: String, msg: String): void {
    if (environment.logger.debug) 
      console.debug(`DEBUG -- ${class_name} -- ${method_name}() -- ${msg}`);
  }

  public error(class_name: String, method_name: String, msg: String): void {
    console.error(`ERROR -- ${class_name} -- ${method_name}() -- ${msg}`);
  }
}
<file_sep>/frontend/src/app/contact-info/chip.ts
import { Icon } from "./icon";

export class Chip {

  icon: Icon;
  link: string;
  value: string;

  constructor(src: string, alt: string, link: string, value: string) {
    this.icon = new Icon(src, alt);
    this.link = link;
    this.value = value;
  }

  public hasLink(): boolean {
    return this.link.length !== 0;
  }
}
<file_sep>/frontend/src/app/enterprise-experience/rsm-el.directive.ts
import { Directive, ElementRef } from '@angular/core';
import { Subscription } from 'rxjs';

import { RsmElDirective } from "../reusable-directives/rsm-el.directive";
import { RsmElState } from "../reusable-enums/rsm-el-state";
import { EntExpRsmElTitleToRsmElCommService } from "./rsm-el-title-to-rsm-el-comm.service";

@Directive({
  selector: '[appEntExpRsmEl]'
})
export class EntExpRsmElDirective extends RsmElDirective {

  private commToRsmElTitle: Subscription;

  constructor(
    el: ElementRef,
    private commToRsmElTitleService: EntExpRsmElTitleToRsmElCommService
  ) {
    super(el);
    this.commToRsmElTitle = this.commToRsmElTitleService.rsmElTitleToRsmEl
      .subscribe((state: RsmElState) => { this.consumeRsmElState(state); }
    );
  }

  ngOnDestroy(): void {
    this.logger.debug("EntExpRsmElDirective", "ngOnDestroy", "Start");
    this.commToRsmElTitle.unsubscribe();
    this.logger.debug("EntExpRsmElDirective", "ngOnDestroy", "Finish");
  }

  private consumeRsmElState(state: RsmElState): void {
    this.logger.debug("EntExpRsmElDirective", "consumeRsmElState", `Start - state: ${state}`);
    if (state == RsmElState.SHOWN)
      this.showDirective();
    else if (state == RsmElState.NOT_SHOWN)
      this.doNotShowDirective();
    this.logger.debug("EntExpRsmElDirective", "consumeRsmElState", "Finish");
  }

  protected doNotShowDirective(): void {
    this.logger.debug("EntExpRsmElDirective", "doNotShowDirective", "Start");
    super.doNotShowDirective();
    this.logger.debug("EntExpRsmElDirective", "doNotShowDirective", "Finish");
  }

  protected showDirective(): void {
    this.logger.debug("EntExpRsmElDirective", "showDirective", "Start");
    super.showDirective();
    this.logger.debug("EntExpRsmElDirective", "doNotShowDirective", "Finish");
  }

}
<file_sep>/frontend/src/app/reusable-services/rsm-el-title-to-rsm-el-comm.service.ts
import { Observable, Subject } from 'rxjs';

import { RsmElState } from "../reusable-enums/rsm-el-state";

export class RsmElTitleToRsmElCommService {

  public rsmElTitleToRsmEl: Observable<RsmElState>;
  private rsmElTitleToRsmElSource: Subject<RsmElState>;

  constructor() {
    this.rsmElTitleToRsmElSource = new Subject<RsmElState>();
    this.rsmElTitleToRsmEl = this.rsmElTitleToRsmElSource.asObservable();
  }

  public showRsmEl(): void {
    this.rsmElTitleToRsmElSource.next(RsmElState.SHOWN);
  }

  public doNotShowRsmEl(): void {
    this.rsmElTitleToRsmElSource.next(RsmElState.NOT_SHOWN);
  }
}
<file_sep>/frontend/src/app/enterprise-experience/rsm-el-title-to-rsm-el-titles-comm.service.ts
import { Injectable } from '@angular/core';

import { RsmElTitleToRsmElTitlesCommService } from "../reusable-services/rsm-el-title-to-rsm-el-titles-comm.service";

@Injectable({
  providedIn: 'root'
})
export class EntExpRsmElTitleToRsmElTitlesCommService extends RsmElTitleToRsmElTitlesCommService {
  
}
<file_sep>/frontend/src/app/enterprise-experience/software-tool.spec.ts
import { SoftwareTool } from './software-tool';

describe('SoftwareTool', () => {
  it('should create an instance', () => {
    expect(new SoftwareTool()).toBeTruthy();
  });
});
<file_sep>/frontend/src/environments/environment.test.ts
export const environment = {
  event: {
    pressed_delay: 10,
    rendered_delay: 10
  },
  logger: {
    debug: false
  },
  production: false
};<file_sep>/frontend/src/app/enterprise-experience/enterprise-experience.component.ts
import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

import { Position } from "./position";
import { POSITIONS } from "./mock-positions";

@Component({
  selector: 'app-enterprise-experience',
  templateUrl: './enterprise-experience.component.html',
  styleUrls: ['./enterprise-experience.component.sass']
})
export class EnterpriseExperienceComponent implements OnInit {

  title: String;
  positions: Position[];

  constructor(private sanitizer: DomSanitizer) {
    this.title = "Enterprise Experience";
    this.positions = POSITIONS;
  }

  ngOnInit(): void {
  }

  pngSrcFromBase64(base64Val: string): SafeResourceUrl {
    return this.sanitizer.bypassSecurityTrustResourceUrl(
      'data:image/png;base64,' + base64Val
    )
  }

}
<file_sep>/frontend/src/app/portfolio/rsm-el-title.directive.ts
import { Directive, ElementRef, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

import { AbtMeRsmElTitleToRsmElTitlesCommService } from "../about-me/rsm-el-title-to-rsm-el-titles-comm.service";
import { ContactInfoRsmElTitleToRsmElTitlesCommService } from "../contact-info/rsm-el-title-to-rsm-el-titles-comm.service";
import { EducationRsmElTitleToRsmElTitlesCommService } from "../education/rsm-el-title-to-rsm-el-titles-comm.service";
import { EntExpRsmElTitleToRsmElTitlesCommService } from "../enterprise-experience/rsm-el-title-to-rsm-el-titles-comm.service";
import { RsmElTitleDirective } from "../reusable-directives/rsm-el-title.directive";
import { PortfolioRsmElTitleToRsmElCommService } from "./rsm-el-title-to-rsm-el-comm.service";
import { PortfolioRsmElTitleToRsmElTitlesCommService } from "./rsm-el-title-to-rsm-el-titles-comm.service";

@Directive({
  selector: '[appPortfolioRsmElTitle]'
})
export class PortfolioRsmElTitleDirective extends RsmElTitleDirective implements OnDestroy {

  private commToAbtMeRsmElTitle: Subscription;
  private commToContactInfoRsmElTitle: Subscription;
  private commToEducationRsmElTitle: Subscription;
  private commToEntExpRsmElTitle: Subscription;

  constructor(
    el: ElementRef,
    private commToRsmElService: PortfolioRsmElTitleToRsmElCommService,
    private commToRsmElTitlesService: PortfolioRsmElTitleToRsmElTitlesCommService,
    private commToAbtMeRsmElTitleService: AbtMeRsmElTitleToRsmElTitlesCommService,
    private commToContactInfoRsmElTitleService: ContactInfoRsmElTitleToRsmElTitlesCommService,
    private commToEducationRsmElTitleService: EducationRsmElTitleToRsmElTitlesCommService,
    private commToEntExpRsmElTitleService: EntExpRsmElTitleToRsmElTitlesCommService
  ) {
    super(el);
    this.commToAbtMeRsmElTitle = this.commToAbtMeRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToContactInfoRsmElTitle = this.commToContactInfoRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToEducationRsmElTitle = this.commToEducationRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToEntExpRsmElTitle = this.commToEntExpRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
  }

  ngOnDestroy(): void {
    this.logger.debug("PortfolioRsmElTitleDirective", "ngOnDestroy", "Start");
    this.commToAbtMeRsmElTitle.unsubscribe();
    this.commToContactInfoRsmElTitle.unsubscribe();
    this.commToEducationRsmElTitle.unsubscribe();
    this.commToEntExpRsmElTitle.unsubscribe();
    this.logger.debug("PortfolioRsmElTitleDirective", "ngOnDestroy", "Finish");
  }

  protected consumeEventFromRsmElTitle(): void {
    this.logger.debug("PortfolioRsmElTitleDirective", "consumeEventFromRsmElTitle", "Start");
    this.commToRsmElService.doNotShowRsmEl();
    this.logger.debug("PortfolioRsmElTitleDirective", "consumeEventFromRsmElTitle", "Finish");
  }

  protected showPressed() {
    this.logger.debug("PortfolioRsmElTitleDirective", "showPressed", "Start");
    super.showPressed();
    this.logger.debug("PortfolioRsmElTitleDirective", "showPressed", "Finish");
  }

  protected showNonPressed() {
    this.logger.debug("PortfolioRsmElTitleDirective", "showNonPressed", "Start");
    super.showNonPressed();
    this.commToRsmElService.showRsmEl();
    this.commToRsmElTitlesService.doNotShowRsmEl();
    this.logger.debug("PortfolioRsmElTitleDirective", "showNonPressed", "Finish");
  }

}
<file_sep>/frontend/src/app/education/rsm-el-title.directive.ts
import { Directive, ElementRef, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

import { AbtMeRsmElTitleToRsmElTitlesCommService } from "../about-me/rsm-el-title-to-rsm-el-titles-comm.service";
import { ContactInfoRsmElTitleToRsmElTitlesCommService } from "../contact-info/rsm-el-title-to-rsm-el-titles-comm.service";
import { EntExpRsmElTitleToRsmElTitlesCommService } from "../enterprise-experience/rsm-el-title-to-rsm-el-titles-comm.service";
import { PortfolioRsmElTitleToRsmElTitlesCommService } from "../portfolio/rsm-el-title-to-rsm-el-titles-comm.service";
import { RsmElTitleDirective } from "../reusable-directives/rsm-el-title.directive";
import { EducationRsmElTitleToRsmElCommService } from "./rsm-el-title-to-rsm-el-comm.service";
import { EducationRsmElTitleToRsmElTitlesCommService } from "./rsm-el-title-to-rsm-el-titles-comm.service";

@Directive({
  selector: '[appEducationRsmElTitle]'
})
export class EducationRsmElTitleDirective extends RsmElTitleDirective implements OnDestroy {

  private commToAbtMeRsmElTitle: Subscription;
  private commToContactInfoRsmElTitle: Subscription;
  private commToEntExpRsmElTitle: Subscription;
  private commToPortfolioRsmElTitle: Subscription;

  constructor(
    el: ElementRef,
    private commToRsmElService: EducationRsmElTitleToRsmElCommService,
    private commToRsmElTitlesService: EducationRsmElTitleToRsmElTitlesCommService,
    private commToAbtMeRsmElTitleService: AbtMeRsmElTitleToRsmElTitlesCommService,
    private commToContactInfoRsmElTitleService: ContactInfoRsmElTitleToRsmElTitlesCommService,
    private commToEntExpRsmElTitleService: EntExpRsmElTitleToRsmElTitlesCommService,
    private commToPortfolioRsmElTitleService: PortfolioRsmElTitleToRsmElTitlesCommService
  ) {
    super(el);
    this.commToAbtMeRsmElTitle = this.commToAbtMeRsmElTitleService.rsmElTitleToRsmElTitles
      .subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToContactInfoRsmElTitle = this.commToContactInfoRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToEntExpRsmElTitle = this.commToEntExpRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
    this.commToPortfolioRsmElTitle = this.commToPortfolioRsmElTitleService
      .rsmElTitleToRsmElTitles.subscribe(() => { this.consumeEventFromRsmElTitle(); });
  }

  ngOnDestroy(): void {
    this.logger.debug("EducationRsmElTitleDirective", "ngOnDestroy", "Start");
    this.commToAbtMeRsmElTitle.unsubscribe();
    this.commToContactInfoRsmElTitle.unsubscribe();
    this.commToEntExpRsmElTitle.unsubscribe();
    this.commToPortfolioRsmElTitle.unsubscribe();
    this.logger.debug("EducationRsmElTitleDirective", "ngOnDestroy", "Finish");
  }

  protected consumeEventFromRsmElTitle(): void {
    this.logger.debug("EducationRsmElTitleDirective", "consumeEventFromRsmElTitle", "Start");
    this.commToRsmElService.doNotShowRsmEl();
    this.logger.debug("EducationRsmElTitleDirective", "consumeEventFromRsmElTitle", "Finish");
  }

  protected showPressed() {
    this.logger.debug("EducationRsmElTitleDirective", "showPressed", "Start");
    super.showPressed();
    this.logger.debug("EducationRsmElTitleDirective", "showPressed", "Finish");
  }

  protected showNonPressed() {
    this.logger.debug("EducationRsmElTitleDirective", "showNonPressed", "Start");
    super.showNonPressed();
    this.commToRsmElService.showRsmEl();
    this.commToRsmElTitlesService.doNotShowRsmEl();
    this.logger.debug("EducationRsmElTitleDirective", "showNonPressed", "Finish");
  }

}
<file_sep>/frontend/src/app/about-me/about-me.component.ts
import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

import { Icon } from "./icon";
import { PROFILE } from "./mock-profile";

@Component({
  selector: 'app-about-me',
  templateUrl: './about-me.component.html',
  styleUrls: ['./about-me.component.sass']
})
export class AboutMeComponent implements OnInit {

  title: String;
  profile: Icon;
  
  constructor(private sanitizer: DomSanitizer) {
    this.title = "About Me";
    this.profile = PROFILE;
  }

  ngOnInit(): void {
  }

  pngSrcFromBase64(base64Val: string): SafeResourceUrl {
    return this.sanitizer.bypassSecurityTrustResourceUrl(
      'data:image/png;base64,' + base64Val
    )
  }

}
<file_sep>/frontend/src/app/reusable-services/rsm-el-title-to-rsm-el-titles-comm.service.ts
import { Observable, Subject } from 'rxjs';

export class RsmElTitleToRsmElTitlesCommService {

  public rsmElTitleToRsmElTitles: Observable<void>;
  private rsmElTitleToRsmElTitlesSource: Subject<void>;

  constructor() {
    this.rsmElTitleToRsmElTitlesSource = new Subject<void>();
    this.rsmElTitleToRsmElTitles = this.rsmElTitleToRsmElTitlesSource.asObservable();
  }

  public doNotShowRsmEl(): void {
    this.rsmElTitleToRsmElTitlesSource.next();
  }
}
<file_sep>/frontend/src/app/about-me/icon.ts
import { ImageAbs } from "../reusable-classes/image-abs";

export class Icon extends ImageAbs {

  constructor(src: string, alt: string) {
    super(src, alt);
  }
}
<file_sep>/frontend/src/app/app.module.ts
import { Injector, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { AboutMeComponent } from './about-me/about-me.component';
import { AbtMeRsmElDirective } from './about-me/rsm-el.directive';
import { AbtMeRsmElTitleDirective } from './about-me/rsm-el-title.directive';

import { ContactInfoComponent } from './contact-info/contact-info.component';
import { ContactInfoRsmElDirective } from './contact-info/rsm-el.directive';
import { ContactInfoRsmElTitleDirective } from './contact-info/rsm-el-title.directive';

import { EducationComponent } from './education/education.component';
import { EducationRsmElDirective } from './education/rsm-el.directive';
import { EducationRsmElTitleDirective } from './education/rsm-el-title.directive';

import { EnterpriseExperienceComponent } from './enterprise-experience/enterprise-experience.component';
import { EntExpRsmElTitleDirective } from './enterprise-experience/rsm-el-title.directive';
import { EntExpRsmElDirective } from './enterprise-experience/rsm-el.directive';

import { PortfolioComponent } from './portfolio/portfolio.component';
import { PortfolioRsmElTitleDirective } from './portfolio/rsm-el-title.directive';
import { PortfolioRsmElDirective } from './portfolio/rsm-el.directive';

@NgModule({
  declarations: [
    AppComponent,
    AboutMeComponent,
    AbtMeRsmElDirective,
    AbtMeRsmElTitleDirective,
    ContactInfoComponent,
    ContactInfoRsmElDirective,
    ContactInfoRsmElTitleDirective,
    EducationComponent,
    EducationRsmElTitleDirective,
    EducationRsmElDirective,
    EnterpriseExperienceComponent,
    EntExpRsmElTitleDirective,
    EntExpRsmElDirective,
    PortfolioComponent,
    PortfolioRsmElTitleDirective,
    PortfolioRsmElDirective
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
  static injector: Injector;
  constructor(injector: Injector) {
    AppModule.injector = injector;
  }
}
<file_sep>/frontend/src/app/contact-info/mock-chips.ts
import { Icon } from "./icon";

import { Chip } from "./chip";

export const CHIPS: Chip[] = [
  new Chip(
    '<KEY>
    "LinkedIn icon",
    "https://www.linkedin.com/in/maxim-ch/",
    "LinkedIn"
  ),
  new Chip(
    '<KEY>NsV<KEY>
    "Gmail icon",
    "",
    "<EMAIL>"
  )
]<file_sep>/frontend/src/app/contact-info/contact-info.component.ts
import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

import { Chip } from "./chip";

import { CHIPS } from "./mock-chips";

@Component({
  selector: 'app-contact-info',
  templateUrl: './contact-info.component.html',
  styleUrls: ['./contact-info.component.sass']
})
export class ContactInfoComponent implements OnInit {

  title: String;
  chips: Chip[];

  constructor(private sanitizer: DomSanitizer) {
    this.title = "Contact Details";
    this.chips = CHIPS;
  }

  ngOnInit(): void {
  }

  pngSrcFromBase64(base64Val: string): SafeResourceUrl {
    return this.sanitizer.bypassSecurityTrustResourceUrl(
      'data:image/png;base64,' + base64Val
    )
  }

}
<file_sep>/frontend/src/app/contact-info/rsm-el-title-to-rsm-el-comm.service.ts
import { Injectable } from '@angular/core';

import { RsmElTitleToRsmElCommService } from "../reusable-services/rsm-el-title-to-rsm-el-comm.service";

@Injectable({
  providedIn: 'root'
})
export class ContactInfoRsmElTitleToRsmElCommService extends RsmElTitleToRsmElCommService {
  
}
<file_sep>/frontend/src/app/portfolio/portfolio.component.spec.ts
import { DebugNode } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { environment } from "../../environments/environment";
import { AppModule } from "../app.module";
import { PortfolioComponent } from "./portfolio.component";
import { PortfolioRsmElDirective } from './rsm-el.directive';
import { PortfolioRsmElTitleDirective } from './rsm-el-title.directive';

describe('PortfolioComponent', () => {
  let component: PortfolioComponent;
  let fixture: ComponentFixture<PortfolioComponent>;
  let portfolioRsmElTitleDirectiveQueryResponse: DebugNode[];
  let portfolioRsmElDirectiveQueryResponse: DebugNode[];

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ PortfolioComponent, PortfolioRsmElDirective, PortfolioRsmElTitleDirective ],
      imports: [ AppModule ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(PortfolioComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    portfolioRsmElTitleDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(PortfolioRsmElTitleDirective)
    );
    portfolioRsmElDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(PortfolioRsmElDirective)
    )
  });

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

  it("should have as title \"Portfolio\"", () => {
    expect(component.title).toEqual('Portfolio');
  });

  it("should contain the directives", () => {
    expect(portfolioRsmElTitleDirectiveQueryResponse).toHaveSize(1);
    expect(portfolioRsmElDirectiveQueryResponse).toHaveSize(1);
  });

  it("should render the PortfolioRsmElTitleDirective with default style", () => {
    let directive: DebugNode = portfolioRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    expect(el.innerHTML).toContain("Portfolio");
    expect(el.classList).toContain("rsm-el-title");
  });

  it("should show PortfolioRsmElTitleDirective as pressed when touch starts", () => {
    let directive: DebugNode = portfolioRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    el.dispatchEvent(new Event("touchstart"));
    expect(el.classList).toContain("pressed");
  });

  it(
    "should show PortfolioRsmElTitleDirective as non pressed when touch ends",
    (done) => {
      let directive: DebugNode = portfolioRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      setTimeout(() => {
        expect(el.classList).not.toContain("pressed");
        done();
      }, environment.event.rendered_delay);
    }
  );

  it(
    "should show PortfolioRsmElDirective when PortfolioRsmElTitleDirective touch ends",
    (done) => {
      let directive: DebugNode = portfolioRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      directive = portfolioRsmElDirectiveQueryResponse[0];
      el = directive.nativeNode;
      setTimeout(() => {
        expect(el.classList).toContain("rsm-el-shown");
        expect(el.classList).not.toContain("rsm-el-not-shown");
        done();
      }, environment.event.rendered_delay);
    }
  );
});
<file_sep>/frontend/src/app/enterprise-experience/mock-positions.ts
import { Position } from "./position";
import { TOOLS } from "./mock-sw-tools";

export const POSITIONS: Position[] = [
  new Position(
    "2020",
    "Present",
    "IBM - SaaS QA Automation Engineer",
    [
      "Automation Framework Backend Maintenance",
      "Automation Framework Frontend Maintenance",
      "Automation Workers Management",
      "Features Development for Automation Framework"
    ],
    TOOLS
  ),
  new Position(
    "2017",
    "2020",
    "IBM - SaaS QA Student Position",
    [
      "Backend API testing",
      "Prediction Algorithms testing",
      "Frontend features testing",
      "Contributing automated tests to Regression"
    ],
    []
  )
]<file_sep>/frontend/src/app/reusable-enums/rsm-el-state.ts
export enum RsmElState {
  NOT_SHOWN,
  SHOWN
}
<file_sep>/frontend/src/app/enterprise-experience/position.ts
import { SoftwareTool } from "./software-tool";

export class Position {
  
  end: String
  responsibilities: String[];
  start: String
  softwareTools: SoftwareTool[];
  title: String;

  constructor(
    start: String,
    end: String,
    title: String,
    responsibilities: String[],
    softwareTools: SoftwareTool[]
  ) {
      this.start = start;
      this.end = end;
      this.title = title;
      this.responsibilities = responsibilities;
      this.softwareTools = softwareTools;
  }

  public hasResponsibilities(): Boolean {
    return this.responsibilities.length > 0;
  }

  public hasSoftwareTools(): Boolean {
    return this.softwareTools.length > 0;
  }

}<file_sep>/frontend/src/app/about-me/about-me.component.spec.ts
import { DebugNode } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { environment } from "../../environments/environment";
import { AppModule } from "../app.module";
import { AboutMeComponent } from "./about-me.component";
import { AbtMeRsmElDirective } from './rsm-el.directive';
import { AbtMeRsmElTitleDirective } from './rsm-el-title.directive';

describe('AboutMeComponent', () => {
  let component: AboutMeComponent;
  let fixture: ComponentFixture<AboutMeComponent>;
  let abtMeRsmElTitleDirectiveQueryResponse: DebugNode[];
  let abtMeRsmElDirectiveQueryResponse: DebugNode[];

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ AboutMeComponent, AbtMeRsmElTitleDirective, AbtMeRsmElDirective ],
      imports: [ AppModule ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AboutMeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    abtMeRsmElTitleDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(AbtMeRsmElTitleDirective)
    );
    abtMeRsmElDirectiveQueryResponse = fixture.debugElement.queryAll(
      By.directive(AbtMeRsmElDirective)
    )
  });

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

  it("should have as title \"About Me\"", () => {
    expect(component.title).toEqual('About Me');
  });
  
  it("should contain the directives", () => {
    expect(abtMeRsmElTitleDirectiveQueryResponse).toHaveSize(1);
    expect(abtMeRsmElDirectiveQueryResponse).toHaveSize(1);
  });

  it("should render the AbtMeRsmElTitleDirective with default style", () => {
    let directive: DebugNode = abtMeRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    expect(el.innerHTML).toContain("About Me");
    expect(el.classList).toContain("rsm-el-title");
  });

  it("should show AbtMeRsmElTitleDirective as pressed when touch starts", () => {
    let directive: DebugNode = abtMeRsmElTitleDirectiveQueryResponse[0];
    let el: HTMLElement = directive.nativeNode;
    el.dispatchEvent(new Event("touchstart"));
    expect(el.classList).toContain("pressed");
  });

  it(
    "should show AbtMeRsmElTitleDirective as non pressed when touch ends",
    (done) => {
      let directive: DebugNode = abtMeRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      setTimeout(() => {
        expect(el.classList).not.toContain("pressed");
        done();
      }, environment.event.rendered_delay);
    }
  );

  it(
    "should show AbtMeRsmElDirective when AbtMeRsmElTitleDirective touch ends",
    (done) => {
      let directive: DebugNode = abtMeRsmElTitleDirectiveQueryResponse[0];
      let el: HTMLElement = directive.nativeNode;
      el.dispatchEvent(new Event("touchstart"));
      el.dispatchEvent(new Event("touchend"));
      directive = abtMeRsmElDirectiveQueryResponse[0];
      el = directive.nativeNode;
      setTimeout(() => {
        expect(el.classList).toContain("rsm-el-shown");
        expect(el.classList).not.toContain("rsm-el-not-shown");
        done();
      }, environment.event.rendered_delay);
    }
  );
});
