diff --git a/docs/README.md b/docs/README.md index 3933aeabfa452ef589518e7d721b145364c00c90..ac3464fbc6315c31e3439488f650238bc2b0b081 100644 --- a/docs/README.md +++ b/docs/README.md @@ -54,7 +54,10 @@ Pour s'assurer que 10 centimètres sont bien couverts, **les petits points "dét  -Pour placer la règle avec plus de précision, utiliser le bouton  (en jaune ci-dessous). +Si il y a moins de 10cm règle sur la photo, il est possible de modifier la taille à couvrir avec les boutons +/- (en bleu ci-dessous). +Le nombre de détrompeurs sera ajusté. + +Pour placer la règle avec plus de précision, utiliser le bouton  (en jaune ci-dessous).  @@ -64,7 +67,7 @@ Une fois la règle placée, **passer à l'étape suivante en appuyant sur le bou ## Étape 3 : positionner la boîte de Petri -Tout comme la règle, **placer la boîte de Petri à l'aide des poignées**, et utiliser le bouton  +Tout comme la règle, **placer la boîte de Petri à l'aide des poignées**, et utiliser le bouton  pour la placer avec précision.  @@ -106,7 +109,7 @@ Le bouton  s'active et permet de **passer à l'étape --- -## Étape 5 : Télécharger les résultats +## Étape 5 : télécharger les résultats  diff --git a/docs/images/ruler_panel.png b/docs/images/ruler_panel.png index e72765f14b8aa57ea69dbb8255301edfbe27fa34..031c6ec2a122ac263e50f693391f963b8dbbd5b9 100644 Binary files a/docs/images/ruler_panel.png and b/docs/images/ruler_panel.png differ diff --git a/karma.conf.js b/karma.conf.js index ab6da1a7a7f93efe41db06f53c74612fdb23b57f..5ebfdfcaea66cc5419695c745c36e6d5274fb416 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -2,8 +2,6 @@ let webpackConfig = require('./webpack.staging.js'); webpackConfig.entry = {}; -console.info(webpackConfig) - module.exports = function(config) { config.set({ basePath: '', @@ -18,7 +16,7 @@ module.exports = function(config) { }, plugins: [ require('karma-jasmine'), - require('karma-chrome-launcher'), + require('karma-firefox-launcher'), require('karma-spec-reporter'), require('karma-jasmine-html-reporter'), require('karma-webpack'), @@ -31,7 +29,7 @@ module.exports = function(config) { logLevel: config.LOG_INFO, autoWatch: true, - browsers: ['Chrome'], + browsers: ['Firefox'], client: { clearContext: false }, diff --git a/package-lock.json b/package-lock.json index 1b1fa08522687a7c708bb77de3f02bc7dfeb905a..f7777b13592621c0a9ac3e7bb478770f678eedb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "jest-mock": "^29.1.2", "karma": "^6.4.1", "karma-chrome-launcher": "^3.1.1", + "karma-firefox-launcher": "^2.1.2", "karma-jasmine": "^5.1.0", "karma-jasmine-html-reporter": "^2.0.0", "karma-spec-reporter": "^0.0.34", @@ -5677,6 +5678,31 @@ "which": "^1.2.1" } }, + "node_modules/karma-firefox-launcher": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz", + "integrity": "sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA==", + "dev": true, + "dependencies": { + "is-wsl": "^2.2.0", + "which": "^2.0.1" + } + }, + "node_modules/karma-firefox-launcher/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/karma-jasmine": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", @@ -12981,6 +13007,27 @@ "which": "^1.2.1" } }, + "karma-firefox-launcher": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz", + "integrity": "sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA==", + "dev": true, + "requires": { + "is-wsl": "^2.2.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "karma-jasmine": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", diff --git a/package.json b/package.json index a55a1099a498ed3db23c9b2c0680cab9ccc611d4..5dd0203d41e8d7352006a4af413164064367b142 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "private": true, "scripts": { "serve": "webpack serve --open --config webpack.staging.js", + "test": "karma start --single-run", "build": "webpack" }, "keywords": [], @@ -38,6 +39,7 @@ "jest-mock": "^29.1.2", "karma": "^6.4.1", "karma-chrome-launcher": "^3.1.1", + "karma-firefox-launcher": "^2.1.2", "karma-jasmine": "^5.1.0", "karma-jasmine-html-reporter": "^2.0.0", "karma-spec-reporter": "^0.0.34", diff --git a/src/custom.d.ts b/src/custom.d.ts index c26f543d8cd7b51dc801f270dca98f7812ea015c..97b032b9a86e37b9fd07b7de0d330e4873500736 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -1 +1,3 @@ -declare module '*.svg'; \ No newline at end of file +declare module '*.svg'; +declare module '*.txt'; +declare module '*.csv'; diff --git a/src/data/dataImporter.ts b/src/data/dataImporter.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1e475f01c124462efaf0ce0b132167736645e97 --- /dev/null +++ b/src/data/dataImporter.ts @@ -0,0 +1,25 @@ +import {Coords} from "./coords/coords"; +import {PathCoords} from "./coords/pathCoords"; +import {StringUtils} from "../utils/stringUtils"; +import * as paper from "paper"; + +/** + * Import de données, sert plutôt ôu rle debug + */ +export class DataImporter { + + /** + * Charge un PathCoords depuis des coordonnées text + */ + public import(text: string): PathCoords { + let pathCoords = new PathCoords(); + let lines = StringUtils.splitLines(text); + lines.filter(line => line.trim().length > 0).forEach( + (line: string) => { + let [x, y] = line.split("\t"); + pathCoords.points.push(new paper.Point(Number(x), Number(y))); + } + ); + return pathCoords; + } +} diff --git a/src/instruments/ruler.ts b/src/instruments/ruler.ts index cb1991c24f63f22e72a6ea1d789b92d906664e4e..814fb598b8aa821c83b0f5b4ff8add63240278ba 100644 --- a/src/instruments/ruler.ts +++ b/src/instruments/ruler.ts @@ -9,7 +9,7 @@ import {PaperUtils} from "../utils/paperUtils"; */ export class Ruler extends AbstractInstrument<VectorCoords> implements Instrument { - public constructor(protected lab : Lab, coords : VectorCoords, private tickCount : number) { + public constructor(protected lab : Lab, coords : VectorCoords) { super(lab, coords, [ new Handle("startHandle", true), new Handle("endHandle", true) @@ -18,10 +18,10 @@ export class Ruler extends AbstractInstrument<VectorCoords> implements Instrumen drawIn(coords : VectorCoords, group: paper.Group) { group.addChild(new paper.Path.Line(coords.start, coords.end)); - + let tickCount = this.lab.data.rulerTickCount; let vector = this.coords.asPointVector(); - for (let i = 0; i < this.tickCount; i++) { - let tickCircle = new paper.Path.Circle(this.coords.start.add(vector.multiply(i / this.tickCount)), PaperUtils.absoluteDimension(1)); + for (let i = 0; i < tickCount; i++) { + let tickCircle = new paper.Path.Circle(this.coords.start.add(vector.multiply(i / tickCount)), PaperUtils.absoluteDimension(1)); group.addChild(tickCircle); } diff --git a/src/lab.tsx b/src/lab.tsx index 342dbbd648c1839e79b05d7415fd358f3207bdbd..654753b806b4aa5084045597608b1e2c07deea56 100644 --- a/src/lab.tsx +++ b/src/lab.tsx @@ -21,6 +21,22 @@ import {Welcome} from "./ui/welcome"; */ export const DEBUG_MODE = false; +/** + * La taille par défaut de la règle + */ +export const DEFAULT_RULER_TICK_COUNT = 10; + +/** + * La taille minimum de la règle + */ +export const MIN_RULER_TICK_COUNT = 8; + +/** + * La taille maximum de la règle + */ +export const MAX_RULER_TICK_COUNT = 15; + + export interface LabData { pictureSize : paper.Size, @@ -159,7 +175,7 @@ export class Lab extends React.Component<{}> { filename: filename, - rulerTickCount : 10, + rulerTickCount : DEFAULT_RULER_TICK_COUNT, rulerCoords: new VectorCoords(new paper.Point(width * 0.25, height / 2), new paper.Point(width * 0.75, height / 2)), @@ -171,7 +187,7 @@ export class Lab extends React.Component<{}> { // Le plus en dessous en premier this.blobMask = new BlobMask(this, this.data.blobMaskCoords); this.petriDish = new PetriDish(this, this.data.petriDishCoords); - this.ruler = new Ruler(this, this.data.rulerCoords, this.data.rulerTickCount); + this.ruler = new Ruler(this, this.data.rulerCoords); // Zoom global this.zoomFit(); @@ -290,7 +306,7 @@ export class Lab extends React.Component<{}> { <Container fluid={true}> <Row className={"col-md-12"}> <div className="d-flex d-flex justify-content-between"> - <Navbar.Brand className={"p-0"}><i className={"fa-solid fa-flask me-2"}></i>Blob Analysis Lab <sup><Badge pill bg="secondary" text="primary">démo</Badge></sup></Navbar.Brand> + <Navbar.Brand className={"p-0"}><i className={"fa-solid fa-flask me-2"}></i>Blob Analysis Lab <sup><Badge pill bg="secondary" text="primary">demo</Badge></sup></Navbar.Brand> <Form className={"inline-form"}> <Form.Group controlId="zoomGroup"> <Form.Label>Zoom :</Form.Label> diff --git a/src/ui/steps/drawBlobMaskStep.tsx b/src/ui/steps/drawBlobMaskStep.tsx index cd2cfac12225448e260193dfd131dd92bded8c69..b8d654f41a356dc679cb96108d7ddf7fbafc5500 100644 --- a/src/ui/steps/drawBlobMaskStep.tsx +++ b/src/ui/steps/drawBlobMaskStep.tsx @@ -5,6 +5,7 @@ import {Alert, Button} from "react-bootstrap"; import {IoUtils} from "../../utils/ioUtils"; import {DEBUG_MODE} from "../../lab"; import {StringUtils} from "../../utils/stringUtils"; +import {DataImporter} from "../../data/dataImporter"; interface DrawBlobMaskStepState extends StepState { @@ -43,18 +44,10 @@ export class DrawBlobMaskStep extends Step<DrawBlobMaskStepState> { } loadData(): void { + let dataImporter = new DataImporter(); IoUtils.openTextFile( (text : string) => { - console.info("text loaded") - this.props.lab.data.blobMaskCoords.points = []; - let lines = StringUtils.splitLines(text); - lines.filter(line => line.trim().length > 0).forEach( - (line : string) => { - let [x, y] = line.split("\t"); - this.props.lab.data.blobMaskCoords.points.push(new paper.Point(Number(x), Number(y))); - } - ); - // this.props.lab.data.blobMaskCoords.points.push(this.props.lab.data.blobMaskCoords.points[0]); + this.props.lab.data.blobMaskCoords = dataImporter.import(text); this.props.lab.blobMask.refresh(); }); } diff --git a/src/ui/steps/rulerStep.tsx b/src/ui/steps/rulerStep.tsx index 51f01e93991574976b99aeef717f7a0fb8003d47..05fe8c196bdbb826cc250f02c820a493c409fd79 100644 --- a/src/ui/steps/rulerStep.tsx +++ b/src/ui/steps/rulerStep.tsx @@ -1,17 +1,25 @@ import {Step, StepProps, StepState} from "./step"; import * as React from "react"; -import {Alert, Button, Form, InputGroup} from "react-bootstrap"; -import {DEBUG_MODE} from "../../lab"; +import {Alert, Button, Form, FormText, InputGroup} from "react-bootstrap"; +import {DEBUG_MODE, DEFAULT_RULER_TICK_COUNT, MAX_RULER_TICK_COUNT, MIN_RULER_TICK_COUNT} from "../../lab"; + + +interface RulerStepState extends StepState { + + tickCount: number | null; + +} + /** * Etape de placement de la règle */ -export class RulerStep extends Step<StepState> { +export class RulerStep extends Step<RulerStepState> { private rescaleInputRef = React.createRef<HTMLInputElement>(); public constructor(props : StepProps) { - super(props, { active: false, activable : false }); + super(props, { active: false, activable : false, tickCount : null }); } canBeActivated(): boolean { @@ -21,6 +29,9 @@ export class RulerStep extends Step<StepState> { onActivation(): void { this.props.lab.ruler.activate(); this.props.lab.zoomFit(); + this.setState( + {tickCount: this.props.lab.data?.rulerTickCount} + ); } onDeactivation(): void { @@ -31,6 +42,23 @@ export class RulerStep extends Step<StepState> { this.props.lab.zoomIn(this.props.lab.data.rulerCoords.bounds().center); } + + private tickCountMinus() { + this.props.lab.data.rulerTickCount = Math.max(this.props.lab.data.rulerTickCount - 1, MIN_RULER_TICK_COUNT); + this.props.lab.ruler.refresh(); + this.setState( + {tickCount: this.props.lab.data?.rulerTickCount} + ); + } + + private tickCountPlus() { + this.props.lab.data.rulerTickCount = Math.min(this.props.lab.data.rulerTickCount + 1, MAX_RULER_TICK_COUNT); + this.props.lab.ruler.refresh(); + this.setState( + {tickCount: this.props.lab.data?.rulerTickCount} + ); + } + private rescale() { let ppcm = Number.parseFloat(this.rescaleInputRef.current.value); let rulerCoords = this.props.lab.data.rulerCoords; @@ -38,14 +66,28 @@ export class RulerStep extends Step<StepState> { this.props.lab.ruler.refresh(); } + render() : React.ReactNode { return <div> <div> <Alert show={!this.state.activable} variant="warning" className={"p-1"}>Veuillez charger une photo.</Alert> - <p>Positionnez la règle sur la photo. La règle doit couvrir 10 cm.</p> + <p>Positionnez la règle sur la photo.<br/> + La règle doit couvrir + <InputGroup className={"d-inline"}> + <div className={"d-inline-flex"}> + <Button disabled={!this.state.active} onClick={this.tickCountMinus.bind(this)} size={"sm"} className={"d-inline"} variant={"light"}>-</Button> + </div> + <div className={"col-1 d-inline-flex"}> + <Form.Control disabled={!this.state.active} className={"d-inline"} readOnly={true} defaultValue={this.state.tickCount} type={"text"} size={"sm"} htmlSize={2}/> + </div> + <div className={"d-inline-flex"}> + <Button disabled={!this.state.active} onClick={this.tickCountPlus.bind(this)} size={"sm"} className={"d-inline"} variant={"light"}>+</Button> + </div> + </InputGroup> cm.</p> <Alert variant={"light"} className={"p-2"}><i className="ms-1 me-1 fa-solid fa-circle-info"></i> Appuyez ici <Button disabled={!this.state.active} onClick={this.zoomOnRuler.bind(this)} size={"sm"}><i className={"fa-solid fa-magnifying-glass-location"}></i></Button> pour placer la règle avec précision.</Alert> <div className={"d-flex flex-row"}> <Button className={"col-3"} variant={"success"} disabled={!this.state.active} onClick={this.terminate.bind(this)}>Terminé !</Button> + {DEBUG_MODE ? <> <InputGroup className={"ms-2"}> diff --git a/src/ui/welcome.tsx b/src/ui/welcome.tsx index 46a38921272295c086ef2e87dce4e0cfb12ac613..064399dabf2726f66880bb082488bd2820ec502b 100644 --- a/src/ui/welcome.tsx +++ b/src/ui/welcome.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import Here from "../assets/images/here.svg"; import {Button} from "react-bootstrap"; +import {StepProps} from "./steps/step"; /** * L'état de l'affichage de l'accueil @@ -14,8 +15,8 @@ export interface WelcomeState { */ export class Welcome extends React.Component<{}, WelcomeState>{ - public constructor() { - super({}); + public constructor(props : {}) { + super(props); this.state = {visible: true} } diff --git a/tests/data/coords/circleCoords.test.ts b/tests/data/coords/circleCoords.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..764df6b29219683a26561b1d10b33f751c54c21e --- /dev/null +++ b/tests/data/coords/circleCoords.test.ts @@ -0,0 +1,22 @@ +import * as paper from "paper"; +import {CircleCoords} from "../../../src/data/coords/circleCoords"; + +describe('Testing CircleCoords...', () => { + + let circleCoords = new CircleCoords(new paper.Point(7, 11), 10.5); + + it('bounds are correct', () => { + let bounds = circleCoords.bounds(); + expect(bounds.x).toBe(-3.5); + expect(bounds.y).toBe(0.5); + expect(bounds.width).toBe(21); + expect(bounds.height).toBe(21); + }); + + it('coords are correct', () => { + expect(circleCoords.radius).toBe(10.5); + expect(circleCoords.center.x).toBe(7); + expect(circleCoords.center.y).toBe(11); + }); + +}); \ No newline at end of file diff --git a/tests/data/dataExporter.test.ts b/tests/data/dataExporter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6df1b56df30a8ba923eb89ccf0187c30735280aa --- /dev/null +++ b/tests/data/dataExporter.test.ts @@ -0,0 +1,29 @@ +import {DataExporter} from "../../src/data/dataExporter"; +import {Fixtures} from "../fixtures/fixtures"; +import expectedResultsCsv from "../fixtures/Results_ExpJ1CrB9.csv"; + +describe('Testing DataExporter...', () => { + + /** + * Class under test + */ + let dataExporter = new DataExporter(); + + it('CSV metrics are correct', () => { + let labData = Fixtures.labData(); + let descriptorsCsv = dataExporter.exportPathDescriptorsAsCsv(labData, labData.blobMaskCoords); + expect(descriptorsCsv).toEqual(expectedResultsCsv); + }); + + it('Tick count may vary along with the ruler length', () => { + let labData = Fixtures.labData(); + + labData.rulerTickCount = 8; + labData.rulerCoords.end = labData.rulerCoords.start.add( + labData.rulerCoords.end.subtract(labData.rulerCoords.start).multiply(8).divide(10) + ) + + let descriptorsCsv = dataExporter.exportPathDescriptorsAsCsv(labData, labData.blobMaskCoords); + expect(descriptorsCsv).toEqual(expectedResultsCsv); + }); +}); \ No newline at end of file diff --git a/tests/fixtures/ExpJ1CrB9_Coord_Blob.txt b/tests/fixtures/ExpJ1CrB9_Coord_Blob.txt new file mode 100644 index 0000000000000000000000000000000000000000..b75420b95906d23a4758edad9ab7b8d790516e64 --- /dev/null +++ b/tests/fixtures/ExpJ1CrB9_Coord_Blob.txt @@ -0,0 +1,2422 @@ +851 785 +853 785 +856 785 +861 785 +863 785 +866 785 +868 785 +875 785 +878 785 +880 785 +882 782 +885 780 +890 778 +890 775 +895 773 +897 773 +899 773 +902 773 +904 773 +907 773 +909 773 +912 773 +916 770 +919 770 +924 770 +926 768 +928 768 +931 768 +933 766 +938 766 +941 766 +943 766 +948 766 +948 768 +953 768 +958 770 +960 773 +962 773 +967 775 +970 778 +972 780 +972 782 +974 782 +977 785 +979 787 +982 787 +984 787 +987 787 +989 787 +991 787 +996 787 +999 787 +1001 787 +1004 787 +1006 787 +1011 787 +1013 787 +1016 787 +1020 787 +1020 785 +1025 782 +1030 778 +1033 778 +1035 775 +1035 773 +1037 773 +1042 770 +1045 768 +1047 768 +1049 766 +1049 763 +1054 763 +1057 761 +1059 761 +1059 758 +1064 758 +1066 756 +1069 756 +1071 753 +1076 753 +1079 751 +1083 749 +1088 749 +1093 749 +1098 749 +1100 746 +1103 746 +1108 746 +1112 744 +1115 744 +1117 744 +1120 744 +1122 744 +1127 744 +1129 744 +1132 744 +1134 744 +1137 744 +1141 749 +1144 749 +1146 751 +1146 753 +1146 756 +1146 758 +1151 766 +1151 768 +1151 773 +1151 778 +1154 780 +1154 782 +1154 785 +1154 787 +1156 792 +1158 797 +1161 802 +1166 804 +1166 807 +1166 809 +1168 812 +1168 814 +1171 814 +1175 816 +1175 819 +1178 821 +1180 824 +1185 826 +1190 828 +1190 831 +1192 831 +1195 831 +1200 833 +1204 836 +1209 838 +1212 841 +1214 841 +1214 843 +1219 845 +1219 850 +1221 853 +1224 855 +1224 858 +1224 860 +1224 865 +1224 867 +1224 874 +1224 879 +1224 882 +1224 889 +1224 894 +1221 899 +1221 904 +1221 908 +1221 911 +1221 913 +1221 916 +1221 918 +1221 920 +1221 923 +1221 928 +1221 933 +1221 937 +1224 942 +1224 945 +1224 947 +1224 949 +1224 954 +1224 962 +1224 966 +1224 971 +1224 976 +1224 981 +1226 983 +1226 986 +1226 988 +1226 991 +1226 995 +1226 998 +1226 1000 +1226 1003 +1226 1005 +1226 1010 +1226 1012 +1226 1015 +1224 1020 +1219 1022 +1217 1022 +1214 1022 +1212 1025 +1209 1027 +1204 1029 +1200 1029 +1195 1034 +1192 1034 +1190 1034 +1187 1037 +1185 1037 +1185 1039 +1183 1041 +1183 1044 +1183 1046 +1175 1061 +1176 1061 +1176 1062 +1176 1065 +1176 1066 +1176 1069 +1176 1070 +1179 1074 +1179 1075 +1182 1076 +1184 1078 +1189 1080 +1193 1083 +1197 1086 +1200 1087 +1204 1089 +1208 1090 +1211 1092 +1214 1092 +1216 1092 +1218 1093 +1220 1094 +1221 1095 +1230 1098 +1237 1100 +1242 1101 +1244 1101 +1246 1101 +1247 1099 +1249 1099 +1251 1099 +1254 1098 +1259 1098 +1262 1096 +1264 1096 +1266 1096 +1267 1096 +1269 1096 +1270 1095 +1271 1095 +1274 1094 +1275 1094 +1278 1093 +1283 1093 +1288 1092 +1290 1092 +1291 1092 +1292 1092 +1294 1092 +1299 1092 +1303 1093 +1305 1094 +1306 1095 +1307 1096 +1308 1098 +1308 1099 +1308 1102 +1308 1103 +1308 1106 +1308 1109 +1308 1110 +1308 1113 +1308 1118 +1308 1119 +1308 1121 +1307 1124 +1305 1126 +1303 1130 +1301 1133 +1297 1137 +1297 1138 +1295 1140 +1294 1141 +1291 1141 +1289 1143 +1287 1143 +1284 1143 +1283 1143 +1281 1143 +1278 1143 +1274 1143 +1270 1142 +1267 1141 +1264 1140 +1263 1140 +1260 1138 +1259 1137 +1257 1136 +1254 1136 +1253 1135 +1252 1135 +1250 1135 +1247 1135 +1244 1134 +1239 1134 +1237 1134 +1236 1134 +1233 1136 +1230 1138 +1227 1139 +1225 1140 +1224 1141 +1223 1143 +1223 1144 +1223 1147 +1223 1149 +1223 1153 +1223 1156 +1224 1160 +1224 1163 +1226 1165 +1226 1167 +1226 1169 +1226 1170 +1227 1173 +1229 1177 +1229 1180 +1229 1183 +1230 1186 +1230 1188 +1230 1192 +1231 1195 +1232 1199 +1232 1201 +1232 1204 +1232 1206 +1232 1208 +1232 1210 +1232 1212 +1232 1214 +1232 1217 +1234 1220 +1235 1221 +1236 1222 +1236 1223 +1236 1224 +1236 1224 +1236 1226 +1236 1227 +1237 1228 +1237 1229 +1237 1231 +1238 1232 +1240 1234 +1240 1235 +1240 1237 +1240 1240 +1241 1241 +1242 1242 +1242 1244 +1242 1247 +1242 1251 +1242 1255 +1244 1261 +1246 1266 +1247 1271 +1248 1274 +1248 1276 +1249 1277 +1249 1278 +1249 1278 +1250 1279 +1250 1280 +1251 1281 +1253 1281 +1255 1281 +1257 1281 +1260 1281 +1266 1281 +1270 1281 +1274 1281 +1277 1281 +1282 1281 +1284 1281 +1288 1281 +1291 1281 +1294 1281 +1297 1281 +1297 1281 +1301 1281 +1304 1281 +1308 1281 +1309 1281 +1311 1282 +1311 1283 +1312 1284 +1314 1285 +1314 1286 +1317 1288 +1320 1291 +1320 1293 +1321 1294 +1321 1295 +1321 1296 +1321 1299 +1322 1303 +1323 1306 +1323 1309 +1323 1312 +1323 1314 +1323 1317 +1323 1321 +1323 1328 +1323 1330 +1323 1334 +1322 1335 +1321 1337 +1321 1339 +1320 1342 +1320 1345 +1319 1347 +1318 1348 +1318 1349 +1318 1349 +1324 1367 +1324 1369 +1324 1369 +1324 1372 +1324 1374 +1324 1375 +1324 1377 +1324 1379 +1324 1380 +1324 1382 +1324 1384 +1323 1385 +1323 1388 +1321 1389 +1321 1392 +1320 1394 +1319 1399 +1318 1400 +1316 1403 +1315 1406 +1314 1408 +1312 1412 +1312 1413 +1311 1419 +1310 1420 +1310 1423 +1309 1425 +1309 1427 +1309 1430 +1309 1433 +1309 1436 +1309 1439 +1309 1442 +1309 1444 +1309 1448 +1311 1452 +1314 1455 +1314 1456 +1314 1458 +1314 1460 +1314 1461 +1314 1462 +1314 1462 +1314 1463 +1314 1464 +1314 1467 +1314 1468 +1314 1470 +1314 1472 +1314 1474 +1314 1475 +1314 1478 +1313 1481 +1312 1484 +1312 1486 +1311 1487 +1311 1489 +1310 1491 +1309 1493 +1308 1496 +1308 1498 +1307 1499 +1307 1503 +1306 1505 +1306 1506 +1305 1507 +1303 1509 +1303 1512 +1301 1512 +1300 1514 +1299 1517 +1296 1520 +1293 1524 +1289 1530 +1286 1534 +1283 1539 +1279 1544 +1276 1549 +1274 1555 +1272 1558 +1271 1559 +1270 1561 +1270 1561 +1270 1562 +1270 1563 +1270 1565 +1269 1567 +1269 1568 +1269 1569 +1268 1572 +1266 1575 +1264 1579 +1264 1580 +1262 1584 +1262 1585 +1260 1586 +1259 1587 +1258 1588 +1258 1589 +1257 1589 +1256 1590 +1255 1591 +1253 1593 +1252 1593 +1250 1593 +1247 1596 +1245 1598 +1244 1599 +1241 1600 +1240 1601 +1240 1602 +1239 1603 +1239 1605 +1239 1605 +1239 1606 +1239 1607 +1239 1608 +1239 1609 +1239 1610 +1240 1611 +1240 1611 +1241 1613 +1242 1614 +1256 1625 +1256 1626 +1256 1627 +1257 1629 +1258 1631 +1259 1633 +1259 1636 +1260 1641 +1261 1647 +1261 1655 +1261 1658 +1261 1663 +1261 1666 +1261 1669 +1261 1670 +1261 1673 +1261 1674 +1260 1677 +1260 1680 +1260 1684 +1260 1685 +1260 1687 +1260 1689 +1260 1690 +1260 1693 +1260 1696 +1260 1698 +1260 1701 +1260 1703 +1260 1706 +1260 1707 +1262 1710 +1262 1714 +1265 1717 +1266 1719 +1267 1720 +1269 1722 +1273 1724 +1277 1725 +1279 1725 +1280 1725 +1281 1725 +1282 1725 +1283 1723 +1285 1722 +1286 1718 +1288 1716 +1288 1713 +1289 1712 +1290 1711 +1291 1709 +1293 1707 +1296 1704 +1297 1702 +1298 1701 +1300 1699 +1301 1698 +1303 1696 +1304 1693 +1305 1691 +1306 1689 +1308 1685 +1309 1684 +1310 1680 +1310 1677 +1311 1674 +1312 1672 +1314 1670 +1314 1669 +1314 1667 +1314 1665 +1315 1663 +1316 1662 +1317 1660 +1319 1658 +1322 1656 +1324 1654 +1326 1653 +1327 1652 +1329 1650 +1330 1650 +1330 1649 +1331 1649 +1332 1649 +1337 1649 +1338 1649 +1339 1649 +1340 1649 +1341 1649 +1344 1649 +1345 1651 +1347 1653 +1348 1654 +1348 1654 +1350 1660 +1352 1662 +1352 1665 +1352 1669 +1353 1672 +1353 1676 +1354 1679 +1354 1682 +1354 1686 +1355 1690 +1356 1692 +1357 1695 +1358 1696 +1359 1696 +1360 1699 +1363 1702 +1365 1704 +1366 1706 +1369 1706 +1369 1707 +1370 1707 +1372 1709 +1373 1711 +1374 1713 +1377 1717 +1378 1718 +1379 1718 +1380 1720 +1380 1722 +1380 1724 +1381 1726 +1381 1728 +1381 1729 +1381 1731 +1382 1733 +1382 1735 +1383 1736 +1383 1737 +1383 1738 +1383 1739 +1383 1742 +1381 1744 +1381 1746 +1381 1747 +1381 1749 +1381 1753 +1381 1755 +1381 1759 +1382 1760 +1383 1761 +1383 1763 +1383 1764 +1385 1767 +1387 1770 +1388 1770 +1388 1771 +1389 1772 +1391 1776 +1391 1777 +1392 1779 +1394 1780 +1394 1781 +1394 1782 +1396 1786 +1398 1788 +1400 1790 +1400 1791 +1401 1792 +1402 1793 +1402 1795 +1402 1796 +1402 1798 +1402 1799 +1402 1803 +1402 1805 +1402 1806 +1402 1808 +1402 1809 +1402 1810 +1402 1811 +1401 1812 +1400 1814 +1399 1815 +1399 1816 +1398 1817 +1398 1819 +1397 1819 +1397 1821 +1396 1823 +1396 1824 +1395 1825 +1395 1825 +1395 1826 +1395 1828 +1395 1830 +1395 1831 +1394 1832 +1394 1833 +1394 1835 +1394 1841 +1394 1845 +1394 1848 +1394 1850 +1394 1851 +1394 1852 +1394 1854 +1395 1854 +1396 1855 +1397 1856 +1396 1849 +1396 1850 +1397 1851 +1397 1852 +1398 1854 +1399 1857 +1399 1861 +1401 1864 +1401 1868 +1402 1870 +1402 1872 +1404 1872 +1404 1873 +1404 1874 +1404 1875 +1404 1876 +1404 1877 +1404 1878 +1404 1880 +1404 1881 +1404 1882 +1404 1883 +1404 1884 +1402 1884 +1401 1886 +1400 1886 +1399 1886 +1398 1888 +1397 1890 +1395 1890 +1391 1892 +1389 1892 +1387 1892 +1385 1893 +1382 1895 +1380 1896 +1379 1896 +1377 1898 +1375 1900 +1374 1900 +1373 1901 +1371 1902 +1369 1903 +1369 1904 +1368 1904 +1367 1904 +1365 1904 +1363 1904 +1363 1905 +1359 1905 +1357 1907 +1355 1907 +1351 1908 +1349 1909 +1346 1910 +1344 1911 +1343 1912 +1341 1912 +1335 1912 +1332 1912 +1329 1915 +1327 1915 +1325 1915 +1321 1915 +1318 1915 +1312 1915 +1308 1915 +1303 1915 +1300 1916 +1297 1916 +1294 1917 +1292 1917 +1290 1917 +1287 1917 +1285 1917 +1283 1917 +1279 1917 +1277 1917 +1271 1917 +1263 1917 +1260 1919 +1259 1919 +1258 1919 +1257 1919 +1255 1919 +1253 1919 +1251 1919 +1249 1919 +1248 1919 +1247 1919 +1246 1919 +1245 1920 +1242 1921 +1241 1921 +1240 1922 +1239 1922 +1236 1922 +1235 1923 +1233 1923 +1231 1923 +1229 1923 +1227 1923 +1225 1923 +1223 1923 +1222 1923 +1221 1923 +1220 1923 +1217 1923 +1217 1922 +1215 1921 +1213 1920 +1209 1919 +1207 1917 +1205 1917 +1205 1916 +1205 1915 +1204 1912 +1203 1911 +1203 1910 +1202 1910 +1201 1909 +1201 1908 +1199 1908 +1198 1908 +1197 1908 +1196 1908 +1195 1908 +1195 1907 +1193 1906 +1191 1905 +1190 1905 +1189 1904 +1187 1904 +1185 1902 +1185 1901 +1183 1900 +1183 1899 +1182 1898 +1181 1896 +1180 1895 +1180 1894 +1179 1893 +1179 1892 +1178 1891 +1177 1890 +1177 1889 +1177 1888 +1176 1887 +1176 1885 +1174 1883 +1174 1882 +1174 1881 +1174 1880 +1174 1879 +1174 1878 +1174 1877 +1174 1876 +1174 1874 +1174 1872 +1173 1871 +1173 1869 +1173 1866 +1173 1863 +1171 1860 +1171 1858 +1170 1855 +1168 1852 +1167 1849 +1166 1847 +1165 1844 +1163 1842 +1161 1837 +1160 1835 +1159 1833 +1158 1832 +1157 1830 +1154 1826 +1153 1825 +1151 1824 +1149 1822 +1148 1822 +1147 1821 +1145 1820 +1143 1818 +1141 1818 +1140 1817 +1138 1816 +1137 1816 +1135 1816 +1134 1816 +1132 1816 +1130 1815 +1129 1815 +1127 1814 +1124 1813 +1121 1812 +1119 1812 +1116 1812 +1111 1814 +1106 1814 +1105 1814 +1103 1814 +1101 1815 +1098 1815 +1095 1817 +1091 1818 +1087 1818 +1083 1822 +1079 1824 +1077 1825 +1074 1826 +1071 1828 +1067 1829 +1065 1831 +1063 1832 +1061 1834 +1059 1835 +1057 1836 +1056 1838 +1052 1838 +1049 1840 +1047 1840 +1047 1842 +1045 1843 +1044 1844 +1043 1845 +1041 1846 +1040 1846 +1037 1846 +1035 1846 +1031 1846 +1029 1846 +1028 1846 +1027 1846 +1025 1846 +1020 1842 +1017 1841 +1014 1839 +1012 1838 +1011 1838 +1011 1836 +1010 1836 +1008 1834 +1007 1833 +1006 1831 +1006 1830 +1006 1828 +1005 1827 +1005 1826 +1004 1824 +1002 1821 +1000 1819 +999 1818 +998 1817 +997 1816 +993 1814 +992 1814 +989 1813 +989 1812 +986 1809 +986 1809 +985 1808 +981 1806 +976 1803 +974 1801 +972 1799 +970 1796 +970 1794 +966 1792 +965 1787 +963 1785 +961 1784 +961 1783 +960 1782 +959 1782 +959 1782 +956 1782 +954 1782 +954 1782 +953 1782 +951 1784 +950 1786 +949 1788 +944 1794 +944 1797 +944 1801 +944 1803 +944 1804 +944 1807 +944 1811 +944 1813 +944 1816 +944 1819 +944 1821 +944 1823 +944 1824 +944 1824 +944 1826 +944 1828 +944 1829 +944 1829 +944 1831 +944 1831 +943 1831 +941 1831 +940 1831 +936 1830 +933 1829 +933 1829 +932 1829 +931 1829 +930 1829 +929 1829 +928 1831 +928 1833 +928 1834 +927 1834 +926 1837 +926 1838 +926 1839 +924 1840 +923 1840 +920 1841 +919 1841 +917 1841 +916 1841 +915 1841 +914 1841 +912 1841 +912 1841 +911 1840 +908 1839 +906 1839 +904 1838 +903 1837 +902 1836 +901 1836 +901 1835 +899 1834 +898 1833 +896 1831 +896 1831 +893 1829 +892 1829 +891 1828 +890 1827 +889 1826 +886 1825 +885 1824 +884 1824 +882 1823 +881 1823 +880 1821 +880 1820 +879 1819 +878 1818 +878 1818 +878 1817 +878 1816 +878 1814 +878 1813 +878 1812 +878 1811 +878 1809 +877 1808 +877 1808 +877 1806 +876 1803 +875 1803 +875 1801 +875 1800 +874 1798 +872 1797 +872 1796 +872 1794 +872 1792 +872 1791 +872 1790 +872 1789 +872 1787 +874 1785 +874 1783 +875 1782 +879 1781 +880 1779 +882 1777 +884 1776 +886 1774 +888 1771 +889 1771 +894 1768 +896 1767 +899 1766 +901 1764 +901 1764 +902 1761 +904 1760 +905 1760 +906 1759 +907 1757 +909 1755 +909 1753 +909 1750 +909 1749 +911 1746 +911 1745 +911 1742 +911 1736 +911 1732 +910 1730 +909 1727 +908 1726 +907 1726 +907 1725 +907 1725 +904 1725 +903 1725 +900 1725 +897 1727 +894 1729 +891 1732 +888 1734 +887 1736 +884 1741 +882 1744 +881 1745 +880 1746 +880 1747 +879 1748 +877 1749 +875 1749 +871 1750 +867 1751 +862 1753 +856 1755 +855 1755 +854 1755 +850 1755 +846 1755 +841 1755 +838 1755 +835 1755 +834 1755 +833 1755 +831 1755 +830 1755 +827 1755 +826 1757 +825 1757 +824 1757 +823 1757 +822 1757 +820 1757 +818 1757 +815 1757 +812 1757 +812 1757 +811 1757 +810 1757 +808 1757 +807 1757 +806 1757 +805 1757 +803 1757 +802 1757 +801 1756 +801 1756 +800 1755 +800 1755 +799 1754 +796 1754 +795 1752 +793 1752 +791 1751 +791 1751 +789 1751 +788 1751 +787 1751 +786 1751 +786 1750 +785 1750 +784 1750 +783 1749 +781 1749 +779 1747 +778 1747 +777 1746 +776 1745 +775 1745 +775 1743 +775 1742 +774 1741 +773 1740 +771 1739 +770 1738 +770 1737 +768 1736 +766 1736 +766 1735 +763 1734 +760 1734 +759 1733 +759 1732 +758 1731 +754 1730 +754 1729 +752 1729 +750 1729 +749 1729 +749 1728 +748 1727 +747 1726 +744 1725 +742 1724 +741 1724 +740 1723 +739 1722 +738 1721 +738 1720 +735 1718 +733 1718 +733 1718 +732 1717 +731 1717 +729 1715 +726 1713 +726 1713 +725 1712 +723 1711 +722 1710 +722 1709 +722 1708 +722 1708 +722 1707 +722 1700 +722 1699 +722 1698 +722 1697 +722 1696 +722 1695 +722 1692 +722 1690 +722 1688 +721 1685 +720 1683 +720 1681 +719 1679 +719 1677 +719 1675 +719 1672 +719 1672 +718 1671 +718 1670 +717 1668 +715 1667 +715 1665 +712 1663 +711 1661 +710 1659 +707 1657 +706 1656 +701 1652 +699 1650 +697 1649 +696 1647 +694 1646 +690 1644 +689 1643 +687 1643 +686 1642 +685 1642 +683 1642 +682 1641 +681 1640 +679 1640 +676 1639 +674 1639 +673 1638 +671 1636 +669 1636 +668 1635 +668 1634 +667 1633 +666 1633 +666 1633 +666 1632 +665 1631 +664 1630 +664 1628 +664 1626 +662 1625 +662 1624 +662 1621 +662 1619 +662 1617 +662 1617 +662 1615 +662 1614 +662 1613 +662 1612 +662 1611 +662 1610 +662 1608 +662 1607 +662 1605 +662 1605 +662 1604 +662 1603 +662 1601 +662 1598 +662 1598 +661 1596 +660 1596 +659 1596 +659 1595 +659 1594 +658 1593 +657 1591 +657 1591 +655 1590 +655 1589 +655 1587 +652 1587 +651 1585 +651 1584 +651 1584 +651 1583 +650 1582 +648 1580 +647 1578 +647 1577 +646 1577 +646 1576 +645 1576 +645 1575 +644 1574 +643 1573 +643 1573 +643 1572 +643 1570 +643 1570 +643 1569 +641 1567 +640 1565 +639 1562 +638 1558 +638 1557 +638 1554 +638 1552 +638 1551 +638 1550 +638 1550 +638 1549 +638 1548 +637 1547 +636 1547 +636 1546 +634 1545 +633 1544 +631 1543 +631 1542 +631 1541 +631 1540 +631 1540 +631 1539 +630 1538 +629 1537 +629 1536 +629 1536 +628 1534 +627 1534 +624 1532 +623 1532 +621 1531 +620 1531 +618 1531 +616 1531 +612 1529 +609 1527 +606 1526 +606 1526 +606 1525 +604 1523 +604 1522 +604 1520 +603 1517 +602 1515 +601 1514 +601 1513 +601 1513 +601 1510 +599 1508 +599 1506 +599 1506 +599 1505 +599 1503 +599 1503 +599 1502 +599 1501 +599 1500 +599 1499 +599 1498 +590 1480 +590 1479 +590 1478 +589 1477 +589 1477 +588 1475 +588 1474 +587 1473 +587 1472 +587 1471 +587 1471 +587 1469 +587 1467 +587 1466 +587 1464 +587 1463 +587 1463 +587 1461 +587 1460 +587 1459 +587 1456 +587 1453 +587 1449 +587 1448 +587 1446 +587 1444 +587 1443 +587 1442 +587 1441 +587 1440 +587 1434 +587 1429 +588 1424 +588 1423 +589 1423 +589 1423 +590 1422 +590 1421 +591 1421 +592 1421 +592 1420 +593 1419 +593 1419 +593 1419 +594 1419 +594 1419 +594 1419 +595 1419 +596 1419 +597 1419 +597 1419 +597 1418 +597 1418 +598 1416 +599 1415 +599 1413 +599 1411 +599 1409 +599 1407 +599 1405 +599 1403 +599 1401 +598 1400 +597 1399 +597 1399 +596 1398 +595 1398 +595 1398 +594 1397 +594 1397 +593 1396 +592 1395 +592 1394 +592 1394 +592 1393 +592 1392 +592 1391 +593 1389 +594 1389 +594 1388 +595 1388 +596 1387 +596 1387 +597 1386 +597 1386 +597 1386 +599 1385 +599 1384 +601 1382 +602 1381 +603 1381 +605 1378 +605 1378 +606 1378 +606 1378 +607 1377 +609 1377 +610 1377 +613 1376 +615 1376 +620 1375 +622 1375 +623 1374 +624 1374 +624 1374 +625 1374 +626 1374 +627 1374 +628 1374 +628 1374 +628 1373 +629 1373 +629 1373 +629 1372 +630 1372 +631 1371 +632 1370 +633 1368 +634 1366 +634 1365 +634 1364 +634 1363 +634 1363 +634 1362 +634 1362 +634 1361 +633 1360 +632 1359 +631 1358 +631 1358 +631 1358 +630 1357 +629 1356 +629 1355 +629 1353 +629 1353 +628 1351 +628 1350 +628 1349 +628 1348 +627 1348 +627 1348 +626 1347 +624 1346 +622 1345 +622 1345 +621 1344 +620 1343 +619 1343 +618 1343 +618 1342 +617 1341 +616 1340 +615 1340 +614 1340 +613 1339 +612 1339 +611 1338 +611 1337 +606 1335 +605 1334 +601 1331 +600 1331 +599 1330 +598 1330 +597 1329 +597 1329 +596 1328 +596 1327 +595 1326 +595 1325 +594 1323 +594 1322 +593 1321 +593 1319 +593 1316 +592 1312 +592 1310 +592 1309 +592 1308 +592 1307 +592 1306 +592 1305 +592 1303 +592 1302 +591 1302 +591 1301 +591 1300 +591 1298 +591 1297 +591 1296 +591 1295 +591 1294 +591 1292 +591 1291 +591 1290 +591 1289 +591 1288 +591 1287 +591 1286 +592 1285 +592 1284 +592 1283 +592 1283 +593 1282 +593 1282 +593 1281 +593 1281 +594 1281 +594 1281 +595 1281 +595 1281 +596 1280 +597 1280 +599 1280 +601 1280 +604 1280 +605 1280 +606 1280 +607 1280 +607 1280 +608 1280 +611 1280 +613 1280 +614 1280 +616 1280 +617 1280 +619 1280 +620 1279 +621 1279 +622 1279 +625 1278 +627 1278 +629 1278 +631 1277 +631 1276 +632 1275 +633 1275 +635 1274 +636 1274 +637 1273 +638 1273 +638 1273 +639 1272 +639 1272 +640 1272 +640 1272 +641 1271 +641 1270 +641 1270 +641 1270 +641 1270 +641 1269 +641 1269 +641 1269 +641 1267 +639 1266 +638 1265 +637 1265 +636 1264 +635 1263 +633 1262 +633 1261 +631 1260 +629 1259 +628 1258 +628 1258 +627 1257 +626 1256 +626 1256 +625 1255 +625 1254 +625 1254 +625 1254 +624 1253 +624 1253 +624 1253 +624 1252 +623 1252 +623 1251 +622 1250 +621 1249 +621 1249 +620 1247 +619 1246 +619 1246 +618 1245 +618 1245 +617 1244 +617 1244 +617 1244 +616 1243 +616 1242 +616 1242 +616 1242 +615 1240 +614 1238 +614 1237 +613 1236 +613 1236 +614 1235 +614 1223 +614 1222 +614 1221 +614 1221 +614 1220 +614 1219 +614 1218 +614 1217 +614 1217 +614 1216 +614 1215 +614 1214 +614 1214 +614 1213 +614 1212 +614 1211 +614 1210 +614 1209 +614 1209 +614 1208 +614 1208 +614 1207 +614 1207 +614 1207 +613 1207 +612 1206 +611 1205 +609 1205 +607 1204 +607 1204 +605 1203 +604 1203 +602 1203 +600 1203 +598 1203 +597 1203 +596 1203 +595 1203 +595 1203 +594 1203 +593 1203 +592 1203 +590 1204 +589 1204 +587 1204 +586 1204 +584 1204 +582 1204 +581 1204 +579 1204 +579 1203 +578 1203 +577 1202 +576 1202 +574 1201 +572 1200 +571 1200 +571 1200 +570 1199 +569 1198 +568 1198 +568 1197 +568 1195 +567 1194 +566 1193 +566 1193 +566 1192 +566 1192 +566 1191 +566 1190 +566 1189 +566 1189 +566 1188 +566 1187 +566 1186 +566 1186 +567 1184 +567 1184 +568 1183 +568 1182 +568 1181 +569 1180 +569 1180 +570 1180 +571 1179 +572 1179 +573 1179 +573 1178 +574 1178 +575 1178 +578 1178 +579 1177 +580 1177 +582 1177 +584 1177 +585 1177 +587 1177 +589 1178 +590 1178 +591 1179 +592 1179 +595 1180 +596 1181 +597 1181 +597 1181 +597 1181 +598 1182 +599 1182 +601 1183 +604 1185 +604 1185 +606 1186 +607 1186 +608 1186 +609 1186 +609 1186 +610 1186 +610 1186 +611 1185 +611 1185 +612 1184 +612 1183 +613 1183 +613 1182 +614 1181 +614 1181 +614 1179 +615 1179 +615 1178 +615 1178 +615 1177 +616 1177 +616 1176 +617 1175 +617 1174 +617 1173 +617 1172 +617 1172 +617 1172 +617 1171 +617 1170 +618 1170 +618 1169 +618 1169 +618 1168 +618 1167 +619 1166 +620 1165 +620 1165 +621 1163 +621 1163 +621 1162 +621 1161 +622 1160 +622 1159 +622 1158 +622 1158 +622 1156 +623 1155 +624 1154 +624 1152 +624 1152 +624 1151 +624 1151 +624 1150 +624 1149 +624 1148 +622 1146 +622 1145 +622 1144 +621 1143 +620 1140 +618 1136 +618 1134 +617 1132 +617 1132 +616 1129 +615 1128 +615 1128 +616 1127 +616 1127 +617 1126 +618 1125 +618 1124 +618 1123 +618 1122 +619 1122 +620 1122 +622 1121 +622 1120 +623 1120 +623 1120 +624 1119 +624 1119 +625 1118 +625 1118 +625 1117 +625 1111 +625 1110 +625 1109 +626 1108 +626 1106 +626 1105 +626 1102 +625 1100 +625 1099 +625 1098 +625 1098 +625 1097 +624 1094 +623 1094 +623 1093 +623 1092 +622 1091 +622 1090 +621 1088 +621 1087 +621 1086 +621 1085 +621 1085 +620 1084 +620 1083 +620 1083 +620 1082 +620 1082 +620 1082 +620 1081 +620 1081 +620 1080 +620 1079 +620 1079 +620 1078 +620 1078 +620 1078 +621 1076 +621 1075 +622 1075 +622 1074 +623 1074 +623 1074 +624 1073 +625 1073 +625 1072 +625 1072 +625 1071 +626 1071 +627 1070 +627 1070 +627 1069 +627 1069 +628 1069 +628 1068 +628 1068 +629 1068 +629 1068 +630 1068 +632 1068 +634 1067 +636 1067 +636 1067 +636 1067 +637 1067 +639 1067 +640 1067 +640 1067 +640 1067 +641 1067 +642 1067 +643 1067 +644 1067 +645 1067 +645 1067 +646 1067 +646 1067 +647 1067 +648 1067 +648 1067 +649 1067 +649 1067 +649 1067 +650 1067 +650 1067 +651 1067 +651 1066 +651 1066 +651 1066 +651 1066 +652 1065 +652 1064 +652 1064 +653 1062 +653 1062 +653 1061 +653 1060 +653 1059 +653 1059 +653 1058 +653 1057 +653 1056 +654 1053 +654 1052 +654 1051 +654 1049 +655 1048 +655 1047 +655 1047 +655 1047 +656 1046 +656 1046 +656 1045 +656 1045 +656 1045 +657 1044 +657 1044 +657 1043 +657 1043 +657 1043 +657 1042 +658 1042 +658 1041 +658 1040 +659 1040 +659 1040 +660 1039 +660 1039 +661 1038 +661 1037 +662 1036 +662 1035 +663 1034 +664 1031 +665 1029 +666 1028 +667 1027 +667 1026 +668 1025 +668 1024 +669 1023 +669 1022 +669 1022 +669 1022 +669 1022 +669 1021 +670 1021 +670 1021 +671 1020 +671 1019 +671 1018 +672 1018 +672 1017 +672 1016 +672 1016 +672 1016 +672 1014 +672 1013 +672 1012 +672 1011 +672 1011 +672 1011 +672 1003 +673 1003 +673 1002 +673 1002 +674 1000 +676 998 +677 996 +678 995 +678 994 +679 993 +680 992 +681 990 +682 989 +683 986 +684 985 +685 985 +685 985 +686 984 +686 984 +687 983 +688 982 +688 980 +689 979 +689 978 +690 976 +690 974 +690 972 +691 972 +691 970 +691 969 +691 966 +691 965 +691 964 +691 963 +692 962 +692 961 +692 960 +692 959 +693 959 +693 958 +693 957 +693 955 +693 955 +694 954 +694 953 +694 952 +695 952 +695 951 +695 951 +696 949 +697 948 +697 946 +698 943 +699 942 +699 942 +699 941 +700 941 +700 941 +701 941 +702 940 +704 938 +706 937 +707 936 +707 935 +707 935 +708 935 +708 934 +709 933 +709 932 +710 930 +711 929 +712 928 +714 926 +717 920 +718 918 +719 916 +719 915 +720 915 +720 915 +720 915 +721 915 +722 914 +723 914 +723 913 +723 913 +723 913 +724 913 +724 913 +724 912 +724 912 +724 912 +725 912 +725 911 +725 911 +725 910 +737 907 +737 907 +738 905 +738 904 +740 903 +740 902 +740 901 +740 900 +740 899 +738 898 +737 896 +733 895 +733 894 +733 894 +733 894 +733 893 +733 892 +732 891 +732 890 +732 888 +732 887 +732 886 +731 884 +731 882 +731 880 +731 878 +731 877 +731 876 +731 874 +731 874 +732 873 +732 873 +732 872 +734 870 +735 868 +735 867 +736 867 +736 867 +737 865 +738 864 +740 862 +741 861 +742 859 +744 858 +745 857 +747 856 +748 855 +750 854 +752 853 +754 852 +756 851 +757 849 +759 849 +760 848 +762 847 +764 845 +765 844 +767 844 +767 843 +769 842 +771 842 +772 841 +773 841 +774 841 +775 840 +777 840 +778 840 +779 840 +780 840 +781 840 +783 840 +783 840 +784 840 +785 840 +785 841 +786 842 +787 842 +787 843 +787 843 +787 844 +787 845 +787 846 +787 847 +787 848 +787 849 +787 850 +787 852 +787 852 +788 854 +788 855 +788 858 +788 859 +788 862 +788 863 +789 865 +790 867 +790 867 +790 869 +790 872 +790 873 +790 874 +790 875 +790 876 +790 877 +791 878 +791 879 +791 880 +792 882 +792 883 +792 883 +793 884 +793 885 +795 887 +796 889 +797 890 +797 891 +798 891 +800 892 +801 891 +802 890 +802 889 +802 887 +803 886 +803 884 +803 882 +803 879 +803 877 +802 874 +802 872 +802 870 +801 865 +800 863 +799 861 +799 860 +799 857 +799 856 +798 854 +798 853 +798 852 +798 851 +798 850 +798 848 +798 847 +798 846 +798 846 +798 845 +799 844 +800 843 +801 843 +801 842 +803 841 +804 841 +806 841 +806 841 +807 841 +808 841 +809 841 +809 841 +810 841 +813 842 +814 843 +815 843 +816 843 +816 842 +816 842 +816 842 +816 841 +816 840 +816 839 +815 839 +815 838 +814 838 +814 837 +813 836 +812 835 +812 834 +811 834 +810 832 +810 831 +809 830 +809 830 +808 830 +808 829 +808 829 +808 827 +808 827 +808 826 +808 825 +809 820 +811 816 +812 812 +813 810 +814 810 +814 810 +815 810 +815 810 +817 810 +821 810 +824 810 +827 810 +828 810 +829 810 +830 810 +831 810 +832 808 +832 807 +833 807 +833 807 +834 806 +835 805 +837 804 +838 804 +839 803 +839 803 +840 802 +840 802 +842 802 +844 802 +846 802 +850 796 +851 796 +851 796 +851 796 +851 796 +851 795 diff --git a/tests/fixtures/Results_ExpJ1CrB9.csv b/tests/fixtures/Results_ExpJ1CrB9.csv new file mode 100644 index 0000000000000000000000000000000000000000..6d2caa0fc90d8ea188ec25d5b634648028981f5e --- /dev/null +++ b/tests/fixtures/Results_ExpJ1CrB9.csv @@ -0,0 +1,2 @@ + ,Label,Area,Perim.,Circ.,AR,Round,Solidity +1,ExpJ1CrB9.jpg,33.4,33.93,0.365,1.625,0.615,0.871 \ No newline at end of file diff --git a/tests/fixtures/fixtures.ts b/tests/fixtures/fixtures.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c85fd40c2c6cb2e1535f4fb4ee2ff32684673da --- /dev/null +++ b/tests/fixtures/fixtures.ts @@ -0,0 +1,37 @@ +/** + * Une classe utilitaire pour données mockées + */ +import expJ1CrB9CoordBlobTxt from './ExpJ1CrB9_Coord_Blob.txt'; +import {DataImporter} from "../../src/data/dataImporter"; +import {LabData} from "../../src/lab"; +import {VectorCoords} from "../../src/data/coords/vectorCoords"; +import {EllipseCoords} from "../../src/data/coords/ellipseCoords"; + +/** + * Charge des données de tes + */ +export class Fixtures { + + /** + * Pour charger les données brutes + */ + private static dataImporter = new DataImporter(); + + /** + * Contenu de ExpJ1CrB9_Coord_Blob.txt + */ + public static labData() : LabData { + return { + filename: "ExpJ1CrB9.jpg", + pictureSize: new paper.Size(2250, 4000), + rulerCoords: new VectorCoords( new paper.Point(542,438), new paper.Point(1929, 398)), + rulerTickCount : 10, + petriDishCoords: new EllipseCoords(new paper.Point(1172, 1305), 631, 625), + blobMaskCoords : this.dataImporter.import(expJ1CrB9CoordBlobTxt), + } + } + + + + +} \ No newline at end of file diff --git a/tests/index.ts b/tests/index.ts index ffe8c21fbc5b299a6404e1eeb2d135eae8345711..ac572228580fd493d5cf9b8ac4d7136a1bd257c6 100644 --- a/tests/index.ts +++ b/tests/index.ts @@ -8,5 +8,4 @@ let canvas = document.createElement('canvas'); canvas.width = 1224; canvas.height = 768; -paper.setup(canvas); -console.log("canvas inited") \ No newline at end of file +paper.setup(canvas); \ No newline at end of file diff --git a/webpack.common.js b/webpack.common.js index f5f2f2b597eddbcb2005ffec8b86a73e6ca5b305..c9047f631f111c094123d3b835f95212af75c0e5 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -12,6 +12,10 @@ module.exports = { use: 'ts-loader', exclude: /node_modules/, }, + { + test: /\.(txt|csv)/, + type: 'asset/source', + }, { test: /\.svg$/, use: ['@svgr/webpack'],