tfjs-evolution 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -52,7 +52,7 @@ Make the call for loading images. You could most likely make the call at the con
52
52
  ```typescript
53
53
  ngAfterViewInit(): void {
54
54
  const options={
55
- base: "./assets/dataset",//base where are you iamges
55
+ base: "./assets/dataset",//base where are your iamges
56
56
  file_name:"image",//how your images are named
57
57
  file_extension:"jpeg" //extension used
58
58
  };
@@ -72,6 +72,11 @@ Finally, do not forget to add the HTML code
72
72
 
73
73
  You should see in our HTML file, in Angular, the images
74
74
 
75
+
76
+ # Updates
77
+
78
+ I have finished! Hope to publish a paper soon!
79
+
75
80
  # Further help
76
81
 
77
82
  Feel free to get in touch: jorgeguerrabrazil@gmail.com
@@ -1,5 +1,6 @@
1
1
  import { Component } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
+ import { TeachableMobileNet } from '../../models/teachable-evolution';
3
4
  import * as i0 from "@angular/core";
4
5
  import * as i1 from "@angular/common";
5
6
  export class DisplayPanelComponent {
@@ -8,6 +9,7 @@ export class DisplayPanelComponent {
8
9
  }
9
10
  loadImages(number_of_species, classes_names, options) {
10
11
  this.classes_names = classes_names;
12
+ this.number_of_samples_per_class = number_of_species;
11
13
  this.add_species(number_of_species, options);
12
14
  }
13
15
  add_species(number_of_species, options) {
@@ -17,16 +19,41 @@ export class DisplayPanelComponent {
17
19
  }
18
20
  add_images(name, number_of_species, options) {
19
21
  const class_add = [];
20
- for (let i = 1; i < number_of_species; i++) {
21
- class_add.push(`${options.base}/${name}/${options.file_name} ${i}.${options.file_extension}`);
22
+ for (let i = 0; i < number_of_species; i++) {
23
+ class_add.push(`${options.base}/${name}/${options.file_name} ${i + 1}.${options.file_extension}`);
22
24
  }
23
25
  this.classes.push({ name: name, images: class_add });
24
26
  }
27
+ async addexamples() {
28
+ //This is needed to make sure it gives time for the images to upload
29
+ //The images upload very fast, what makes this method execute before the images are on HTML
30
+ //It can be removed if somehow this method is just called after the images are available.
31
+ // console.log("Loading examples as tensors....")
32
+ await this.delay(0);
33
+ for (let i = 0; i < this.classes_names.length; i++) {
34
+ await this.add_example(this.classes_names[i], this.number_of_samples_per_class);
35
+ }
36
+ }
37
+ async add_example(name, number_of_species) {
38
+ const class_add = [];
39
+ // console.log(name)
40
+ for (let i = 0; i < number_of_species; i++) {
41
+ //Collecting the images from HTML
42
+ const aux = document.getElementById(`class-${name}-${i}`);
43
+ //Adding the example
44
+ const index = this.classes_names.findIndex((elem) => elem === name);
45
+ await TeachableMobileNet.addExample(index, name, aux);
46
+ }
47
+ // this.classes.push({name: name, images: class_add})
48
+ }
49
+ delay(ms) {
50
+ return new Promise((resolve) => setTimeout(resolve, ms));
51
+ }
25
52
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: DisplayPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: DisplayPanelComponent, isStandalone: true, selector: "neuroevolution-display-panel", ngImport: i0, template: "<div *ngFor=\"let class of classes; index as i\">\r\n <h1>{{class.name}}</h1>\r\n <img *ngFor=\"let item of class.images; index as i\" [src]=\"item\" width=\"10%\" height=\"10%\" [id]=\"'class-1-' + i\" crossorigin=\"anonymous\" >\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); }
53
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: DisplayPanelComponent, isStandalone: true, selector: "neuroevolution-display-panel", ngImport: i0, template: "<div *ngFor=\"let class of classes; index as i\">\r\n <h1>{{class.name}}</h1>\r\n <img *ngFor=\"let item of class.images; index as i\" [src]=\"item\" width=\"224\" height=\"224\" [id]=\"'class-' + class.name + '-' + i\" crossorigin=\"anonymous\" >\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); }
27
54
  }
28
55
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: DisplayPanelComponent, decorators: [{
29
56
  type: Component,
30
- args: [{ selector: 'neuroevolution-display-panel', standalone: true, imports: [CommonModule], template: "<div *ngFor=\"let class of classes; index as i\">\r\n <h1>{{class.name}}</h1>\r\n <img *ngFor=\"let item of class.images; index as i\" [src]=\"item\" width=\"10%\" height=\"10%\" [id]=\"'class-1-' + i\" crossorigin=\"anonymous\" >\r\n</div>\r\n" }]
57
+ args: [{ selector: 'neuroevolution-display-panel', standalone: true, imports: [CommonModule], template: "<div *ngFor=\"let class of classes; index as i\">\r\n <h1>{{class.name}}</h1>\r\n <img *ngFor=\"let item of class.images; index as i\" [src]=\"item\" width=\"224\" height=\"224\" [id]=\"'class-' + class.name + '-' + i\" crossorigin=\"anonymous\" >\r\n</div>\r\n" }]
31
58
  }] });
32
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzcGxheS1wYW5lbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90ZmpzLWV2b2x1dGlvbi9zcmMvbGliL2NvbXBvbmVudHMvZGlzcGxheS1wYW5lbC9kaXNwbGF5LXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3RmanMtZXZvbHV0aW9uL3NyYy9saWIvY29tcG9uZW50cy9kaXNwbGF5LXBhbmVsL2Rpc3BsYXktcGFuZWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7OztBQVMvQyxNQUFNLE9BQU8scUJBQXFCO0lBUGxDO1FBU0UsWUFBTyxHQUFVLEVBQUUsQ0FBQztLQThCckI7SUExQkMsVUFBVSxDQUFDLGlCQUF5QixFQUFFLGFBQXVCLEVBQUUsT0FBZTtRQUM1RSxJQUFJLENBQUMsYUFBYSxHQUFDLGFBQWEsQ0FBQztRQUVqQyxJQUFJLENBQUMsV0FBVyxDQUFDLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFHRCxXQUFXLENBQUMsaUJBQXlCLEVBQUUsT0FBZTtRQUVwRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDbEQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1NBQ3BFO0lBQ0gsQ0FBQztJQUVELFVBQVUsQ0FBQyxJQUFZLEVBQUUsaUJBQXlCLEVBQUUsT0FBWTtRQUU5RCxNQUFNLFNBQVMsR0FBTyxFQUFFLENBQUM7UUFFekIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGlCQUFpQixFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsSUFBSSxJQUFJLElBQUksSUFBSSxPQUFPLENBQUMsU0FBUyxJQUFJLENBQUMsSUFBSSxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQztTQUNqRztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFDLENBQUMsQ0FBQTtJQUVsRCxDQUFDOzhHQTlCVSxxQkFBcUI7a0dBQXJCLHFCQUFxQix3RkNYbEMseVBBSUEseURER1ksWUFBWTs7MkZBSVgscUJBQXFCO2tCQVBqQyxTQUFTOytCQUNFLDhCQUE4QixjQUM1QixJQUFJLFdBQ1AsQ0FBQyxZQUFZLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnR9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBHcm91cCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMvZ3JvdXAnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZXVyb2V2b2x1dGlvbi1kaXNwbGF5LXBhbmVsJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9kaXNwbGF5LXBhbmVsLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vZGlzcGxheS1wYW5lbC5jb21wb25lbnQuY3NzJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgRGlzcGxheVBhbmVsQ29tcG9uZW50IHtcclxuXHJcbiAgY2xhc3NlczogR3JvdXBbXT1bXTtcclxuXHJcbiAgY2xhc3Nlc19uYW1lcyE6IHN0cmluZ1tdO1xyXG5cclxuICBsb2FkSW1hZ2VzKG51bWJlcl9vZl9zcGVjaWVzOiBudW1iZXIsIGNsYXNzZXNfbmFtZXM6IHN0cmluZ1tdLCBvcHRpb25zOiBvYmplY3Qpe1xyXG4gICAgdGhpcy5jbGFzc2VzX25hbWVzPWNsYXNzZXNfbmFtZXM7XHJcblxyXG4gICAgdGhpcy5hZGRfc3BlY2llcyhudW1iZXJfb2Zfc3BlY2llcywgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuXHJcbiAgYWRkX3NwZWNpZXMobnVtYmVyX29mX3NwZWNpZXM6IG51bWJlciwgb3B0aW9uczogb2JqZWN0KXtcclxuXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY2xhc3Nlc19uYW1lcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB0aGlzLmFkZF9pbWFnZXModGhpcy5jbGFzc2VzX25hbWVzW2ldLCBudW1iZXJfb2Zfc3BlY2llcywgb3B0aW9ucyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhZGRfaW1hZ2VzKG5hbWU6IHN0cmluZywgbnVtYmVyX29mX3NwZWNpZXM6IG51bWJlciwgb3B0aW9uczogYW55KXsgICBcclxuXHJcbiAgICBjb25zdCBjbGFzc19hZGQ6IGFueT0gW107XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCBudW1iZXJfb2Zfc3BlY2llczsgaSsrKSB7ICAgICAgXHJcbiAgICAgIGNsYXNzX2FkZC5wdXNoKGAke29wdGlvbnMuYmFzZX0vJHtuYW1lfS8ke29wdGlvbnMuZmlsZV9uYW1lfSAke2l9LiR7b3B0aW9ucy5maWxlX2V4dGVuc2lvbn1gKTtcclxuICB9XHJcblxyXG4gIHRoaXMuY2xhc3Nlcy5wdXNoKHtuYW1lOiBuYW1lLCBpbWFnZXM6IGNsYXNzX2FkZH0pICBcclxuXHJcbiAgfVxyXG5cclxufVxyXG4iLCI8ZGl2ICpuZ0Zvcj1cImxldCBjbGFzcyBvZiBjbGFzc2VzOyBpbmRleCBhcyBpXCI+XHJcbiAgPGgxPnt7Y2xhc3MubmFtZX19PC9oMT5cclxuICA8aW1nICAqbmdGb3I9XCJsZXQgaXRlbSBvZiBjbGFzcy5pbWFnZXM7IGluZGV4IGFzIGlcIiBbc3JjXT1cIml0ZW1cIiB3aWR0aD1cIjEwJVwiIGhlaWdodD1cIjEwJVwiIFtpZF09XCInY2xhc3MtMS0nICsgaVwiIGNyb3Nzb3JpZ2luPVwiYW5vbnltb3VzXCIgPlxyXG48L2Rpdj5cclxuIl19
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzcGxheS1wYW5lbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy90ZmpzLWV2b2x1dGlvbi9zcmMvbGliL2NvbXBvbmVudHMvZGlzcGxheS1wYW5lbC9kaXNwbGF5LXBhbmVsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3RmanMtZXZvbHV0aW9uL3NyYy9saWIvY29tcG9uZW50cy9kaXNwbGF5LXBhbmVsL2Rpc3BsYXktcGFuZWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7OztBQVN0RSxNQUFNLE9BQU8scUJBQXFCO0lBUGxDO1FBU0UsWUFBTyxHQUFVLEVBQUUsQ0FBQztLQXlFckI7SUFuRUQsVUFBVSxDQUFDLGlCQUF5QixFQUFFLGFBQXVCLEVBQUUsT0FBZTtRQUUxRSxJQUFJLENBQUMsYUFBYSxHQUFDLGFBQWEsQ0FBQztRQUNqQyxJQUFJLENBQUMsMkJBQTJCLEdBQUMsaUJBQWlCLENBQUM7UUFFbkQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUUvQyxDQUFDO0lBR0gsV0FBVyxDQUFDLGlCQUF5QixFQUFFLE9BQWU7UUFFbEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ2xELElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQztTQUVwRTtJQUVILENBQUM7SUFFRCxVQUFVLENBQUMsSUFBWSxFQUFFLGlCQUF5QixFQUFFLE9BQVk7UUFFOUQsTUFBTSxTQUFTLEdBQU8sRUFBRSxDQUFDO1FBRXpCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxpQkFBaUIsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMxQyxTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxJQUFJLElBQUksT0FBTyxDQUFDLFNBQVMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1NBQ25HO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUMsQ0FBQyxDQUFBO0lBRWxELENBQUM7SUFFRixLQUFLLENBQUMsV0FBVztRQUVoQixvRUFBb0U7UUFDcEUsMkZBQTJGO1FBQzNGLHlGQUF5RjtRQUN6RixpREFBaUQ7UUFDakQsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXBCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNsRCxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQztTQUNqRjtJQUNELENBQUM7SUFFRCxLQUFLLENBQUMsV0FBVyxDQUFDLElBQVksRUFBRSxpQkFBeUI7UUFFdkQsTUFBTSxTQUFTLEdBQU8sRUFBRSxDQUFDO1FBQ3pCLG9CQUFvQjtRQUNwQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFFMUMsaUNBQWlDO1lBQ2pDLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQXFCLENBQUM7WUFFOUUsb0JBQW9CO1lBQ3BCLE1BQU0sS0FBSyxHQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFDLEVBQUUsQ0FBQSxJQUFJLEtBQUcsSUFBSSxDQUFDLENBQUE7WUFFOUQsTUFBTSxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztTQUV6RDtRQUVELHVEQUF1RDtJQUV2RCxDQUFDO0lBRUQsS0FBSyxDQUFDLEVBQVU7UUFDZCxPQUFPLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbkUsQ0FBQzs4R0ExRVkscUJBQXFCO2tHQUFyQixxQkFBcUIsd0ZDWmxDLDBRQUlBLHlERElZLFlBQVk7OzJGQUlYLHFCQUFxQjtrQkFQakMsU0FBUzsrQkFDRSw4QkFBOEIsY0FDNUIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50fSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgR3JvdXAgfSBmcm9tICcuLi8uLi9pbnRlcmZhY2VzL2dyb3VwJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgVGVhY2hhYmxlTW9iaWxlTmV0IH0gZnJvbSAnLi4vLi4vbW9kZWxzL3RlYWNoYWJsZS1ldm9sdXRpb24nO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZXVyb2V2b2x1dGlvbi1kaXNwbGF5LXBhbmVsJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9kaXNwbGF5LXBhbmVsLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vZGlzcGxheS1wYW5lbC5jb21wb25lbnQuY3NzJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgRGlzcGxheVBhbmVsQ29tcG9uZW50IHtcclxuXHJcbiAgY2xhc3NlczogR3JvdXBbXT1bXTtcclxuXHJcbiAgY2xhc3Nlc19uYW1lcyE6IHN0cmluZ1tdO1xyXG5cclxuICBudW1iZXJfb2Zfc2FtcGxlc19wZXJfY2xhc3MhOiBudW1iZXI7XHJcblxyXG5sb2FkSW1hZ2VzKG51bWJlcl9vZl9zcGVjaWVzOiBudW1iZXIsIGNsYXNzZXNfbmFtZXM6IHN0cmluZ1tdLCBvcHRpb25zOiBvYmplY3Qpe1xyXG4gICAgXHJcbiAgICB0aGlzLmNsYXNzZXNfbmFtZXM9Y2xhc3Nlc19uYW1lcztcclxuICAgIHRoaXMubnVtYmVyX29mX3NhbXBsZXNfcGVyX2NsYXNzPW51bWJlcl9vZl9zcGVjaWVzO1xyXG5cclxuICAgIHRoaXMuYWRkX3NwZWNpZXMobnVtYmVyX29mX3NwZWNpZXMsIG9wdGlvbnMpOyAgICBcclxuXHJcbiAgfVxyXG5cclxuXHJcbmFkZF9zcGVjaWVzKG51bWJlcl9vZl9zcGVjaWVzOiBudW1iZXIsIG9wdGlvbnM6IG9iamVjdCl7XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmNsYXNzZXNfbmFtZXMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdGhpcy5hZGRfaW1hZ2VzKHRoaXMuY2xhc3Nlc19uYW1lc1tpXSwgbnVtYmVyX29mX3NwZWNpZXMsIG9wdGlvbnMpO1xyXG4gICAgICBcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICBhZGRfaW1hZ2VzKG5hbWU6IHN0cmluZywgbnVtYmVyX29mX3NwZWNpZXM6IG51bWJlciwgb3B0aW9uczogYW55KXsgICBcclxuXHJcbiAgICBjb25zdCBjbGFzc19hZGQ6IGFueT0gW107XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1iZXJfb2Zfc3BlY2llczsgaSsrKSB7ICAgICAgXHJcbiAgICAgIGNsYXNzX2FkZC5wdXNoKGAke29wdGlvbnMuYmFzZX0vJHtuYW1lfS8ke29wdGlvbnMuZmlsZV9uYW1lfSAke2krMX0uJHtvcHRpb25zLmZpbGVfZXh0ZW5zaW9ufWApO1xyXG4gIH1cclxuXHJcbiAgdGhpcy5jbGFzc2VzLnB1c2goe25hbWU6IG5hbWUsIGltYWdlczogY2xhc3NfYWRkfSkgIFxyXG5cclxuICB9XHJcblxyXG4gYXN5bmMgYWRkZXhhbXBsZXMoKXtcclxuXHJcbiAgLy9UaGlzIGlzIG5lZWRlZCB0byBtYWtlIHN1cmUgaXQgZ2l2ZXMgdGltZSBmb3IgdGhlIGltYWdlcyB0byB1cGxvYWRcclxuICAvL1RoZSBpbWFnZXMgdXBsb2FkIHZlcnkgZmFzdCwgd2hhdCBtYWtlcyB0aGlzIG1ldGhvZCBleGVjdXRlIGJlZm9yZSB0aGUgaW1hZ2VzIGFyZSBvbiBIVE1MXHJcbiAgLy9JdCBjYW4gYmUgcmVtb3ZlZCBpZiBzb21laG93IHRoaXMgbWV0aG9kIGlzIGp1c3QgY2FsbGVkIGFmdGVyIHRoZSBpbWFnZXMgYXJlIGF2YWlsYWJsZS5cclxuICAvLyBjb25zb2xlLmxvZyhcIkxvYWRpbmcgZXhhbXBsZXMgYXMgdGVuc29ycy4uLi5cIilcclxuICBhd2FpdCB0aGlzLmRlbGF5KDApO1xyXG5cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY2xhc3Nlc19uYW1lcy5sZW5ndGg7IGkrKykge1xyXG4gICAgYXdhaXQgdGhpcy5hZGRfZXhhbXBsZSh0aGlzLmNsYXNzZXNfbmFtZXNbaV0sIHRoaXMubnVtYmVyX29mX3NhbXBsZXNfcGVyX2NsYXNzKTtcclxuICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBhZGRfZXhhbXBsZShuYW1lOiBzdHJpbmcsIG51bWJlcl9vZl9zcGVjaWVzOiBudW1iZXIpeyAgIFxyXG5cclxuICAgIGNvbnN0IGNsYXNzX2FkZDogYW55PSBbXTtcclxuICAgIC8vIGNvbnNvbGUubG9nKG5hbWUpXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bWJlcl9vZl9zcGVjaWVzOyBpKyspIHsgXHJcbiAgICAgIFxyXG4gICAgICAvL0NvbGxlY3RpbmcgdGhlIGltYWdlcyBmcm9tIEhUTUxcclxuICAgICAgY29uc3QgYXV4ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoYGNsYXNzLSR7bmFtZX0tJHtpfWApIGFzIEhUTUxJbWFnZUVsZW1lbnQ7ICAgICAgXHJcblxyXG4gICAgICAvL0FkZGluZyB0aGUgZXhhbXBsZVxyXG4gICAgICBjb25zdCBpbmRleD0gdGhpcy5jbGFzc2VzX25hbWVzLmZpbmRJbmRleCgoZWxlbSk9PmVsZW09PT1uYW1lKVxyXG5cclxuICAgICAgYXdhaXQgVGVhY2hhYmxlTW9iaWxlTmV0LmFkZEV4YW1wbGUoaW5kZXgsIG5hbWUsIGF1eCk7ICAgIFxyXG4gICAgICBcclxuICB9XHJcblxyXG4gIC8vIHRoaXMuY2xhc3Nlcy5wdXNoKHtuYW1lOiBuYW1lLCBpbWFnZXM6IGNsYXNzX2FkZH0pICBcclxuXHJcbiAgfVxyXG5cclxuICBkZWxheShtczogbnVtYmVyKSB7XHJcbiAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcclxufVxyXG59XHJcbiIsIjxkaXYgKm5nRm9yPVwibGV0IGNsYXNzIG9mIGNsYXNzZXM7IGluZGV4IGFzIGlcIj5cclxuICA8aDE+e3tjbGFzcy5uYW1lfX08L2gxPlxyXG4gIDxpbWcgICpuZ0Zvcj1cImxldCBpdGVtIG9mIGNsYXNzLmltYWdlczsgaW5kZXggYXMgaVwiIFtzcmNdPVwiaXRlbVwiIHdpZHRoPVwiMjI0XCIgaGVpZ2h0PVwiMjI0XCIgW2lkXT1cIidjbGFzcy0nICsgY2xhc3MubmFtZSArICctJyArIGlcIiBjcm9zc29yaWdpbj1cImFub255bW91c1wiID5cclxuPC9kaXY+XHJcbiJdfQ==
@@ -0,0 +1,182 @@
1
+ import * as tf from '@tensorflow/tfjs';
2
+ export const IMAGE_SIZE = 224;
3
+ const DEFAULT_MOBILENET_VERSION = 2;
4
+ const DEFAULT_TRAINING_LAYER_V1 = 'conv_pw_13_relu';
5
+ const DEFAULT_TRAINING_LAYER_V2 = "out_relu";
6
+ const DEFAULT_ALPHA_V1_v2 = 0.35;
7
+ const DEFAULT_ALPHA_V1 = 0.25; //256
8
+ const DEFAULT_ALPHA_V2 = 0.5; //512
9
+ const DEFAULT_ALPHA_V3 = 0.75; //768 features
10
+ const DEFAULT_ALPHA_V4 = 1; //1024 features
11
+ const DEFAULT_ALPHA = 1; //1024 features
12
+ // v2: 0.35, 0.50, 0.75 or 1.00.
13
+ const isAlphaValid = (version, alpha) => {
14
+ if (version === 1) {
15
+ if (alpha !== 0.25 && alpha !== 0.5 && alpha !== 0.75 && alpha !== 1) {
16
+ console.warn("Invalid alpha. Options are: 0.25, 0.50, 0.75 or 1.00.");
17
+ console.log("Loading model with alpha: ", DEFAULT_ALPHA_V1.toFixed(2));
18
+ return DEFAULT_ALPHA_V1;
19
+ }
20
+ }
21
+ else {
22
+ if (alpha !== 0.35 && alpha !== 0.5 && alpha !== 0.75 && alpha !== 1) {
23
+ console.warn("Invalid alpha. Options are: 0.35, 0.50, 0.75 or 1.00.");
24
+ console.log("Loading model with alpha: ", DEFAULT_ALPHA_V2.toFixed(2));
25
+ return DEFAULT_ALPHA_V2;
26
+ }
27
+ }
28
+ return alpha;
29
+ };
30
+ const parseModelOptions = (options) => {
31
+ options = options || {};
32
+ if (options.checkpointUrl && options.trainingLayer) {
33
+ if (options.alpha || options.version) {
34
+ console.warn("Checkpoint URL passed to modelOptions, alpha options are ignored");
35
+ }
36
+ return [options.checkpointUrl, options.trainingLayer];
37
+ }
38
+ else {
39
+ options.version = options.version || DEFAULT_MOBILENET_VERSION;
40
+ if (options.version === 1) {
41
+ options.alpha = options.alpha || DEFAULT_ALPHA_V4;
42
+ options.alpha = isAlphaValid(options.version, options.alpha);
43
+ console.log(`Loading mobilenet ${options.version} and alpha ${options.alpha}`);
44
+ // exception is alpha o f 1 can only be 1.0
45
+ let alphaString = options.alpha.toFixed(2);
46
+ if (alphaString === "1.00") {
47
+ alphaString = "1.0";
48
+ }
49
+ console.log("Using the model: ");
50
+ return [
51
+ // tslint:disable-next-line:max-line-length
52
+ //They are loading MobileNet_v1
53
+ `https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_${alphaString}_${IMAGE_SIZE}/model.json`,
54
+ DEFAULT_TRAINING_LAYER_V1
55
+ ];
56
+ }
57
+ else if (options.version === 2) {
58
+ options.alpha = options.alpha || DEFAULT_ALPHA_V4;
59
+ options.alpha = isAlphaValid(options.version, options.alpha);
60
+ console.log(`Loading mobilenet ${options.version} and alpha ${options.alpha}`);
61
+ console.log(`Loading mobilenet ${options.version} and alpha ${options.alpha}`);
62
+ return [
63
+ // tslint:disable-next-line:max-line-length
64
+ `https://storage.googleapis.com/teachable-machine-models/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_${options.alpha.toFixed(2)}_${IMAGE_SIZE}_no_top/model.json`,
65
+ DEFAULT_TRAINING_LAYER_V2
66
+ ];
67
+ }
68
+ else {
69
+ throw new Error(`MobileNet V${options.version} doesn't exist`);
70
+ }
71
+ }
72
+ };
73
+ /**
74
+ * load the base mobilenet model
75
+ * @param modelOptions options determining what model to load
76
+ */
77
+ export async function loadTruncatedMobileNet(modelOptions) {
78
+ const [checkpointUrl, trainingLayer] = parseModelOptions(modelOptions);
79
+ const mobilenet = await tf.loadLayersModel(checkpointUrl);
80
+ if (modelOptions && modelOptions.version === 1) {
81
+ const layer = mobilenet.getLayer(trainingLayer);
82
+ const truncatedModel = tf.model({ inputs: mobilenet.inputs, outputs: layer.output });
83
+ console.log("Feature model loaded, memory: ", tf.memory().numBytes);
84
+ const model = tf.sequential();
85
+ model.add(truncatedModel);
86
+ model.add(tf.layers.flatten());
87
+ return model;
88
+ }
89
+ else {
90
+ const layer = mobilenet.getLayer(trainingLayer);
91
+ const truncatedModel = tf.model({ inputs: mobilenet.inputs, outputs: layer.output });
92
+ console.log("Feature model loaded, memory: ", tf.memory().numBytes);
93
+ const model = tf.sequential();
94
+ model.add(truncatedModel);
95
+ model.add(tf.layers.globalAveragePooling2d({})); // go from shape [7, 7, 1280] to [1280]
96
+ return model;
97
+ }
98
+ }
99
+ export class CustomMobileNet {
100
+ static getinputShape() {
101
+ /**truncatedModel is the base model, the model used to apply transfer learning */
102
+ const inputShape = this.truncatedModel.outputs[0].shape.slice(1); // [ 7 x 7 x 1280] (not sure about those dimensions)
103
+ // console.log("Input Shape(complete): ", this.truncatedModel.outputs[0].shape);
104
+ // console.log("Input Shape: ", inputShape);
105
+ const inputSize = tf.util.sizeFromShape(inputShape);
106
+ // console.log("Input Size: ", inputSize);
107
+ return inputSize;
108
+ }
109
+ static get EXPECTED_IMAGE_SIZE() {
110
+ return IMAGE_SIZE;
111
+ }
112
+ getMetadata() {
113
+ return this._metadata;
114
+ }
115
+ constructor() {
116
+ // this._metadata = fillMetadata(metadata);
117
+ //Loading the truncated model
118
+ // loadTruncatedMobileNet();
119
+ // this.loadFeatureModel();
120
+ }
121
+ static async loadFeatureModel() {
122
+ this.truncatedModel = await loadTruncatedMobileNet();
123
+ }
124
+ /**
125
+ * get the total number of classes existing within model
126
+ */
127
+ // getTotalClasses() {
128
+ // const output = this.model.output as SymbolicTensor;
129
+ // const totalClasses = output.shape[1];
130
+ // return totalClasses;
131
+ // }
132
+ /**
133
+ * get the model labels
134
+ */
135
+ getClassLabels() {
136
+ return this._metadata.labels;
137
+ }
138
+ /**
139
+ * Given an image element, makes a prediction through mobilenet returning the
140
+ * probabilities of the top K classes.
141
+ * @param image the image to classify
142
+ * @param maxPredictions the maximum number of classification predictions
143
+ */
144
+ // async predictTopK(image: ClassifierInputSource, maxPredictions = 10, flipped = false) {
145
+ // const croppedImage = cropTo(image, this._metadata.imageSize, flipped);
146
+ // const logits = tf.tidy(() => {
147
+ // const captured = capture(croppedImage, this._metadata.grayscale);
148
+ // return this.model.predict(captured);
149
+ // });
150
+ // // Convert logits to probabilities and class names.
151
+ // const classes = await getTopKClasses(this._metadata.labels, logits as tf.Tensor<tf.Rank>, maxPredictions);
152
+ // dispose(logits);
153
+ // return classes;
154
+ // }
155
+ /**
156
+ * Given an image element, makes a prediction through mobilenet returning the
157
+ * probabilities for ALL classes.
158
+ * @param image the image to classify
159
+ * @param flipped whether to flip the image on X
160
+ */
161
+ // async predict(image: ClassifierInputSource, flipped = false) {
162
+ // const croppedImage = cropTo(image, this._metadata.imageSize, flipped);
163
+ // const logits = tf.tidy(() => {
164
+ // const captured = capture(croppedImage, this._metadata.grayscale);
165
+ // return this.model.predict(captured);
166
+ // });
167
+ // const values = await (logits as tf.Tensor<tf.Rank>).data();
168
+ // const classes = [];
169
+ // for (let i = 0; i < values.length; i++) {
170
+ // classes.push({
171
+ // className: this._metadata.labels[i],
172
+ // probability: values[i]
173
+ // });
174
+ // }
175
+ // dispose(logits);
176
+ // return classes;
177
+ // }
178
+ dispose() {
179
+ this.truncatedModel.dispose();
180
+ }
181
+ } // end of CustomMobileNet
182
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tLW1vYmlsZW5ldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3RmanMtZXZvbHV0aW9uL3NyYy9saWIvbW9kZWxzL2N1c3RvbS1tb2JpbGVuZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUt2QyxNQUFNLENBQUMsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDO0FBNEI5QixNQUFNLHlCQUF5QixHQUFHLENBQUMsQ0FBQztBQUNwQyxNQUFNLHlCQUF5QixHQUFHLGlCQUFpQixDQUFDO0FBQ3BELE1BQU0seUJBQXlCLEdBQUcsVUFBVSxDQUFDO0FBQzdDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBQ2pDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLENBQUEsS0FBSztBQUNuQyxNQUFNLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxDQUFDLEtBQUs7QUFDbkMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsQ0FBQSxjQUFjO0FBQzVDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLENBQUEsZUFBZTtBQUMxQyxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQUMsQ0FBQSxlQUFlO0FBRXZDLGdDQUFnQztBQUVoQyxNQUFNLFlBQVksR0FBRyxDQUFDLE9BQWUsRUFBRSxLQUFhLEVBQUUsRUFBRTtJQUNwRCxJQUFJLE9BQU8sS0FBSyxDQUFDLEVBQUU7UUFDZixJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLEdBQUcsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLEtBQUssS0FBSyxDQUFDLEVBQUU7WUFDbEUsT0FBTyxDQUFDLElBQUksQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1lBQ3RFLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLEVBQUUsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENB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QUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQztJQUNqQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCwwRkFBMEY7SUFDMUYsNkVBQTZFO0lBRTdFLHFDQUFxQztJQUNyQyw0RUFBNEU7SUFDNUUsK0NBQStDO0lBQy9DLFVBQVU7SUFFViwwREFBMEQ7SUFDMUQsaUhBQWlIO0lBQ2pILHVCQUF1QjtJQUV2QixzQkFBc0I7SUFDdEIsSUFBSTtJQUVKOzs7OztPQUtHO0lBQ0gsaUVBQWlFO0lBQ2pFLDZFQUE2RTtJQUU3RSxxQ0FBcUM7SUFDckMsNEVBQTRFO0lBQzVFLCtDQUErQztJQUMvQyxVQUFVO0lBRVYsa0VBQWtFO0lBRWxFLDBCQUEwQjtJQUMxQixnREFBZ0Q7SUFDaEQseUJBQXlCO0lBQ3pCLG1EQUFtRDtJQUNuRCxxQ0FBcUM7SUFDckMsY0FBYztJQUNkLFFBQVE7SUFFUix1QkFBdUI7SUFFdkIsc0JBQXNCO0lBQ3RCLElBQUk7SUFFRyxPQUFPO1FBQ1YsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNsQyxDQUFDO0NBQ0osQ0FBQSx5QkFBeUIiLCJzb3VyY2VzQ29udGVudCI6WyJcclxuaW1wb3J0ICogYXMgdGYgZnJvbSAnQHRlbnNvcmZsb3cvdGZqcyc7XHJcblxyXG5pbXBvcnQgeyBTeW1ib2xpY1RlbnNvciB9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMnO1xyXG5cclxuXHJcbmV4cG9ydCBjb25zdCBJTUFHRV9TSVpFID0gMjI0O1xyXG5cclxuXHJcbi8qKlxyXG4gKiB0aGUgbWV0YWRhdGEgdG8gZGVzY3JpYmUgdGhlIG1vZGVsJ3MgY3JlYXRpb24sXHJcbiAqIGluY2x1ZGVzIHRoZSBsYWJlbHMgYXNzb2NpYXRlZCB3aXRoIHRoZSBjbGFzc2VzXHJcbiAqIGFuZCB2ZXJzaW9uaW5nIGluZm9ybWF0aW9uIGZyb20gdHJhaW5pbmcuXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIE1ldGFkYXRhIHtcclxuICAgIHRmanNWZXJzaW9uOiBzdHJpbmc7XHJcbiAgICB0bVZlcnNpb24/OiBzdHJpbmc7XHJcbiAgICBwYWNrYWdlVmVyc2lvbjogc3RyaW5nO1xyXG4gICAgcGFja2FnZU5hbWU6IHN0cmluZztcclxuICAgIG1vZGVsTmFtZT86IHN0cmluZztcclxuICAgIHRpbWVTdGFtcD86IHN0cmluZztcclxuICAgIGxhYmVsczogc3RyaW5nW107XHJcbiAgICB1c2VyTWV0YWRhdGE/OiB7fTtcclxuICAgIGdyYXlzY2FsZT86IGJvb2xlYW47XHJcbiAgICBpbWFnZVNpemU/OiBudW1iZXI7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTW9kZWxPcHRpb25zIHtcclxuICAgIHZlcnNpb24/OiBudW1iZXI7XHJcbiAgICBjaGVja3BvaW50VXJsPzogc3RyaW5nO1xyXG4gICAgYWxwaGE/OiBudW1iZXI7XHJcbiAgICB0cmFpbmluZ0xheWVyPzogc3RyaW5nO1xyXG59XHJcblxyXG5jb25zdCBERUZBVUxUX01PQklMRU5FVF9WRVJTSU9OID0gMjtcclxuY29uc3QgREVGQVVMVF9UUkFJTklOR19MQVlFUl9WMSA9ICdjb252X3B3XzEzX3JlbHUnO1xyXG5jb25zdCBERUZBVUxUX1RSQUlOSU5HX0xBWUVSX1YyID0gXCJvdXRfcmVsdVwiOyBcclxuY29uc3QgREVGQVVMVF9BTFBIQV9WMV92MiA9IDAuMzU7XHJcbmNvbnN0IERFRkFVTFRfQUxQSEFfVjEgPSAwLjI1Oy8vMjU2XHJcbmNvbnN0IERFRkFVTFRfQUxQSEFfVjIgPSAwLjU7IC8vNTEyXHJcbmNvbnN0IERFRkFVTFRfQUxQSEFfVjMgPSAwLjc1Oy8vNzY4IGZlYXR1cmVzXHJcbmNvbnN0IERFRkFVTFRfQUxQSEFfVjQgPSAxOy8vMTAyNCBmZWF0dXJlc1xyXG5jb25zdCBERUZBVUxUX0FMUEhBID0gMTsvLzEwMjQgZmVhdHVyZXNcclxuXHJcbi8vIHYyOiAwLjM1LCAwLjUwLCAwLjc1IG9yIDEuMDAuXHJcblxyXG5jb25zdCBpc0FscGhhVmFsaWQgPSAodmVyc2lvbjogbnVtYmVyLCBhbHBoYTogbnVtYmVyKSA9PiB7XHJcbiAgICBpZiAodmVyc2lvbiA9PT0gMSkge1xyXG4gICAgICAgIGlmIChhbHBoYSAhPT0gMC4yNSAmJiBhbHBoYSAhPT0gMC41ICYmIGFscGhhICE9PSAwLjc1ICYmIGFscGhhICE9PSAxKSB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkludmFsaWQgYWxwaGEuIE9wdGlvbnMgYXJlOiAwLjI1LCAwLjUwLCAwLjc1IG9yIDEuMDAuXCIpO1xyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkxvYWRpbmcgbW9kZWwgd2l0aCBhbHBoYTogXCIsIERFRkFVTFRfQUxQSEFfVjEudG9GaXhlZCgyKSk7IFxyXG4gICAgICAgICAgICByZXR1cm4gREVGQVVMVF9BTFBIQV9WMTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBlbHNlIHtcclxuICAgICAgICBpZiAoYWxwaGEgIT09IDAuMzUgJiYgYWxwaGEgIT09IDAuNSAmJiBhbHBoYSAhPT0gMC43NSAmJiBhbHBoYSAhPT0gMSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJJbnZhbGlkIGFscGhhLiBPcHRpb25zIGFyZTogMC4zNSwgMC41MCwgMC43NSBvciAxLjAwLlwiKTtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coXCJMb2FkaW5nIG1vZGVsIHdpdGggYWxwaGE6IFwiLCBERUZBVUxUX0FMUEhBX1YyLnRvRml4ZWQoMikpOyBcclxuICAgICAgICAgICAgcmV0dXJuIERFRkFVTFRfQUxQSEFfVjI7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBhbHBoYTtcclxufTtcclxuXHJcblxyXG5jb25zdCBwYXJzZU1vZGVsT3B0aW9ucyA9IChvcHRpb25zPzogTW9kZWxPcHRpb25zKSA9PiB7XHJcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fVxyXG5cclxuICAgIGlmIChvcHRpb25zLmNoZWNrcG9pbnRVcmwgJiYgb3B0aW9ucy50cmFpbmluZ0xheWVyKSB7XHJcbiAgICAgICAgaWYgKG9wdGlvbnMuYWxwaGEgfHwgb3B0aW9ucy52ZXJzaW9uKXtcclxuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiQ2hlY2twb2ludCBVUkwgcGFzc2VkIHRvIG1vZGVsT3B0aW9ucywgYWxwaGEgb3B0aW9ucyBhcmUgaWdub3JlZFwiKTtcclxuICAgICAgICB9ICAgICAgICBcclxuICAgICAgICByZXR1cm4gW29wdGlvbnMuY2hlY2twb2ludFVybCwgb3B0aW9ucy50cmFpbmluZ0xheWVyXTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb3B0aW9ucy52ZXJzaW9uID0gb3B0aW9ucy52ZXJzaW9uIHx8IERFRkFVTFRfTU9CSUxFTkVUX1ZFUlNJT047XHJcbiAgICAgICAgXHJcbiAgICAgICAgaWYob3B0aW9ucy52ZXJzaW9uID09PSAxKXtcclxuICAgICAgICAgICAgb3B0aW9ucy5hbHBoYSA9IG9wdGlvbnMuYWxwaGEgfHwgREVGQVVMVF9BTFBIQV9WNDsgIFxyXG4gICAgICAgICAgICBvcHRpb25zLmFscGhhID0gaXNBbHBoYVZhbGlkKG9wdGlvbnMudmVyc2lvbiwgb3B0aW9ucy5hbHBoYSk7XHJcblxyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgTG9hZGluZyBtb2JpbGVuZXQgJHtvcHRpb25zLnZlcnNpb259IGFuZCBhbHBoYSAke29wdGlvbnMuYWxwaGF9YCk7XHJcbiAgICAgICAgICAgIC8vIGV4Y2VwdGlvbiBpcyBhbHBoYSBvIGYgMSBjYW4gb25seSBiZSAxLjBcclxuICAgICAgICAgICAgbGV0IGFscGhhU3RyaW5nID0gb3B0aW9ucy5hbHBoYS50b0ZpeGVkKDIpO1xyXG4gICAgICAgICAgICBpZiAoYWxwaGFTdHJpbmcgPT09IFwiMS4wMFwiKSB7IGFscGhhU3RyaW5nID0gXCIxLjBcIjsgfVxyXG5cclxuICAgICAgICAgICAgY29uc29sZS5sb2coXCJVc2luZyB0aGUgbW9kZWw6IFwiLCAgKVxyXG5cclxuICAgICAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTptYXgtbGluZS1sZW5ndGhcclxuICAgICAgICAgICAgICAgIC8vVGhleSBhcmUgbG9hZGluZyBNb2JpbGVOZXRfdjEgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgYGh0dHBzOi8vc3RvcmFnZS5nb29nbGVhcGlzLmNvbS90ZmpzLW1vZGVscy90ZmpzL21vYmlsZW5ldF92MV8ke2FscGhhU3RyaW5nfV8ke0lNQUdFX1NJWkV9L21vZGVsLmpzb25gLFxyXG4gICAgICAgICAgICAgICAgREVGQVVMVF9UUkFJTklOR19MQVlFUl9WMVxyXG4gICAgICAgICAgICBdO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIGlmIChvcHRpb25zLnZlcnNpb24gPT09IDIpe1xyXG4gICAgICAgICAgICBvcHRpb25zLmFscGhhID0gb3B0aW9ucy5hbHBoYSB8fCBERUZBVUxUX0FMUEhBX1Y0OyAgXHJcbiAgICAgICAgICAgIG9wdGlvbnMuYWxwaGEgPSBpc0FscGhhVmFsaWQob3B0aW9ucy52ZXJzaW9uLCBvcHRpb25zLmFscGhhKTtcclxuXHJcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBMb2FkaW5nIG1vYmlsZW5ldCAke29wdGlvbnMudmVyc2lvbn0gYW5kIGFscGhhICR7b3B0aW9ucy5hbHBoYX1gKTtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coYExvYWRpbmcgbW9iaWxlbmV0ICR7b3B0aW9ucy52ZXJzaW9ufSBhbmQgYWxwaGEgJHtvcHRpb25zLmFscGhhfWApO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTptYXgtbGluZS1sZW5ndGggICAgICAgIFxyXG4gICAgICAgICAgICAgICAgYGh0dHBzOi8vc3RvcmFnZS5nb29nbGVhcGlzLmNvbS90ZWFjaGFibGUtbWFjaGluZS1tb2RlbHMvbW9iaWxlbmV0X3YyX3dlaWdodHNfdGZfZGltX29yZGVyaW5nX3RmX2tlcm5lbHNfJHtvcHRpb25zLmFscGhhLnRvRml4ZWQoMil9XyR7SU1BR0VfU0laRX1fbm9fdG9wL21vZGVsLmpzb25gLFxyXG4gICAgICAgICAgICAgICAgREVGQVVMVF9UUkFJTklOR19MQVlFUl9WMlxyXG4gICAgICAgICAgICBdO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTW9iaWxlTmV0IFYke29wdGlvbnMudmVyc2lvbn0gZG9lc24ndCBleGlzdGApO1xyXG4gICAgICAgIH0gICBcclxuICAgIH1cclxufTtcclxuXHJcblxyXG4vKipcclxuICogbG9hZCB0aGUgYmFzZSBtb2JpbGVuZXQgbW9kZWxcclxuICogQHBhcmFtIG1vZGVsT3B0aW9ucyBvcHRpb25zIGRldGVybWluaW5nIHdoYXQgbW9kZWwgdG8gbG9hZFxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRUcnVuY2F0ZWRNb2JpbGVOZXQobW9kZWxPcHRpb25zPzogTW9kZWxPcHRpb25zKSB7XHJcbiAgICBjb25zdCBbY2hlY2twb2ludFVybCwgdHJhaW5pbmdMYXllcl0gPSBwYXJzZU1vZGVsT3B0aW9ucyhtb2RlbE9wdGlvbnMpO1xyXG4gICAgXHJcbiAgICBcclxuICAgIGNvbnN0IG1vYmlsZW5ldCA9IGF3YWl0IHRmLmxvYWRMYXllcnNNb2RlbChjaGVja3BvaW50VXJsKTtcclxuXHJcbiAgICBpZiAobW9kZWxPcHRpb25zICYmIG1vZGVsT3B0aW9ucy52ZXJzaW9uID09PSAxKXtcclxuICAgICAgICBjb25zdCBsYXllciA9IG1vYmlsZW5ldC5nZXRMYXllcih0cmFpbmluZ0xheWVyKTtcclxuICAgICAgICBcclxuICAgICAgICBjb25zdCB0cnVuY2F0ZWRNb2RlbCA9IHRmLm1vZGVsKHsgaW5wdXRzOiBtb2JpbGVuZXQuaW5wdXRzLCBvdXRwdXRzOiBsYXllci5vdXRwdXQgfSk7XHJcbiAgICAgICAgY29uc29sZS5sb2coXCJGZWF0dXJlIG1vZGVsIGxvYWRlZCwgbWVtb3J5OiBcIiwgdGYubWVtb3J5KCkubnVtQnl0ZXMpO1xyXG5cclxuICAgICAgICBcclxuICAgICAgICBjb25zdCBtb2RlbCA9IHRmLnNlcXVlbnRpYWwoKTtcclxuICAgICAgICBtb2RlbC5hZGQodHJ1bmNhdGVkTW9kZWwpO1xyXG4gICAgICAgIG1vZGVsLmFkZCh0Zi5sYXllcnMuZmxhdHRlbigpKTsgICAgICAgIFxyXG4gICAgICAgIFxyXG4gICAgICAgIFxyXG4gICAgICAgIHJldHVybiBtb2RlbDtcclxuICAgIH1cclxuICAgIGVsc2Uge1xyXG4gICAgICAgIGNvbnN0IGxheWVyID0gbW9iaWxlbmV0LmdldExheWVyKHRyYWluaW5nTGF5ZXIpO1xyXG4gICAgICAgIGNvbnN0IHRydW5jYXRlZE1vZGVsID0gdGYubW9kZWwoeyBpbnB1dHM6IG1vYmlsZW5ldC5pbnB1dHMsIG91dHB1dHM6IGxheWVyLm91dHB1dCB9KTtcclxuICAgICAgICBjb25zb2xlLmxvZyhcIkZlYXR1cmUgbW9kZWwgbG9hZGVkLCBtZW1vcnk6IFwiLCB0Zi5tZW1vcnkoKS5udW1CeXRlcyk7XHJcbiAgICAgICAgY29uc3QgbW9kZWwgPSB0Zi5zZXF1ZW50aWFsKCk7XHJcbiAgICAgICAgbW9kZWwuYWRkKHRydW5jYXRlZE1vZGVsKTtcclxuICAgICAgICBtb2RlbC5hZGQodGYubGF5ZXJzLmdsb2JhbEF2ZXJhZ2VQb29saW5nMmQoe30pKTsgLy8gZ28gZnJvbSBzaGFwZSBbNywgNywgMTI4MF0gdG8gWzEyODBdXHJcbiAgICAgICAgcmV0dXJuIG1vZGVsO1xyXG4gICAgfVxyXG59XHJcblxyXG5cclxuZXhwb3J0IGNsYXNzIEN1c3RvbU1vYmlsZU5ldCB7XHJcbiAgICAvKipcclxuICAgICAqIHRoZSB0cnVuY2F0ZWQgbW9iaWxlbmV0IG1vZGVsIHdlIHdpbGwgdHJhaW4gb24gdG9wIG9mXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCB0cnVuY2F0ZWRNb2RlbCE6IHRmLkxheWVyc01vZGVsO1xyXG4gICAgc3RhdGljIHRydW5jYXRlZE1vZGVsOiB0Zi5TZXF1ZW50aWFsO1xyXG5cclxuc3RhdGljIGdldGlucHV0U2hhcGUoKXtcclxuICAgLyoqdHJ1bmNhdGVkTW9kZWwgaXMgdGhlIGJhc2UgbW9kZWwsIHRoZSBtb2RlbCB1c2VkIHRvIGFwcGx5IHRyYW5zZmVyIGxlYXJuaW5nICovXHJcbiAgY29uc3QgaW5wdXRTaGFwZTogYW55ID0gdGhpcy50cnVuY2F0ZWRNb2RlbC5vdXRwdXRzWzBdLnNoYXBlLnNsaWNlKDEpOyAvLyBbIDcgeCA3IHggMTI4MF0gKG5vdCBzdXJlIGFib3V0IHRob3NlIGRpbWVuc2lvbnMpXHJcbi8vICAgY29uc29sZS5sb2coXCJJbnB1dCBTaGFwZShjb21wbGV0ZSk6IFwiLCB0aGlzLnRydW5jYXRlZE1vZGVsLm91dHB1dHNbMF0uc2hhcGUpO1xyXG4vLyAgIGNvbnNvbGUubG9nKFwiSW5wdXQgU2hhcGU6IFwiLCBpbnB1dFNoYXBlKTtcclxuXHJcbiAgY29uc3QgaW5wdXRTaXplID0gdGYudXRpbC5zaXplRnJvbVNoYXBlKGlucHV0U2hhcGUpO1xyXG5cclxuLy8gICBjb25zb2xlLmxvZyhcIklucHV0IFNpemU6IFwiLCBpbnB1dFNpemUpO1xyXG5cclxuICByZXR1cm4gaW5wdXRTaXplO1xyXG59XHJcblxyXG4gICAgc3RhdGljIGdldCBFWFBFQ1RFRF9JTUFHRV9TSVpFKCkge1xyXG4gICAgICAgIHJldHVybiBJTUFHRV9TSVpFO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfbWV0YWRhdGEhOiBNZXRhZGF0YTtcclxuXHJcbiAgICBwdWJsaWMgZ2V0TWV0YWRhdGEoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX21ldGFkYXRhO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIC8vIHRoaXMuX21ldGFkYXRhID0gZmlsbE1ldGFkYXRhKG1ldGFkYXRhKTtcclxuICAgICAgICAvL0xvYWRpbmcgdGhlIHRydW5jYXRlZCBtb2RlbFxyXG4gICAgICAgIC8vIGxvYWRUcnVuY2F0ZWRNb2JpbGVOZXQoKTtcclxuICAgICAgICAvLyB0aGlzLmxvYWRGZWF0dXJlTW9kZWwoKTtcclxuXHJcbiAgICB9XHJcblxyXG4gICBzdGF0aWMgIGFzeW5jIGxvYWRGZWF0dXJlTW9kZWwoKXtcclxuXHJcbiAgICAgICAgdGhpcy50cnVuY2F0ZWRNb2RlbCA9IGF3YWl0IGxvYWRUcnVuY2F0ZWRNb2JpbGVOZXQoKTtcclxuXHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBnZXQgdGhlIHRvdGFsIG51bWJlciBvZiBjbGFzc2VzIGV4aXN0aW5nIHdpdGhpbiBtb2RlbFxyXG4gICAgICovXHJcbiAgICAvLyBnZXRUb3RhbENsYXNzZXMoKSB7XHJcbiAgICAvLyAgICAgY29uc3Qgb3V0cHV0ID0gdGhpcy5tb2RlbC5vdXRwdXQgYXMgU3ltYm9saWNUZW5zb3I7XHJcbiAgICAvLyAgICAgY29uc3QgdG90YWxDbGFzc2VzID0gb3V0cHV0LnNoYXBlWzFdO1xyXG4gICAgLy8gICAgIHJldHVybiB0b3RhbENsYXNzZXM7XHJcbiAgICAvLyB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBnZXQgdGhlIG1vZGVsIGxhYmVsc1xyXG4gICAgICovXHJcbiAgICBnZXRDbGFzc0xhYmVscygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5fbWV0YWRhdGEubGFiZWxzO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2l2ZW4gYW4gaW1hZ2UgZWxlbWVudCwgbWFrZXMgYSBwcmVkaWN0aW9uIHRocm91Z2ggbW9iaWxlbmV0IHJldHVybmluZyB0aGVcclxuICAgICAqIHByb2JhYmlsaXRpZXMgb2YgdGhlIHRvcCBLIGNsYXNzZXMuXHJcbiAgICAgKiBAcGFyYW0gaW1hZ2UgdGhlIGltYWdlIHRvIGNsYXNzaWZ5XHJcbiAgICAgKiBAcGFyYW0gbWF4UHJlZGljdGlvbnMgdGhlIG1heGltdW0gbnVtYmVyIG9mIGNsYXNzaWZpY2F0aW9uIHByZWRpY3Rpb25zXHJcbiAgICAgKi9cclxuICAgIC8vIGFzeW5jIHByZWRpY3RUb3BLKGltYWdlOiBDbGFzc2lmaWVySW5wdXRTb3VyY2UsIG1heFByZWRpY3Rpb25zID0gMTAsIGZsaXBwZWQgPSBmYWxzZSkge1xyXG4gICAgLy8gICAgIGNvbnN0IGNyb3BwZWRJbWFnZSA9IGNyb3BUbyhpbWFnZSwgdGhpcy5fbWV0YWRhdGEuaW1hZ2VTaXplLCBmbGlwcGVkKTtcclxuXHJcbiAgICAvLyAgICAgY29uc3QgbG9naXRzID0gdGYudGlkeSgoKSA9PiB7XHJcbiAgICAvLyAgICAgICAgIGNvbnN0IGNhcHR1cmVkID0gY2FwdHVyZShjcm9wcGVkSW1hZ2UsIHRoaXMuX21ldGFkYXRhLmdyYXlzY2FsZSk7XHJcbiAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLm1vZGVsLnByZWRpY3QoY2FwdHVyZWQpO1xyXG4gICAgLy8gICAgIH0pO1xyXG5cclxuICAgIC8vICAgICAvLyBDb252ZXJ0IGxvZ2l0cyB0byBwcm9iYWJpbGl0aWVzIGFuZCBjbGFzcyBuYW1lcy5cclxuICAgIC8vICAgICBjb25zdCBjbGFzc2VzID0gYXdhaXQgZ2V0VG9wS0NsYXNzZXModGhpcy5fbWV0YWRhdGEubGFiZWxzLCBsb2dpdHMgYXMgdGYuVGVuc29yPHRmLlJhbms+LCBtYXhQcmVkaWN0aW9ucyk7XHJcbiAgICAvLyAgICAgZGlzcG9zZShsb2dpdHMpO1xyXG5cclxuICAgIC8vICAgICByZXR1cm4gY2xhc3NlcztcclxuICAgIC8vIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdpdmVuIGFuIGltYWdlIGVsZW1lbnQsIG1ha2VzIGEgcHJlZGljdGlvbiB0aHJvdWdoIG1vYmlsZW5ldCByZXR1cm5pbmcgdGhlXHJcbiAgICAgKiBwcm9iYWJpbGl0aWVzIGZvciBBTEwgY2xhc3Nlcy5cclxuICAgICAqIEBwYXJhbSBpbWFnZSB0aGUgaW1hZ2UgdG8gY2xhc3NpZnlcclxuICAgICAqIEBwYXJhbSBmbGlwcGVkIHdoZXRoZXIgdG8gZmxpcCB0aGUgaW1hZ2Ugb24gWFxyXG4gICAgICovXHJcbiAgICAvLyBhc3luYyBwcmVkaWN0KGltYWdlOiBDbGFzc2lmaWVySW5wdXRTb3VyY2UsIGZsaXBwZWQgPSBmYWxzZSkge1xyXG4gICAgLy8gICAgIGNvbnN0IGNyb3BwZWRJbWFnZSA9IGNyb3BUbyhpbWFnZSwgdGhpcy5fbWV0YWRhdGEuaW1hZ2VTaXplLCBmbGlwcGVkKTtcclxuXHJcbiAgICAvLyAgICAgY29uc3QgbG9naXRzID0gdGYudGlkeSgoKSA9PiB7XHJcbiAgICAvLyAgICAgICAgIGNvbnN0IGNhcHR1cmVkID0gY2FwdHVyZShjcm9wcGVkSW1hZ2UsIHRoaXMuX21ldGFkYXRhLmdyYXlzY2FsZSk7XHJcbiAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLm1vZGVsLnByZWRpY3QoY2FwdHVyZWQpO1xyXG4gICAgLy8gICAgIH0pO1xyXG5cclxuICAgIC8vICAgICBjb25zdCB2YWx1ZXMgPSBhd2FpdCAobG9naXRzIGFzIHRmLlRlbnNvcjx0Zi5SYW5rPikuZGF0YSgpO1xyXG5cclxuICAgIC8vICAgICBjb25zdCBjbGFzc2VzID0gW107XHJcbiAgICAvLyAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZXMubGVuZ3RoOyBpKyspIHtcclxuICAgIC8vICAgICAgICAgY2xhc3Nlcy5wdXNoKHtcclxuICAgIC8vICAgICAgICAgICAgIGNsYXNzTmFtZTogdGhpcy5fbWV0YWRhdGEubGFiZWxzW2ldLFxyXG4gICAgLy8gICAgICAgICAgICAgcHJvYmFiaWxpdHk6IHZhbHVlc1tpXVxyXG4gICAgLy8gICAgICAgICB9KTtcclxuICAgIC8vICAgICB9XHJcblxyXG4gICAgLy8gICAgIGRpc3Bvc2UobG9naXRzKTtcclxuXHJcbiAgICAvLyAgICAgcmV0dXJuIGNsYXNzZXM7XHJcbiAgICAvLyB9XHJcblxyXG4gICAgcHVibGljIGRpc3Bvc2UoKSB7XHJcbiAgICAgICAgdGhpcy50cnVuY2F0ZWRNb2RlbC5kaXNwb3NlKCk7XHJcbiAgICB9XHJcbn0vLyBlbmQgb2YgQ3VzdG9tTW9iaWxlTmV0XHJcbiJdfQ==