diff options
-rw-r--r-- | docs/user_guide/utils/demonstrations_scripts.md | 8 | ||||
-rw-r--r-- | src/argaze/utils/contexts/File.py | 213 | ||||
-rw-r--r-- | src/argaze/utils/demo/csv_file_context.json | 10 | ||||
-rw-r--r-- | src/argaze/utils/demo/gaze_positions.csv | 1052 |
4 files changed, 1283 insertions, 0 deletions
diff --git a/docs/user_guide/utils/demonstrations_scripts.md b/docs/user_guide/utils/demonstrations_scripts.md index 277f380..e55e547 100644 --- a/docs/user_guide/utils/demonstrations_scripts.md +++ b/docs/user_guide/utils/demonstrations_scripts.md @@ -20,6 +20,14 @@ Load **random_context.json** file to generate random gaze positions: python -m argaze load ./src/argaze/utils/demo/random_context.json ``` +## CSV file context + +Load **csv_file_context.json** file to analyze gaze positions from a CSV file: + +```shell +python -m argaze load ./src/argaze/utils/demo/csv_file_context.json +``` + ## OpenCV ### Cursor context diff --git a/src/argaze/utils/contexts/File.py b/src/argaze/utils/contexts/File.py new file mode 100644 index 0000000..91c64e2 --- /dev/null +++ b/src/argaze/utils/contexts/File.py @@ -0,0 +1,213 @@ +"""Define eye tracking data file context""" + +""" +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program. If not, see <https://www.gnu.org/licenses/>. +""" + +__author__ = "Théo de la Hogue" +__credits__ = [] +__copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" +__license__ = "GPLv3" + +import logging +import time +import math +import threading + +import pandas +import numpy + +from argaze import ArFeatures, DataFeatures, GazeFeatures + + +class CSV(ArFeatures.DataPlaybackContext): + + @DataFeatures.PipelineStepInit + def __init__(self, **kwargs): + + # Init ArContext class + super().__init__() + + # Init private attributes + self.__path = None + self.__separator = ',' + self.__timestamp_column = None + self.__x_column = None + self.__y_column = None + self.__start = math.nan + self.__end = math.nan + self.__duration = 0. + self.__progression = 0. + + @property + def path(self) -> str: + """Path to data file.""" + return self.__path + + @path.setter + def path(self, path: str): + + self.__path = path + + @property + def separator(self) -> str: + """Value delimiter character""" + return self.__separator + + @separator.setter + def separator(self, separator: str): + + self.__separator = separator + + @property + def timestamp_column(self) -> str: + """Select timestamp column.""" + return self.__timestamp_column + + @timestamp_column.setter + def timestamp_column(self, timestamp_column: str): + + self.__timestamp_column = timestamp_column + + @property + def x_column(self) -> str: + """Select x column.""" + return self.__x_column + + @x_column.setter + def x_column(self, x_column: str): + + self.__x_column = x_column + + @property + def y_column(self) -> str: + """Select y column.""" + return self.__y_column + + @y_column.setter + def y_column(self, y_column: str): + + self.__y_column = y_column + @property + def start(self) -> int|float: + """Start reading timestamp.""" + return self.__start + + @start.setter + def start(self, start: int|float): + + self.__start = start + + @property + def end(self) -> int|float: + """End reading timestamp.""" + return self.__end + + @end.setter + def end(self, end: int|float): + + self.__end = end + + @property + def duration(self) -> int|float: + """Get data duration.""" + + return self.__duration + + @property + def progression(self) -> float: + """Get data processing progression between 0 and 1.""" + + return self.__progression + + @DataFeatures.PipelineStepEnter + def __enter__(self): + + logging.info('CSV file context starts...') + + # Load gaze positions from a CSV file into Panda Dataframe + data_selector = { + self.__timestamp_column: numpy.float64, + self.__x_column: numpy.float64, + self.__y_column: numpy.float64 + } + + dataframe = pandas.read_csv(self.__path, delimiter = self.__separator, low_memory = False, usecols=data_selector.keys(), dtype=data_selector) + + # Rename columns with generic names + dataframe.rename(columns={ + self.__timestamp_column: 'timestamp', + self.__x_column: 'x', + self.__y_column: 'y' + }, inplace=True) + + # Optionnaly select a time range + if not math.isnan(self.start): + + dataframe = dataframe.loc[(dataframe['timestamp'] >= self.start)] + + if not math.isnan(self.end): + + dataframe = dataframe.loc[(dataframe['timestamp'] <= self.end)] + + # Filter unvalid gaze positions + len_before = len(dataframe) + dataframe = dataframe[(dataframe['x'].notna() & dataframe['y']).notna()] + + if len(dataframe) != len_before: + logging.info('%i unvalid gaze positions have been removed', len_before - len(dataframe)) + + # Open reading thread + self.__reading_thread = threading.Thread(target=self.__read, kwargs={'dataframe': dataframe}) + + logging.debug('> starting reading thread...') + self.__reading_thread.start() + + @DataFeatures.PipelineStepExit + def __exit__(self, exception_type, exception_value, exception_traceback): + + logging.info('CSV file context stops...') + + # Close data stream + self.stop() + + # Stop reading thread + threading.Thread.join(self.__reading_thread) + + def __read(self, dataframe: pandas.DataFrame): + """Read and process gaze positions from dataframe.""" + + start_ts = dataframe.iloc[0].timestamp + end_ts = dataframe.iloc[-1].timestamp + + self.__duration = end_ts - start_ts + self.__progression = 0. + + logging.info('Reading %i gaze positions from %s to %s...', len(dataframe), f'{start_ts}', f'{end_ts}') + + for index, row in dataframe.iterrows(): + + # Stop reading + if not self.is_running(): + + break + + # Pause reading + while self.is_paused() and self.is_running(): + + time.sleep(0.1) + + # Process gaze position + self._process_gaze_position(x = row['x'], y = row['y'], timestamp = row['timestamp']) + + # Update progression + self.__progression = row['timestamp'] / self.__duration + diff --git a/src/argaze/utils/demo/csv_file_context.json b/src/argaze/utils/demo/csv_file_context.json new file mode 100644 index 0000000..a09914f --- /dev/null +++ b/src/argaze/utils/demo/csv_file_context.json @@ -0,0 +1,10 @@ +{ + "argaze.utils.contexts.File.CSV" : { + "name": "CSV file data playback", + "path": "./src/argaze/utils/demo/gaze_positions.csv", + "timestamp_column": "Timestamp (ms)", + "x_column": "Gaze Position X (px)", + "y_column": "Gaze Position Y (px)", + "pipeline": "gaze_analysis_pipeline.json" + } +}
\ No newline at end of file diff --git a/src/argaze/utils/demo/gaze_positions.csv b/src/argaze/utils/demo/gaze_positions.csv new file mode 100644 index 0000000..558c995 --- /dev/null +++ b/src/argaze/utils/demo/gaze_positions.csv @@ -0,0 +1,1052 @@ +"Timestamp (ms)","Gaze Position X (px)","Gaze Position Y (px)"
+6016,400,443
+6056,400,443
+6106,401,443
+6128,401,443
+6168,401,442
+6367,401,442
+6409,401,442
+6486,401,442
+7310,408,433
+7334,415,427
+7375,435,412
+7397,441,409
+7438,445,405
+7472,446,405
+7509,446,404
+7532,446,404
+7570,449,392
+7593,450,384
+7631,450,378
+7653,450,377
+7705,432,371
+7730,415,365
+7766,390,353
+7788,376,345
+7828,334,318
+7847,318,306
+7890,296,288
+7912,286,277
+7950,278,263
+7978,275,256
+8018,268,246
+8039,266,245
+8074,265,244
+8092,264,243
+8128,262,243
+8185,263,242
+8205,264,241
+8241,265,231
+8261,265,228
+8305,267,227
+8337,267,226
+8392,267,228
+8427,269,232
+8445,270,232
+8481,272,231
+8501,273,228
+8537,273,219
+8558,272,217
+8592,272,217
+8613,271,218
+8650,271,222
+8671,271,225
+8703,272,227
+8724,272,227
+8755,274,227
+8776,274,226
+8813,275,224
+8834,275,223
+8866,275,223
+8886,279,225
+8922,292,228
+8944,312,227
+8981,351,222
+9000,382,218
+9033,424,214
+9053,447,213
+9087,510,216
+9104,538,216
+9137,591,218
+9156,620,220
+9192,691,219
+9212,719,216
+9246,788,214
+9267,812,215
+9300,855,216
+9319,878,215
+9352,900,215
+9371,907,216
+9403,915,217
+9420,915,217
+9464,915,217
+9484,915,218
+9519,913,219
+9538,912,219
+9573,904,222
+9592,893,224
+9626,875,225
+9645,871,226
+9677,869,226
+9738,869,227
+9760,870,229
+9798,872,231
+9818,872,231
+9851,875,232
+9871,879,232
+9904,883,230
+9925,884,229
+9963,886,228
+9984,886,227
+10073,887,229
+10125,892,234
+10146,894,234
+10181,895,233
+10202,896,231
+10232,896,229
+10252,896,229
+10341,896,229
+10363,896,232
+10399,894,247
+10420,894,254
+10454,890,274
+10472,887,284
+10519,866,316
+10540,858,328
+10573,842,352
+10590,830,370
+10621,816,386
+10641,801,399
+10671,780,415
+10690,770,422
+10723,749,435
+10742,734,442
+10772,717,449
+10790,699,458
+10823,673,468
+10839,659,471
+10868,639,477
+10885,625,481
+10921,597,492
+10941,587,496
+10975,566,508
+10991,558,513
+11025,545,523
+11044,542,527
+11078,537,536
+11095,536,540
+11126,535,548
+11142,535,551
+11177,538,556
+11196,538,557
+11230,541,559
+11247,542,559
+11288,542,559
+11331,542,559
+11349,541,559
+11383,540,558
+11441,542,558
+11462,544,559
+11497,552,562
+11518,558,566
+11549,561,569
+11571,562,569
+11605,562,570
+11657,565,564
+11676,565,561
+11711,564,557
+11766,564,558
+11787,565,560
+11822,569,569
+11841,569,570
+11877,571,570
+11898,572,568
+11933,573,564
+11954,574,561
+11988,575,559
+12009,575,559
+12078,575,560
+12115,578,564
+12137,583,565
+12171,599,560
+12192,607,549
+12229,612,537
+12254,613,535
+12288,613,536
+12305,613,537
+12334,613,539
+12354,613,539
+12388,617,541
+12406,624,540
+12438,638,534
+12458,647,530
+12495,685,512
+12515,706,502
+12547,752,474
+12567,779,449
+12602,811,405
+12622,830,380
+12653,848,359
+12671,864,341
+12706,881,316
+12726,887,308
+12760,890,305
+12776,892,305
+12812,896,301
+12831,898,300
+12868,901,299
+12888,911,296
+12926,928,284
+12947,936,280
+12983,957,266
+13000,963,262
+13034,969,257
+13053,969,257
+13087,969,258
+13108,969,260
+13142,970,266
+13159,971,267
+13189,971,267
+13216,972,266
+13249,972,261
+13271,970,256
+13310,964,252
+13331,963,252
+13367,962,253
+13388,962,255
+13422,962,257
+13443,963,257
+13480,964,256
+13500,964,255
+13536,964,253
+13556,964,253
+13590,964,254
+13611,964,255
+13647,965,257
+13668,965,257
+13705,966,256
+13725,967,253
+13762,959,243
+13782,944,238
+13816,914,234
+13837,893,233
+13870,830,223
+13890,806,216
+13922,751,204
+13941,718,201
+13974,655,192
+13993,629,188
+14030,565,184
+14051,539,184
+14082,491,186
+14100,467,186
+14132,420,189
+14150,393,189
+14182,363,190
+14198,349,189
+14232,324,188
+14252,315,188
+14286,306,190
+14305,303,190
+14338,295,191
+14358,295,191
+14394,295,190
+14414,296,190
+14448,299,188
+14468,302,186
+14501,311,178
+14521,317,174
+14556,319,174
+14614,318,177
+14634,318,181
+14666,318,182
+14686,319,182
+14721,320,181
+14741,320,180
+14776,319,179
+14795,318,179
+14835,313,181
+14856,312,185
+14896,312,186
+14917,312,186
+14950,315,185
+14971,316,184
+15007,316,182
+15027,315,182
+15069,309,182
+15094,302,187
+15127,285,199
+15144,276,205
+15178,261,219
+15204,256,223
+15238,250,229
+15256,243,239
+15290,235,263
+15309,229,274
+15344,217,294
+15363,212,302
+15400,205,314
+15419,204,314
+15453,204,314
+15482,203,313
+15517,204,307
+15537,204,305
+15569,203,304
+15586,203,303
+15621,202,303
+15641,203,302
+15673,208,296
+15694,209,294
+15732,210,291
+15753,210,291
+15790,210,290
+15808,210,291
+15842,211,292
+15861,211,292
+15899,212,292
+15924,212,291
+15955,209,290
+15973,209,290
+16010,208,291
+16032,208,291
+16070,208,287
+16091,210,279
+16122,210,258
+16140,208,244
+16174,205,213
+16193,204,203
+16223,203,195
+16239,203,192
+16273,203,190
+16291,203,190
+16325,203,192
+16345,205,202
+16377,210,210
+16397,211,210
+16433,213,208
+16454,213,205
+16488,211,202
+16507,211,202
+16543,211,202
+16565,211,203
+16600,212,205
+16621,213,206
+16654,214,206
+16674,214,206
+16713,214,203
+16734,213,203
+16768,212,203
+16788,213,206
+16823,223,224
+16843,227,229
+16876,241,236
+16894,252,242
+16930,263,252
+16950,269,258
+16987,273,262
+17006,278,267
+17037,284,272
+17054,288,275
+17089,290,275
+17106,291,276
+17139,299,282
+17162,303,285
+17197,305,286
+17217,306,287
+17256,307,287
+17277,307,285
+17315,302,279
+17337,302,279
+17373,304,281
+17394,306,282
+17427,308,281
+17448,308,281
+17484,308,280
+17505,307,280
+17544,308,281
+17567,309,282
+17603,316,285
+17624,326,291
+17662,350,319
+17683,361,336
+17719,389,378
+17738,403,396
+17768,435,430
+17788,451,444
+17822,486,473
+17842,499,482
+17875,523,500
+17894,538,510
+17928,552,519
+17947,557,522
+17981,565,528
+17998,566,529
+18033,568,527
+18051,569,527
+18085,572,527
+18102,573,526
+18136,574,522
+18153,575,520
+18185,578,518
+18206,579,517
+18242,580,517
+18300,581,517
+18321,582,517
+18359,585,513
+18379,586,509
+18411,590,498
+18432,592,491
+18467,593,487
+18489,594,487
+18527,594,486
+18582,595,490
+18601,596,490
+18638,597,491
+18660,598,490
+18696,599,483
+18717,599,481
+18750,599,480
+18771,600,483
+18810,603,496
+18830,604,500
+18866,609,508
+18888,613,513
+18924,614,513
+18945,615,514
+18983,621,530
+19001,622,538
+19035,624,548
+19060,625,554
+19093,626,567
+19110,626,570
+19145,626,571
+19164,626,572
+19199,628,576
+19218,628,576
+19249,631,576
+19266,632,575
+19304,633,573
+19325,633,573
+19405,633,574
+19428,637,576
+19467,642,578
+19488,642,578
+19546,643,578
+19583,644,577
+19604,645,576
+19636,649,572
+19654,651,569
+19686,654,567
+19707,657,565
+19745,666,559
+19764,672,555
+19801,691,535
+19822,704,514
+19853,720,489
+19872,740,462
+19907,771,419
+19926,791,382
+19960,814,335
+19977,825,315
+20010,846,289
+20030,859,275
+20063,877,258
+20080,885,249
+20115,897,240
+20134,901,238
+20170,902,239
+20190,903,246
+20224,905,252
+20242,906,253
+20277,908,258
+20296,910,266
+20330,911,275
+20350,910,276
+20384,910,279
+20404,909,282
+20443,908,289
+20464,908,290
+20560,907,290
+20597,907,290
+20630,907,289
+20665,907,286
+20686,907,285
+20745,907,286
+20777,908,288
+20798,911,288
+20835,923,283
+20854,937,272
+20891,955,247
+20913,964,231
+20947,973,211
+20968,980,196
+21004,986,175
+21021,989,166
+21054,990,142
+21071,989,135
+21100,988,129
+21120,987,129
+21156,983,131
+21177,980,134
+21213,978,137
+21232,977,142
+21270,974,158
+21292,974,162
+21326,969,169
+21348,969,172
+21381,967,177
+21402,965,180
+21436,965,181
+21494,965,179
+21516,964,179
+21554,959,178
+21572,957,178
+21607,949,181
+21629,948,182
+21666,947,183
+21686,947,184
+21723,942,185
+21745,936,185
+21778,920,183
+21797,910,181
+21833,892,180
+21854,890,181
+21889,889,181
+21918,889,181
+21954,895,186
+21973,903,189
+22008,922,198
+22029,928,200
+22069,930,200
+22091,928,200
+22128,909,192
+22149,902,191
+22182,895,191
+22205,894,191
+22251,893,191
+22278,894,193
+22317,894,194
+22338,894,194
+22375,895,194
+22396,896,193
+22433,900,188
+22454,902,187
+22492,915,187
+22513,920,188
+22550,924,190
+22571,930,195
+22609,949,212
+22631,962,219
+22667,979,225
+22686,991,226
+22717,1000,227
+22734,1004,228
+22770,1005,228
+22790,1005,230
+22821,1005,231
+22850,1005,231
+22886,1003,231
+22906,1001,231
+22943,985,232
+22964,975,231
+23003,959,230
+23025,956,231
+23063,954,233
+23084,954,233
+23116,954,235
+23135,956,236
+23174,956,239
+23195,956,241
+23231,954,244
+23250,953,244
+23288,948,242
+23309,941,239
+23347,918,228
+23366,906,226
+23404,898,224
+23424,894,223
+23460,892,221
+23480,890,221
+23513,890,222
+23530,891,224
+23568,893,229
+23589,894,232
+23625,905,245
+23646,912,248
+23682,930,248
+23704,932,248
+23742,931,247
+23760,930,247
+23793,928,248
+23814,927,249
+23854,926,251
+23876,926,252
+23908,926,252
+23927,926,252
+23967,926,254
+23989,926,255
+24027,928,258
+24049,930,259
+24081,932,258
+24102,933,252
+24141,929,240
+24163,929,239
+24213,929,239
+24235,930,239
+24269,940,247
+24290,951,258
+24327,958,264
+24345,958,264
+24385,958,265
+24404,959,266
+24440,959,268
+24463,959,272
+24504,962,283
+24525,963,285
+24559,961,285
+24579,961,285
+24616,955,282
+24638,953,282
+24673,948,279
+24691,944,276
+24724,939,272
+24744,938,272
+24781,937,272
+24802,937,272
+24837,940,272
+24858,943,270
+24898,944,260
+24920,941,257
+24956,933,256
+24978,931,257
+25011,929,262
+25030,929,263
+25072,931,266
+25093,931,266
+25129,924,267
+25150,909,266
+25188,879,261
+25210,847,260
+25245,797,265
+25263,759,274
+25298,682,286
+25318,629,288
+25353,472,278
+25373,412,270
+25407,273,250
+25427,239,243
+25461,187,227
+25481,158,210
+25518,147,198
+25538,147,198
+25568,147,198
+25589,149,198
+25629,174,201
+25649,194,206
+25686,235,222
+25704,252,229
+25738,281,236
+25758,291,237
+25794,296,238
+25824,296,238
+25860,296,242
+25880,296,243
+25934,296,243
+25972,297,243
+25991,297,243
+26026,297,244
+26046,298,247
+26078,301,249
+26098,302,249
+26137,303,246
+26158,303,244
+26195,302,243
+26213,302,243
+26251,300,250
+26271,300,251
+26302,300,251
+26321,303,248
+26358,305,243
+26376,303,240
+26409,302,239
+26431,301,239
+26470,295,240
+26492,293,241
+26529,291,242
+26550,291,242
+26588,287,238
+26609,284,237
+26642,279,235
+26663,277,237
+26702,272,246
+26723,267,254
+26761,262,268
+26782,259,272
+26821,258,273
+26840,257,272
+26877,246,268
+26902,242,268
+26937,242,268
+26955,245,266
+26993,267,263
+27013,274,262
+27046,278,258
+27066,280,251
+27102,279,246
+27149,279,247
+27171,280,250
+27205,289,252
+27224,294,249
+27259,298,239
+27280,298,223
+27315,296,208
+27334,297,202
+27370,303,192
+27391,304,190
+27428,304,189
+27459,304,190
+27494,303,197
+27513,303,197
+27550,302,198
+27567,301,198
+27603,294,200
+27624,284,207
+27662,272,224
+27684,268,233
+27719,270,241
+27740,273,244
+27774,275,248
+27795,274,250
+27831,273,251
+27853,273,251
+27888,284,255
+27907,292,255
+27945,304,256
+27966,305,257
+28003,308,265
+28022,311,272
+28056,327,294
+28077,337,304
+28117,374,334
+28138,400,351
+28173,432,372
+28193,456,389
+28224,480,408
+28241,488,416
+28276,505,439
+28295,514,455
+28329,519,469
+28349,521,475
+28385,528,491
+28405,529,495
+28438,530,497
+28455,533,501
+28492,548,516
+28510,554,522
+28543,566,534
+28563,577,545
+28599,604,575
+28619,610,581
+28654,612,585
+28674,613,588
+28707,615,593
+28727,615,594
+28774,613,589
+28795,608,584
+28828,602,578
+28845,602,578
+28880,599,578
+28900,598,579
+28931,595,579
+28951,593,579
+28982,593,580
+29040,592,579
+29059,587,577
+29094,575,577
+29115,567,578
+29147,558,579
+29167,555,579
+29207,555,579
+29251,555,578
+29271,555,577
+29309,554,575
+29330,550,573
+29369,549,573
+29420,552,574
+29446,571,577
+29494,615,569
+29517,627,561
+29554,635,547
+29578,635,545
+29634,635,545
+29672,629,540
+29692,623,535
+29728,608,523
+29746,606,522
+29778,600,518
+29799,597,514
+29840,597,514
+29859,598,516
+29896,600,524
+29917,600,527
+29953,600,529
+29974,600,529
+30011,605,517
+30033,606,509
+30068,606,508
+30089,606,509
+30121,605,517
+30142,604,522
+30181,603,527
+30200,604,529
+30244,606,530
+30269,608,529
+30310,609,528
+30331,609,528
+30368,605,533
+30389,602,535
+30428,591,536
+30447,580,532
+30484,558,515
+30505,540,498
+30540,513,471
+30559,491,451
+30591,460,424
+30609,442,408
+30647,402,372
+30667,387,359
+30702,348,332
+30722,333,321
+30758,306,303
+30779,289,292
+30812,273,282
+30829,267,278
+30864,254,275
+30888,243,274
+30933,224,272
+30953,217,270
+30984,214,269
+31002,214,269
+31047,215,269
+31078,216,267
+31096,216,267
+31143,215,267
+31162,214,268
+31196,213,271
+31213,213,273
+31250,216,274
+31272,217,272
+31311,219,261
+31332,218,257
+31366,217,256
+31398,218,257
+31436,220,263
+31457,221,264
+31492,224,262
+31513,229,258
+31552,230,247
+31574,229,242
+31612,228,237
+31633,227,232
+31670,230,229
+31689,237,224
+31729,254,212
+31756,267,207
+31791,289,208
+31812,292,209
+31845,291,211
+31865,286,221
+31902,280,236
+31924,279,244
+31962,280,248
+31984,289,248
+32021,305,242
+32043,312,237
+32083,313,236
+32139,313,238
+32158,312,238
+32192,312,239
+32224,312,239
+32264,316,235
+32285,317,232
+32323,317,224
+32344,317,223
+32392,317,225
+32430,318,235
+32451,318,238
+32586,317,239
+32609,313,244
+32644,301,254
+32665,295,257
+32707,290,257
+32728,288,256
+32764,285,255
+32784,284,255
+32823,287,261
+32845,290,264
+32883,314,264
+32904,338,257
+32940,372,245
+32961,398,238
+32999,454,238
+33020,478,240
+33054,524,239
+33074,558,236
+33112,620,231
+33132,645,229
+33168,707,224
+33189,733,225
+33223,784,222
+33243,800,221
+33279,840,223
+33296,851,225
+33332,867,227
+33353,873,226
+33394,891,226
+33416,898,227
+33452,899,227
+33480,899,228
+33512,900,233
+33530,901,236
+33569,901,237
+33629,900,237
+33647,898,237
+33680,896,238
+33697,896,239
+33737,894,240
+33758,893,240
+33798,890,243
+33819,887,247
+33856,882,254
+33877,882,256
+33911,882,257
+33929,882,257
+33969,883,257
+33990,883,258
+34027,884,261
+34049,884,263
+34089,884,265
+34111,886,265
+34147,893,263
+34169,902,258
+34207,923,233
+34229,929,223
+34265,944,203
+34290,951,189
+34325,955,170
+34346,955,159
+34382,955,155
+34413,954,155
+34449,952,165
+34471,951,175
+34506,949,189
+34527,950,195
+34564,951,197
+34586,952,198
+34627,954,199
+34649,955,202
+34685,955,214
+34704,955,221
+34737,956,223
+34758,958,223
+34798,959,223
+34817,959,222
+34854,957,222
+34874,955,223
+34914,953,228
+34938,954,231
+34973,959,238
+34994,964,244
+35030,968,249
+35049,967,250
+35091,965,252
+35113,962,258
+35149,958,267
+35171,956,270
+35209,956,271
+35265,956,271
+35299,949,266
+35319,943,264
+35353,940,263
+35373,937,263
+35414,932,263
+35438,928,263
+35469,921,260
+35490,914,248
+35530,905,223
+35552,904,207
+35585,908,198
+35604,910,196
+35638,915,192
+35658,918,191
+35696,920,190
+35750,920,193
+35768,921,195
+35802,925,201
+35821,928,202
+35864,941,208
+35886,945,211
+35924,946,219
+35945,944,228
+35983,942,244
+36005,942,248
+36044,942,250
+36062,942,250
+36100,939,248
+36122,926,243
+36163,914,243
+36185,907,243
+36223,893,243
+36243,891,243
+36282,890,243
+36304,889,244
+36341,887,246
+36360,886,248
+36403,885,253
+36425,882,259
+36459,878,268
+36481,874,272
+36515,854,275
+36535,818,275
+36569,756,275
+36589,728,279
+36625,660,296
+36643,635,302
+36673,589,309
+36690,573,311
+36731,555,313
+36757,554,313
+36843,555,313
+36863,559,316
+36897,566,322
+36917,573,325
+36957,597,329
+36981,615,326
+37030,633,316
+37054,633,314
+37095,634,314
+37117,634,315
+37153,633,316
+37174,633,317
+37212,635,319
+37233,637,319
+37274,639,318
+37295,639,315
+37334,633,311
+37355,628,310
+37389,623,311
+37407,621,313
+37443,620,315
+37461,620,316
+37497,621,317
+37515,623,318
+37555,626,317
+37576,626,317
+37610,627,320
+37630,628,324
+37667,629,325
+37687,630,326
+37722,633,326
+37742,634,325
+37779,634,324
+37801,634,323
|