From 44e66882f6e517b06522cb1e510ed9dea7574273 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 21 Nov 2020 18:20:00 +0100 Subject: Render emoji in text, do not show notification count for cache sync, lazy load 4chan board --- README.md | 2 + generate-emoji-sprite.py | 98 +- generated/Emoji.cpp | 2946 ++++++++++++++++++++++++++++++++++++++++++++ generated/Emoji.hpp | 15 + images/emoji.png | Bin 0 -> 932613 bytes include/Body.hpp | 3 +- include/FontLoader.hpp | 19 - include/ResourceLoader.hpp | 27 + include/Text.hpp | 2 +- plugins/Fourchan.hpp | 5 +- plugins/Matrix.hpp | 2 +- src/Body.cpp | 2 +- src/Entry.cpp | 2 +- src/FontLoader.cpp | 52 - src/ImageViewer.cpp | 2 +- src/QuickMedia.cpp | 4 +- src/ResourceLoader.cpp | 79 ++ src/SearchBar.cpp | 2 +- src/Text.cpp | 71 +- src/plugins/Fourchan.cpp | 266 ++-- src/plugins/Matrix.cpp | 6 +- 21 files changed, 3349 insertions(+), 256 deletions(-) create mode 100644 generated/Emoji.cpp create mode 100644 generated/Emoji.hpp create mode 100644 images/emoji.png delete mode 100644 include/FontLoader.hpp create mode 100644 include/ResourceLoader.hpp delete mode 100644 src/FontLoader.cpp create mode 100644 src/ResourceLoader.cpp diff --git a/README.md b/README.md index 93144ec..2e49c7a 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,8 @@ See project.conf \[dependencies]. `waifu2x-ncnn-vulkan` needs to be installed when using the `--upscale-images` or `--upscale-images-always` option.\ `xdg-utils` which provides `xdg-open` needs to be installed when downloading torrents with `nyaa.si` plugin.\ `ffmpeg (and ffprobe which is included in ffmpeg)` needs to be installed to upload videos with thumbnails on matrix. +## License +QuickMedia is free software licensed under GPL 3.0, see LICENSE for more details. `images/emoji.png` uses Noto Color Emoji, which is licensed under the Apache license, see: https://github.com/googlefonts/noto-emoji. # Screenshots ## Youtube search ![](https://www.dec05eba.com/images/youtube.jpg) diff --git a/generate-emoji-sprite.py b/generate-emoji-sprite.py index b0e9dc3..849a81d 100755 --- a/generate-emoji-sprite.py +++ b/generate-emoji-sprite.py @@ -1,35 +1,73 @@ #!/usr/bin/env python3 -import requests -from subprocess import Popen, PIPE +from gi.repository import Gtk, Gdk, Pango, PangoCairo +import cairo -def create_image_with_text(text, image_filepath): - process = Popen(["convert", "-size", "1024x", "-background", "#ff00ff", "-strip", "pango:" + text, image_filepath]) - _, _ = process.communicate() +surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1024, 1512) +context = cairo.Context(surface) +pc = PangoCairo.create_context(context) +layout = PangoCairo.create_layout(context) +layout.set_font_description(Pango.FontDescription('NotoSans Emoji Normal 12')) +layout.set_width(1024*Pango.SCALE) +layout.set_wrap(Pango.WrapMode.CHAR) -resp = requests.get("https://unicode.org/Public/emoji/13.1/emoji-test.txt") -resp.raise_for_status() -emoji_sequences = resp.text - -ss = [] +emoji_start = 0x1F000 +emoji_end = 0x1FB6F emoji_characters = [] -for line in emoji_sequences.splitlines(): - if len(line) == 0 or line[0] == '#': - continue - - columns = line.split(";") - sequences = columns[0].strip().split() - text = [chr(int(c, 16)) for c in sequences] - emoji_characters.extend(text) - ss.append(int(sequences[0], 16)) - #print(str(sequences)) - -#print(str(len(emoji_characters))) -create_image_with_text("".join(emoji_characters), "emoji.jpg") - -sow = list(set(ss)) -sow.sort() -for i in range(len(sow) - 1): - s1 = sow[i] - s2 = sow[i + 1] - print(str(s2-s1)) +i = emoji_start +while i <= emoji_end: + emoji_characters.append(chr(i)) + i += 1 + +layout.set_text("".join(emoji_characters), -1) +PangoCairo.show_layout(context, layout) +surface.write_to_png('images/emoji.png') + +with open("generated/Emoji.hpp", "w") as header_file: + header_file.write("""#pragma once + +#include + +// This file was automatically generated with generate-emoji-sprite.py, do not edit manually! + +namespace QuickMedia { + struct EmojiRectangle { + int x, y; + int width, height; + }; + + bool codepoint_is_emoji(uint32_t codepoint); + EmojiRectangle emoji_get_extents(uint32_t codepoint); +}""") + +with open("generated/Emoji.cpp", "w") as source_file: + source_file.write("""#include "Emoji.hpp" +#include + +// This file was automatically generated with generate-emoji-sprite.py, do not edit manually! + +namespace QuickMedia { + static EmojiRectangle emoji_extents[%s] = { +""" % len(emoji_characters)) + + i = 0 + index = 0 + for e in emoji_characters: + emoji_pos = layout.index_to_pos(index) + source_file.write(" {%s, %s, %s, %s}%s\n" % (int(emoji_pos.x/Pango.SCALE), int(emoji_pos.y/Pango.SCALE), int(emoji_pos.width/Pango.SCALE), int(emoji_pos.height/Pango.SCALE), "," if i < len(emoji_characters) - 1 else "")) + i += 1 + index += 4 + + source_file.write( +""" }; + + bool codepoint_is_emoji(uint32_t codepoint) { + return codepoint >= 0x1F000 && codepoint <= 0x1FB6F; + } + + EmojiRectangle emoji_get_extents(uint32_t codepoint) { + assert(codepoint_is_emoji(codepoint)); + return emoji_extents[codepoint - 0x1F000]; + } +} +""") \ No newline at end of file diff --git a/generated/Emoji.cpp b/generated/Emoji.cpp new file mode 100644 index 0000000..07b240b --- /dev/null +++ b/generated/Emoji.cpp @@ -0,0 +1,2946 @@ +#include "Emoji.hpp" +#include + +// This file was automatically generated with generate-emoji-sprite.py, do not edit manually! + +namespace QuickMedia { + static EmojiRectangle emoji_extents[2928] = { + {0, 0, 13, 21}, + {13, 0, 13, 21}, + {26, 0, 13, 21}, + {39, 0, 13, 21}, + {52, 0, 20, 21}, + {72, 0, 13, 21}, + {85, 0, 13, 21}, + {98, 0, 13, 21}, + {111, 0, 13, 21}, + {124, 0, 13, 21}, + {137, 0, 13, 21}, + {150, 0, 13, 21}, + {163, 0, 13, 21}, + {176, 0, 13, 21}, + {189, 0, 13, 21}, + {202, 0, 13, 21}, + {215, 0, 13, 21}, + {228, 0, 13, 21}, + {241, 0, 13, 21}, + {254, 0, 13, 21}, + {267, 0, 13, 21}, + {280, 0, 13, 21}, + {293, 0, 13, 21}, + {306, 0, 13, 21}, + {319, 0, 13, 21}, + {332, 0, 13, 21}, + {345, 0, 13, 21}, + {358, 0, 13, 21}, + {371, 0, 13, 21}, + {384, 0, 13, 21}, + {397, 0, 13, 21}, + {410, 0, 13, 21}, + {423, 0, 13, 21}, + {436, 0, 13, 21}, + {449, 0, 13, 21}, + {462, 0, 13, 21}, + {475, 0, 13, 21}, + {488, 0, 13, 21}, + {501, 0, 13, 21}, + {514, 0, 13, 21}, + {527, 0, 13, 21}, + {540, 0, 13, 21}, + {553, 0, 13, 21}, + {566, 0, 13, 21}, + {579, 0, 23, 21}, + {602, 0, 23, 21}, + {625, 0, 23, 21}, + {648, 0, 23, 21}, + {671, 0, 22, 21}, + {693, 0, 22, 21}, + {715, 0, 22, 21}, + {737, 0, 22, 21}, + {759, 0, 22, 21}, + {781, 0, 22, 21}, + {803, 0, 22, 21}, + {825, 0, 22, 21}, + {847, 0, 22, 21}, + {869, 0, 22, 21}, + {891, 0, 22, 21}, + {913, 0, 22, 21}, + {935, 0, 22, 21}, + {957, 0, 22, 21}, + {979, 0, 22, 21}, + {1001, 0, 22, 21}, + {0, 21, 22, 19}, + {22, 21, 22, 19}, + {44, 21, 22, 19}, + {66, 21, 22, 19}, + {88, 21, 22, 19}, + {110, 21, 22, 19}, + {132, 21, 22, 19}, + {154, 21, 22, 19}, + {176, 21, 22, 19}, + {198, 21, 22, 19}, + {220, 21, 22, 19}, + {242, 21, 22, 19}, + {264, 21, 22, 19}, + {286, 21, 22, 19}, + {308, 21, 22, 19}, + {330, 21, 22, 19}, + {352, 21, 22, 19}, + {374, 21, 22, 19}, + {396, 21, 22, 19}, + {418, 21, 22, 19}, + {440, 21, 22, 19}, + {462, 21, 22, 19}, + {484, 21, 22, 19}, + {506, 21, 22, 19}, + {528, 21, 22, 19}, + {550, 21, 22, 19}, + {572, 21, 22, 19}, + {594, 21, 22, 19}, + {616, 21, 22, 19}, + {638, 21, 22, 19}, + {660, 21, 22, 19}, + {682, 21, 22, 19}, + {704, 21, 22, 19}, + {726, 21, 22, 19}, + {748, 21, 13, 19}, + {761, 21, 13, 19}, + {774, 21, 13, 19}, + {787, 21, 13, 19}, + {800, 21, 13, 19}, + {813, 21, 13, 19}, + {826, 21, 13, 19}, + {839, 21, 13, 19}, + {852, 21, 13, 19}, + {865, 21, 13, 19}, + {878, 21, 13, 19}, + {891, 21, 13, 19}, + {904, 21, 13, 19}, + {917, 21, 13, 19}, + {930, 21, 13, 19}, + {943, 21, 13, 19}, + {956, 21, 13, 19}, + {969, 21, 13, 19}, + {982, 21, 13, 19}, + {995, 21, 13, 19}, + {1008, 21, 13, 19}, + {0, 40, 13, 21}, + {13, 40, 13, 21}, + {26, 40, 13, 21}, + {39, 40, 13, 21}, + {52, 40, 13, 21}, + {65, 40, 13, 21}, + {78, 40, 13, 21}, + {91, 40, 13, 21}, + {104, 40, 13, 21}, + {117, 40, 13, 21}, + {130, 40, 13, 21}, + {143, 40, 13, 21}, + {156, 40, 13, 21}, + {169, 40, 13, 21}, + {182, 40, 13, 21}, + {195, 40, 13, 21}, + {208, 40, 13, 21}, + {221, 40, 13, 21}, + {234, 40, 13, 21}, + {247, 40, 13, 21}, + {260, 40, 13, 21}, + {273, 40, 13, 21}, + {286, 40, 13, 21}, + {299, 40, 13, 21}, + {312, 40, 13, 21}, + {325, 40, 13, 21}, + {338, 40, 13, 21}, + {351, 40, 13, 21}, + {364, 40, 13, 21}, + {377, 40, 23, 21}, + {400, 40, 23, 21}, + {423, 40, 23, 21}, + {446, 40, 23, 21}, + {469, 40, 23, 21}, + {492, 40, 23, 21}, + {515, 40, 23, 21}, + {538, 40, 23, 21}, + {561, 40, 23, 21}, + {584, 40, 23, 21}, + {607, 40, 23, 21}, + {630, 40, 23, 21}, + {653, 40, 16, 21}, + {669, 40, 16, 21}, + {685, 40, 16, 21}, + {701, 40, 16, 21}, + {717, 40, 16, 21}, + {733, 40, 16, 21}, + {749, 40, 16, 21}, + {765, 40, 16, 21}, + {781, 40, 16, 21}, + {797, 40, 16, 21}, + {813, 40, 16, 21}, + {829, 40, 16, 21}, + {845, 40, 16, 21}, + {861, 40, 16, 21}, + {877, 40, 16, 21}, + {893, 40, 23, 21}, + {916, 40, 23, 21}, + {939, 40, 16, 21}, + {955, 40, 16, 21}, + {971, 40, 16, 21}, + {987, 40, 16, 21}, + {1003, 40, 16, 21}, + {0, 61, 16, 29}, + {16, 61, 16, 29}, + {32, 61, 16, 29}, + {48, 61, 16, 29}, + {64, 61, 16, 29}, + {80, 61, 16, 29}, + {96, 61, 16, 29}, + {112, 61, 17, 29}, + {129, 61, 16, 29}, + {145, 61, 11, 29}, + {156, 61, 23, 29}, + {179, 61, 16, 29}, + {195, 61, 16, 29}, + {211, 61, 16, 29}, + {227, 61, 16, 29}, + {243, 61, 16, 29}, + {259, 61, 16, 29}, + {275, 61, 16, 29}, + {291, 61, 16, 29}, + {307, 61, 16, 29}, + {323, 61, 16, 29}, + {339, 61, 16, 29}, + {355, 61, 16, 29}, + {371, 61, 16, 29}, + {387, 61, 16, 29}, + {403, 61, 20, 29}, + {423, 61, 23, 29}, + {446, 61, 16, 29}, + {462, 61, 16, 29}, + {478, 61, 16, 29}, + {494, 61, 16, 29}, + {510, 61, 16, 29}, + {526, 61, 16, 29}, + {542, 61, 16, 29}, + {558, 61, 16, 29}, + {574, 61, 16, 29}, + {590, 61, 16, 29}, + {606, 61, 16, 29}, + {622, 61, 16, 29}, + {638, 61, 16, 29}, + {654, 61, 16, 29}, + {670, 61, 16, 29}, + {686, 61, 11, 29}, + {697, 61, 11, 29}, + {708, 61, 11, 29}, + {719, 61, 11, 29}, + {730, 61, 11, 29}, + {741, 61, 11, 29}, + {752, 61, 11, 29}, + {763, 61, 11, 29}, + {774, 61, 11, 29}, + {785, 61, 11, 29}, + {796, 61, 11, 29}, + {807, 61, 11, 29}, + {818, 61, 11, 29}, + {829, 61, 11, 29}, + {840, 61, 11, 29}, + {851, 61, 11, 29}, + {862, 61, 11, 29}, + {873, 61, 11, 29}, + {884, 61, 11, 29}, + {895, 61, 11, 29}, + {906, 61, 11, 29}, + {917, 61, 11, 29}, + {928, 61, 23, 29}, + {951, 61, 23, 29}, + {974, 61, 23, 29}, + {997, 61, 23, 29}, + {0, 90, 23, 24}, + {23, 90, 23, 24}, + {46, 90, 23, 24}, + {69, 90, 23, 24}, + {92, 90, 23, 24}, + {115, 90, 23, 24}, + {138, 90, 16, 24}, + {154, 90, 16, 24}, + {170, 90, 16, 24}, + {186, 90, 16, 24}, + {202, 90, 16, 24}, + {218, 90, 16, 24}, + {234, 90, 16, 24}, + {250, 90, 16, 24}, + {266, 90, 16, 24}, + {282, 90, 16, 24}, + {298, 90, 16, 24}, + {314, 90, 16, 24}, + {330, 90, 16, 24}, + {346, 90, 23, 24}, + {369, 90, 23, 24}, + {392, 90, 23, 24}, + {415, 90, 16, 24}, + {431, 90, 16, 24}, + {447, 90, 16, 24}, + {463, 90, 16, 24}, + {479, 90, 16, 24}, + {495, 90, 16, 24}, + {511, 90, 16, 24}, + {527, 90, 16, 24}, + {543, 90, 16, 24}, + {559, 90, 16, 24}, + {575, 90, 16, 24}, + {591, 90, 16, 24}, + {607, 90, 16, 24}, + {623, 90, 16, 24}, + {639, 90, 16, 24}, + {655, 90, 16, 24}, + {671, 90, 16, 24}, + {687, 90, 16, 24}, + {703, 90, 16, 24}, + {719, 90, 16, 24}, + {735, 90, 16, 24}, + {751, 90, 16, 24}, + {767, 90, 16, 24}, + {783, 90, 16, 24}, + {799, 90, 16, 24}, + {815, 90, 16, 24}, + {831, 90, 16, 24}, + {847, 90, 16, 24}, + {863, 90, 16, 24}, + {879, 90, 16, 24}, + {895, 90, 16, 24}, + {911, 90, 13, 24}, + {924, 90, 16, 24}, + {940, 90, 16, 24}, + {956, 90, 16, 24}, + {972, 90, 16, 24}, + {988, 90, 16, 24}, + {1004, 90, 16, 24}, + {0, 114, 16, 24}, + {16, 114, 16, 24}, + {32, 114, 16, 24}, + {48, 114, 16, 24}, + {64, 114, 16, 24}, + {80, 114, 16, 24}, + {96, 114, 16, 24}, + {112, 114, 16, 24}, + {128, 114, 16, 24}, + {144, 114, 16, 24}, + {160, 114, 16, 24}, + {176, 114, 16, 24}, + {192, 114, 16, 24}, + {208, 114, 16, 24}, + {224, 114, 16, 24}, + {240, 114, 16, 24}, + {256, 114, 16, 24}, + {272, 114, 16, 24}, + {288, 114, 16, 24}, + {304, 114, 16, 24}, + {320, 114, 16, 24}, + {336, 114, 16, 24}, + {352, 114, 16, 24}, + {368, 114, 16, 24}, + {384, 114, 16, 24}, + {400, 114, 16, 24}, + {416, 114, 16, 24}, + {432, 114, 16, 24}, + {448, 114, 16, 24}, + {464, 114, 16, 24}, + {480, 114, 16, 24}, + {496, 114, 16, 24}, + {512, 114, 16, 24}, + {528, 114, 16, 24}, + {544, 114, 16, 24}, + {560, 114, 16, 24}, + {576, 114, 16, 24}, + {592, 114, 16, 24}, + {608, 114, 16, 24}, + {624, 114, 16, 24}, + {640, 114, 16, 24}, + {656, 114, 16, 24}, + {672, 114, 16, 24}, + {688, 114, 16, 24}, + {704, 114, 16, 24}, + {720, 114, 16, 24}, + {736, 114, 16, 24}, + {752, 114, 16, 24}, + {768, 114, 16, 24}, + {784, 114, 16, 24}, + {800, 114, 16, 24}, + {816, 114, 16, 24}, + {832, 114, 11, 24}, + {843, 114, 12, 24}, + {855, 114, 12, 24}, + {867, 114, 23, 24}, + {890, 114, 23, 24}, + {913, 114, 23, 24}, + {936, 114, 16, 24}, + {952, 114, 16, 24}, + {968, 114, 16, 24}, + {984, 114, 16, 24}, + {1000, 114, 16, 24}, + {0, 138, 16, 24}, + {16, 138, 16, 24}, + {32, 138, 16, 24}, + {48, 138, 16, 24}, + {64, 138, 16, 24}, + {80, 138, 16, 24}, + {96, 138, 16, 24}, + {112, 138, 16, 24}, + {128, 138, 16, 24}, + {144, 138, 16, 24}, + {160, 138, 16, 24}, + {176, 138, 16, 24}, + {192, 138, 16, 24}, + {208, 138, 16, 24}, + {224, 138, 16, 24}, + {240, 138, 16, 24}, + {256, 138, 16, 24}, + {272, 138, 16, 24}, + {288, 138, 16, 24}, + {304, 138, 16, 24}, + {320, 138, 16, 24}, + {336, 138, 16, 24}, + {352, 138, 16, 24}, + {368, 138, 16, 24}, + {384, 138, 16, 24}, + {400, 138, 20, 24}, + {420, 138, 16, 24}, + {436, 138, 16, 24}, + {452, 138, 20, 24}, + {472, 138, 20, 24}, + {492, 138, 20, 24}, + {512, 138, 20, 24}, + {532, 138, 20, 24}, + {552, 138, 20, 24}, + {572, 138, 20, 24}, + {592, 138, 20, 24}, + {612, 138, 20, 24}, + {632, 138, 20, 24}, + {652, 138, 16, 24}, + {668, 138, 16, 24}, + {684, 138, 16, 24}, + {700, 138, 16, 24}, + {716, 138, 16, 24}, + {732, 138, 16, 24}, + {748, 138, 16, 24}, + {764, 138, 16, 24}, + {780, 138, 16, 24}, + {796, 138, 16, 24}, + {812, 138, 16, 24}, + {828, 138, 16, 24}, + {844, 138, 16, 24}, + {860, 138, 16, 24}, + {876, 138, 16, 24}, + {892, 138, 16, 24}, + {908, 138, 16, 24}, + {924, 138, 16, 24}, + {940, 138, 23, 24}, + {963, 138, 23, 24}, + {986, 138, 23, 24}, + {0, 162, 23, 21}, + {23, 162, 23, 21}, + {46, 162, 23, 21}, + {69, 162, 23, 21}, + {92, 162, 23, 21}, + {115, 162, 23, 21}, + {138, 162, 23, 21}, + {161, 162, 23, 21}, + {184, 162, 23, 21}, + {207, 162, 23, 21}, + {230, 162, 23, 21}, + {253, 162, 23, 21}, + {276, 162, 23, 21}, + {299, 162, 23, 21}, + {322, 162, 23, 21}, + {345, 162, 23, 21}, + {368, 162, 23, 21}, + {391, 162, 23, 21}, + {414, 162, 23, 21}, + {437, 162, 23, 21}, + {460, 162, 23, 21}, + {483, 162, 23, 21}, + {506, 162, 23, 21}, + {529, 162, 23, 21}, + {552, 162, 23, 21}, + {575, 162, 23, 21}, + {598, 162, 23, 21}, + {621, 162, 23, 21}, + {644, 162, 23, 21}, + {667, 162, 23, 21}, + {690, 162, 23, 21}, + {713, 162, 23, 21}, + {736, 162, 23, 21}, + {759, 162, 23, 21}, + {782, 162, 23, 21}, + {805, 162, 23, 21}, + {828, 162, 23, 21}, + {851, 162, 23, 21}, + {874, 162, 23, 21}, + {897, 162, 23, 21}, + {920, 162, 23, 21}, + {943, 162, 23, 21}, + {966, 162, 23, 21}, + {989, 162, 23, 21}, + {0, 183, 23, 24}, + {23, 183, 23, 24}, + {46, 183, 23, 24}, + {69, 183, 23, 24}, + {92, 183, 23, 24}, + {115, 183, 23, 24}, + {138, 183, 23, 24}, + {161, 183, 23, 24}, + {184, 183, 23, 24}, + {207, 183, 23, 24}, + {230, 183, 20, 24}, + {230, 183, 20, 24}, + {250, 183, 20, 24}, + {250, 183, 20, 24}, + {270, 183, 20, 24}, + {270, 183, 20, 24}, + {290, 183, 20, 24}, + {290, 183, 20, 24}, + {310, 183, 20, 24}, + {310, 183, 20, 24}, + {330, 183, 20, 24}, + {330, 183, 20, 24}, + {350, 183, 20, 24}, + {350, 183, 20, 24}, + {370, 183, 20, 24}, + {370, 183, 20, 24}, + {390, 183, 30, 24}, + {390, 183, 30, 24}, + {420, 183, 20, 24}, + {420, 183, 20, 24}, + {440, 183, 20, 24}, + {440, 183, 20, 24}, + {460, 183, 20, 24}, + {460, 183, 20, 24}, + {480, 183, 30, 24}, + {480, 183, 30, 24}, + {510, 183, 16, 24}, + {526, 183, 20, 24}, + {546, 183, 16, 24}, + {562, 183, 23, 24}, + {585, 183, 23, 24}, + {608, 183, 23, 24}, + {631, 183, 23, 24}, + {654, 183, 23, 24}, + {677, 183, 23, 24}, + {700, 183, 23, 24}, + {723, 183, 23, 24}, + {746, 183, 23, 24}, + {769, 183, 23, 24}, + {792, 183, 23, 24}, + {815, 183, 23, 24}, + {838, 183, 23, 24}, + {861, 183, 16, 24}, + {877, 183, 16, 24}, + {893, 183, 16, 24}, + {909, 183, 16, 24}, + {925, 183, 16, 24}, + {941, 183, 16, 24}, + {957, 183, 16, 24}, + {973, 183, 16, 24}, + {989, 183, 16, 24}, + {1005, 183, 16, 24}, + {0, 207, 20, 24}, + {20, 207, 16, 24}, + {36, 207, 16, 24}, + {52, 207, 16, 24}, + {68, 207, 16, 24}, + {84, 207, 16, 24}, + {100, 207, 16, 24}, + {116, 207, 16, 24}, + {132, 207, 16, 24}, + {148, 207, 16, 24}, + {164, 207, 16, 24}, + {180, 207, 16, 24}, + {196, 207, 16, 24}, + {212, 207, 16, 24}, + {228, 207, 16, 24}, + {244, 207, 16, 24}, + {260, 207, 16, 24}, + {276, 207, 16, 24}, + {292, 207, 16, 24}, + {308, 207, 16, 24}, + {324, 207, 16, 24}, + {340, 207, 20, 24}, + {360, 207, 16, 24}, + {376, 207, 16, 24}, + {392, 207, 20, 24}, + {412, 207, 20, 24}, + {432, 207, 20, 24}, + {452, 207, 20, 24}, + {472, 207, 20, 24}, + {492, 207, 16, 24}, + {508, 207, 20, 24}, + {528, 207, 20, 24}, + {548, 207, 20, 24}, + {568, 207, 16, 24}, + {584, 207, 23, 24}, + {607, 207, 23, 24}, + {630, 207, 23, 24}, + {653, 207, 23, 24}, + {676, 207, 16, 24}, + {692, 207, 16, 24}, + {708, 207, 16, 24}, + {724, 207, 16, 24}, + {740, 207, 16, 24}, + {756, 207, 16, 24}, + {772, 207, 16, 24}, + {788, 207, 16, 24}, + {804, 207, 16, 24}, + {820, 207, 23, 24}, + {843, 207, 23, 24}, + {866, 207, 23, 24}, + {889, 207, 23, 24}, + {912, 207, 23, 24}, + {935, 207, 23, 24}, + {958, 207, 23, 24}, + {981, 207, 20, 24}, + {1001, 207, 20, 24}, + {0, 231, 23, 21}, + {23, 231, 23, 21}, + {46, 231, 23, 21}, + {69, 231, 23, 21}, + {92, 231, 23, 21}, + {115, 231, 23, 21}, + {138, 231, 23, 21}, + {161, 231, 23, 21}, + {184, 231, 23, 21}, + {207, 231, 23, 21}, + {230, 231, 23, 21}, + {253, 231, 23, 21}, + {276, 231, 23, 21}, + {299, 231, 23, 21}, + {322, 231, 23, 21}, + {345, 231, 23, 21}, + {368, 231, 23, 21}, + {391, 231, 23, 21}, + {414, 231, 23, 21}, + {437, 231, 23, 21}, + {460, 231, 23, 21}, + {483, 231, 23, 21}, + {506, 231, 23, 21}, + {529, 231, 23, 21}, + {552, 231, 23, 21}, + {575, 231, 23, 21}, + {598, 231, 23, 21}, + {621, 231, 23, 21}, + {644, 231, 23, 21}, + {667, 231, 23, 21}, + {690, 231, 23, 21}, + {713, 231, 23, 21}, + {736, 231, 23, 21}, + {759, 231, 23, 21}, + {782, 231, 23, 21}, + {805, 231, 23, 21}, + {828, 231, 23, 21}, + {851, 231, 23, 21}, + {874, 231, 23, 21}, + {897, 231, 23, 21}, + {920, 231, 23, 21}, + {943, 231, 23, 21}, + {966, 231, 23, 21}, + {989, 231, 23, 21}, + {0, 252, 23, 21}, + {23, 252, 23, 21}, + {46, 252, 23, 21}, + {69, 252, 23, 21}, + {92, 252, 23, 21}, + {115, 252, 23, 21}, + {138, 252, 23, 21}, + {161, 252, 23, 21}, + {184, 252, 23, 21}, + {207, 252, 23, 21}, + {230, 252, 23, 21}, + {253, 252, 23, 21}, + {276, 252, 23, 21}, + {299, 252, 23, 21}, + {322, 252, 23, 21}, + {345, 252, 23, 21}, + {368, 252, 23, 21}, + {391, 252, 23, 21}, + {414, 252, 23, 21}, + {437, 252, 23, 21}, + {460, 252, 23, 21}, + {483, 252, 23, 21}, + {506, 252, 23, 21}, + {529, 252, 23, 21}, + {552, 252, 23, 21}, + {575, 252, 23, 21}, + {598, 252, 23, 21}, + {621, 252, 23, 21}, + {644, 252, 23, 21}, + {667, 252, 23, 21}, + {690, 252, 23, 21}, + {713, 252, 23, 21}, + {736, 252, 23, 21}, + {759, 252, 23, 21}, + {782, 252, 23, 21}, + {805, 252, 23, 21}, + {828, 252, 23, 21}, + {851, 252, 23, 21}, + {874, 252, 23, 21}, + {897, 252, 23, 21}, + {920, 252, 23, 21}, + {943, 252, 23, 21}, + {966, 252, 23, 21}, + {989, 252, 23, 21}, + {0, 273, 23, 21}, + {23, 273, 23, 21}, + {46, 273, 23, 21}, + {69, 273, 23, 21}, + {92, 273, 23, 21}, + {115, 273, 23, 21}, + {138, 273, 23, 21}, + {161, 273, 23, 21}, + {184, 273, 23, 21}, + {207, 273, 23, 21}, + {230, 273, 23, 21}, + {253, 273, 23, 21}, + {276, 273, 23, 21}, + {299, 273, 23, 21}, + {322, 273, 23, 21}, + {345, 273, 23, 21}, + {368, 273, 23, 21}, + {391, 273, 23, 21}, + {414, 273, 23, 21}, + {437, 273, 23, 21}, + {460, 273, 23, 21}, + {483, 273, 23, 21}, + {506, 273, 23, 21}, + {529, 273, 23, 21}, + {552, 273, 23, 21}, + {575, 273, 23, 21}, + {598, 273, 23, 21}, + {621, 273, 23, 21}, + {644, 273, 23, 21}, + {667, 273, 23, 21}, + {690, 273, 23, 21}, + {713, 273, 23, 21}, + {736, 273, 23, 21}, + {759, 273, 23, 21}, + {782, 273, 23, 21}, + {805, 273, 23, 21}, + {828, 273, 23, 21}, + {851, 273, 23, 21}, + {874, 273, 23, 21}, + {897, 273, 23, 21}, + {920, 273, 23, 21}, + {943, 273, 23, 21}, + {966, 273, 23, 21}, + {989, 273, 23, 21}, + {0, 294, 23, 21}, + {23, 294, 23, 21}, + {46, 294, 23, 21}, + {69, 294, 23, 21}, + {92, 294, 23, 21}, + {115, 294, 23, 21}, + {138, 294, 23, 21}, + {161, 294, 23, 21}, + {184, 294, 23, 21}, + {207, 294, 23, 21}, + {230, 294, 23, 21}, + {253, 294, 23, 21}, + {276, 294, 23, 21}, + {299, 294, 23, 21}, + {322, 294, 23, 21}, + {345, 294, 23, 21}, + {368, 294, 23, 21}, + {391, 294, 23, 21}, + {414, 294, 23, 21}, + {437, 294, 23, 21}, + {460, 294, 23, 21}, + {483, 294, 23, 21}, + {506, 294, 23, 21}, + {529, 294, 23, 21}, + {552, 294, 23, 21}, + {575, 294, 23, 21}, + {598, 294, 23, 21}, + {621, 294, 23, 21}, + {644, 294, 23, 21}, + {667, 294, 23, 21}, + {690, 294, 23, 21}, + {713, 294, 23, 21}, + {736, 294, 23, 21}, + {759, 294, 23, 21}, + {782, 294, 23, 21}, + {805, 294, 23, 21}, + {828, 294, 23, 21}, + {851, 294, 23, 21}, + {874, 294, 23, 21}, + {897, 294, 23, 21}, + {920, 294, 23, 21}, + {943, 294, 23, 21}, + {966, 294, 20, 21}, + {986, 294, 20, 21}, + {0, 315, 20, 29}, + {20, 315, 20, 29}, + {40, 315, 20, 29}, + {60, 315, 20, 29}, + {80, 315, 20, 29}, + {100, 315, 20, 29}, + {120, 315, 20, 29}, + {140, 315, 20, 29}, + {160, 315, 20, 29}, + {180, 315, 20, 29}, + {200, 315, 20, 29}, + {220, 315, 20, 29}, + {240, 315, 20, 29}, + {260, 315, 20, 29}, + {280, 315, 20, 29}, + {300, 315, 20, 29}, + {320, 315, 20, 29}, + {340, 315, 20, 29}, + {360, 315, 20, 29}, + {380, 315, 20, 29}, + {400, 315, 20, 29}, + {420, 315, 20, 29}, + {440, 315, 20, 29}, + {460, 315, 20, 29}, + {480, 315, 20, 29}, + {500, 315, 20, 29}, + {520, 315, 20, 29}, + {540, 315, 20, 29}, + {560, 315, 20, 29}, + {580, 315, 20, 29}, + {600, 315, 20, 29}, + {620, 315, 11, 29}, + {631, 315, 11, 29}, + {642, 315, 14, 29}, + {656, 315, 19, 29}, + {675, 315, 17, 29}, + {692, 315, 18, 29}, + {710, 315, 18, 29}, + {728, 315, 20, 29}, + {748, 315, 18, 29}, + {766, 315, 18, 29}, + {784, 315, 18, 29}, + {802, 315, 17, 29}, + {819, 315, 20, 29}, + {839, 315, 20, 29}, + {859, 315, 20, 29}, + {879, 315, 20, 29}, + {899, 315, 20, 29}, + {919, 315, 20, 29}, + {939, 315, 20, 29}, + {959, 315, 20, 29}, + {979, 315, 20, 29}, + {999, 315, 12, 29}, + {0, 344, 20, 18}, + {20, 344, 20, 18}, + {40, 344, 20, 18}, + {60, 344, 20, 18}, + {80, 344, 20, 18}, + {100, 344, 20, 18}, + {120, 344, 20, 18}, + {140, 344, 20, 18}, + {160, 344, 20, 18}, + {180, 344, 20, 18}, + {200, 344, 20, 18}, + {220, 344, 20, 18}, + {240, 344, 20, 18}, + {260, 344, 20, 18}, + {280, 344, 20, 18}, + {300, 344, 20, 18}, + {320, 344, 20, 18}, + {340, 344, 20, 18}, + {360, 344, 20, 18}, + {380, 344, 20, 18}, + {400, 344, 20, 18}, + {420, 344, 20, 18}, + {440, 344, 20, 18}, + {460, 344, 20, 18}, + {480, 344, 20, 18}, + {500, 344, 20, 18}, + {520, 344, 20, 18}, + {540, 344, 20, 18}, + {560, 344, 20, 18}, + {580, 344, 20, 18}, + {600, 344, 20, 18}, + {620, 344, 20, 18}, + {640, 344, 20, 18}, + {660, 344, 20, 18}, + {680, 344, 20, 18}, + {700, 344, 20, 18}, + {720, 344, 20, 18}, + {740, 344, 20, 18}, + {760, 344, 20, 18}, + {780, 344, 20, 18}, + {800, 344, 20, 18}, + {820, 344, 20, 18}, + {840, 344, 20, 18}, + {860, 344, 20, 18}, + {880, 344, 20, 18}, + {900, 344, 20, 18}, + {920, 344, 20, 18}, + {940, 344, 20, 18}, + {960, 344, 20, 18}, + {980, 344, 20, 18}, + {1000, 344, 20, 18}, + {0, 362, 20, 29}, + {20, 362, 20, 29}, + {40, 362, 20, 29}, + {60, 362, 20, 29}, + {80, 362, 20, 29}, + {100, 362, 20, 29}, + {120, 362, 20, 29}, + {140, 362, 20, 29}, + {160, 362, 20, 29}, + {180, 362, 20, 29}, + {200, 362, 20, 29}, + {220, 362, 20, 29}, + {240, 362, 20, 29}, + {260, 362, 20, 29}, + {280, 362, 20, 29}, + {300, 362, 20, 29}, + {320, 362, 20, 29}, + {340, 362, 20, 29}, + {360, 362, 20, 29}, + {380, 362, 17, 29}, + {397, 362, 20, 29}, + {417, 362, 20, 29}, + {437, 362, 20, 29}, + {457, 362, 20, 29}, + {477, 362, 20, 29}, + {497, 362, 20, 29}, + {517, 362, 20, 29}, + {537, 362, 20, 29}, + {557, 362, 20, 29}, + {577, 362, 20, 29}, + {597, 362, 20, 29}, + {617, 362, 20, 29}, + {637, 362, 20, 29}, + {657, 362, 20, 29}, + {677, 362, 20, 29}, + {697, 362, 20, 29}, + {717, 362, 20, 29}, + {737, 362, 20, 29}, + {757, 362, 20, 29}, + {777, 362, 20, 29}, + {797, 362, 20, 29}, + {817, 362, 20, 29}, + {837, 362, 17, 29}, + {854, 362, 14, 29}, + {868, 362, 10, 29}, + {878, 362, 12, 29}, + {890, 362, 17, 29}, + {907, 362, 9, 29}, + {916, 362, 9, 29}, + {925, 362, 18, 29}, + {943, 362, 16, 29}, + {959, 362, 15, 29}, + {974, 362, 18, 29}, + {992, 362, 18, 29}, + {0, 391, 20, 29}, + {20, 391, 20, 29}, + {40, 391, 20, 29}, + {60, 391, 20, 29}, + {80, 391, 20, 29}, + {100, 391, 20, 29}, + {120, 391, 20, 29}, + {140, 391, 20, 29}, + {160, 391, 20, 29}, + {180, 391, 20, 29}, + {200, 391, 20, 29}, + {220, 391, 20, 29}, + {240, 391, 20, 29}, + {260, 391, 20, 29}, + {280, 391, 20, 29}, + {300, 391, 20, 29}, + {320, 391, 20, 29}, + {340, 391, 20, 29}, + {360, 391, 20, 29}, + {380, 391, 20, 29}, + {400, 391, 20, 29}, + {420, 391, 20, 29}, + {440, 391, 20, 29}, + {460, 391, 20, 29}, + {480, 391, 20, 29}, + {500, 391, 20, 29}, + {520, 391, 20, 29}, + {540, 391, 20, 29}, + {560, 391, 20, 29}, + {580, 391, 20, 29}, + {600, 391, 20, 29}, + {620, 391, 20, 29}, + {640, 391, 20, 29}, + {660, 391, 20, 29}, + {680, 391, 20, 29}, + {700, 391, 20, 29}, + {720, 391, 20, 29}, + {740, 391, 20, 29}, + {760, 391, 20, 29}, + {780, 391, 20, 29}, + {800, 391, 20, 29}, + {820, 391, 20, 29}, + {840, 391, 20, 29}, + {860, 391, 20, 29}, + {880, 391, 20, 29}, + {900, 391, 18, 29}, + {918, 391, 20, 29}, + {938, 391, 20, 29}, + {958, 391, 20, 29}, + {978, 391, 20, 29}, + {998, 391, 20, 29}, + {0, 420, 20, 29}, + {20, 420, 18, 29}, + {38, 420, 18, 29}, + {56, 420, 18, 29}, + {74, 420, 18, 29}, + {92, 420, 18, 29}, + {110, 420, 18, 29}, + {128, 420, 18, 29}, + {146, 420, 18, 29}, + {164, 420, 18, 29}, + {182, 420, 18, 29}, + {200, 420, 18, 29}, + {218, 420, 18, 29}, + {236, 420, 20, 29}, + {256, 420, 20, 29}, + {276, 420, 20, 29}, + {296, 420, 20, 29}, + {316, 420, 20, 29}, + {336, 420, 20, 29}, + {356, 420, 20, 29}, + {376, 420, 20, 29}, + {396, 420, 20, 29}, + {416, 420, 20, 29}, + {436, 420, 20, 29}, + {456, 420, 20, 29}, + {476, 420, 20, 29}, + {496, 420, 20, 29}, + {516, 420, 20, 29}, + {536, 420, 20, 29}, + {556, 420, 20, 29}, + {576, 420, 14, 29}, + {590, 420, 14, 29}, + {604, 420, 18, 29}, + {622, 420, 20, 29}, + {642, 420, 15, 29}, + {657, 420, 15, 29}, + {672, 420, 18, 29}, + {690, 420, 20, 29}, + {710, 420, 20, 29}, + {730, 420, 40, 29}, + {750, 420, 100, 29}, + {750, 420, 100, 29}, + {750, 420, 100, 29}, + {750, 420, 100, 29}, + {750, 420, 100, 29}, + {850, 420, 20, 29}, + {870, 420, 20, 29}, + {890, 420, 20, 29}, + {910, 420, 20, 29}, + {930, 420, 20, 29}, + {950, 420, 20, 29}, + {970, 420, 20, 29}, + {990, 420, 20, 29}, + {0, 449, 20, 18}, + {20, 449, 20, 18}, + {40, 449, 20, 18}, + {60, 449, 20, 18}, + {80, 449, 20, 18}, + {100, 449, 20, 18}, + {120, 449, 20, 18}, + {140, 449, 20, 18}, + {160, 449, 20, 18}, + {180, 449, 20, 18}, + {200, 449, 20, 18}, + {220, 449, 20, 18}, + {240, 449, 20, 18}, + {260, 449, 20, 18}, + {280, 449, 20, 18}, + {300, 449, 20, 18}, + {320, 449, 20, 18}, + {340, 449, 20, 18}, + {360, 449, 20, 18}, + {380, 449, 20, 18}, + {400, 449, 20, 18}, + {420, 449, 20, 18}, + {440, 449, 20, 18}, + {460, 449, 20, 18}, + {480, 449, 20, 18}, + {500, 449, 20, 18}, + {520, 449, 20, 18}, + {540, 449, 20, 18}, + {560, 449, 20, 18}, + {580, 449, 20, 18}, + {600, 449, 20, 18}, + {620, 449, 20, 18}, + {640, 449, 20, 18}, + {660, 449, 20, 18}, + {680, 449, 20, 18}, + {700, 449, 20, 18}, + {720, 449, 20, 18}, + {740, 449, 20, 18}, + {760, 449, 20, 18}, + {780, 449, 20, 18}, + {800, 449, 20, 18}, + {820, 449, 20, 18}, + {840, 449, 20, 18}, + {860, 449, 20, 18}, + {880, 449, 20, 18}, + {900, 449, 20, 18}, + {920, 449, 20, 18}, + {940, 449, 20, 18}, + {960, 449, 20, 18}, + {980, 449, 20, 18}, + {1000, 449, 20, 18}, + {0, 468, 20, 29}, + {20, 468, 20, 29}, + {40, 468, 20, 29}, + {60, 468, 20, 29}, + {80, 468, 17, 29}, + {97, 468, 20, 29}, + {117, 468, 16, 29}, + {133, 468, 20, 29}, + {153, 468, 20, 29}, + {173, 468, 20, 29}, + {193, 468, 20, 29}, + {213, 468, 20, 29}, + {233, 468, 20, 29}, + {253, 468, 20, 29}, + {273, 468, 20, 29}, + {293, 468, 20, 29}, + {313, 468, 20, 29}, + {333, 468, 20, 29}, + {353, 468, 20, 29}, + {373, 468, 20, 29}, + {393, 468, 20, 29}, + {413, 468, 20, 29}, + {433, 468, 20, 29}, + {453, 468, 20, 29}, + {473, 468, 20, 29}, + {493, 468, 20, 29}, + {513, 468, 20, 29}, + {533, 468, 20, 29}, + {553, 468, 20, 29}, + {573, 468, 20, 29}, + {593, 468, 20, 29}, + {613, 468, 20, 29}, + {633, 468, 20, 29}, + {653, 468, 20, 29}, + {673, 468, 20, 29}, + {693, 468, 20, 29}, + {713, 468, 20, 29}, + {733, 468, 20, 29}, + {753, 468, 20, 29}, + {773, 468, 20, 29}, + {793, 468, 20, 29}, + {813, 468, 20, 29}, + {833, 468, 20, 29}, + {853, 468, 20, 29}, + {873, 468, 20, 29}, + {893, 468, 20, 29}, + {913, 468, 20, 29}, + {933, 468, 20, 29}, + {953, 468, 20, 29}, + {973, 468, 20, 29}, + {993, 468, 20, 29}, + {0, 497, 20, 18}, + {20, 497, 20, 18}, + {40, 497, 20, 18}, + {60, 497, 20, 18}, + {80, 497, 20, 18}, + {100, 497, 20, 18}, + {120, 497, 20, 18}, + {140, 497, 20, 18}, + {160, 497, 20, 18}, + {180, 497, 20, 18}, + {200, 497, 20, 18}, + {220, 497, 20, 18}, + {240, 497, 20, 18}, + {260, 497, 20, 18}, + {280, 497, 20, 18}, + {300, 497, 20, 18}, + {320, 497, 20, 18}, + {340, 497, 20, 18}, + {360, 497, 20, 18}, + {380, 497, 20, 18}, + {400, 497, 20, 18}, + {420, 497, 20, 18}, + {440, 497, 20, 18}, + {460, 497, 20, 18}, + {480, 497, 20, 18}, + {500, 497, 20, 18}, + {520, 497, 20, 18}, + {540, 497, 20, 18}, + {560, 497, 20, 18}, + {580, 497, 20, 18}, + {600, 497, 20, 18}, + {620, 497, 20, 18}, + {640, 497, 20, 18}, + {660, 497, 20, 18}, + {680, 497, 20, 18}, + {700, 497, 20, 18}, + {720, 497, 20, 18}, + {740, 497, 20, 18}, + {760, 497, 20, 18}, + {780, 497, 20, 18}, + {800, 497, 20, 18}, + {820, 497, 20, 18}, + {840, 497, 20, 18}, + {860, 497, 20, 18}, + {880, 497, 20, 18}, + {900, 497, 20, 18}, + {920, 497, 20, 18}, + {940, 497, 20, 18}, + {960, 497, 20, 18}, + {980, 497, 20, 18}, + {1000, 497, 20, 18}, + {0, 516, 20, 18}, + {20, 516, 20, 18}, + {40, 516, 20, 18}, + {60, 516, 20, 18}, + {80, 516, 20, 18}, + {100, 516, 20, 18}, + {120, 516, 20, 18}, + {140, 516, 20, 18}, + {160, 516, 20, 18}, + {180, 516, 20, 18}, + {200, 516, 20, 18}, + {220, 516, 20, 18}, + {240, 516, 20, 18}, + {260, 516, 20, 18}, + {280, 516, 20, 18}, + {300, 516, 20, 18}, + {320, 516, 20, 18}, + {340, 516, 20, 18}, + {360, 516, 20, 18}, + {380, 516, 20, 18}, + {400, 516, 20, 18}, + {420, 516, 20, 18}, + {440, 516, 20, 18}, + {460, 516, 20, 18}, + {480, 516, 20, 18}, + {500, 516, 20, 18}, + {520, 516, 20, 18}, + {540, 516, 20, 18}, + {560, 516, 20, 18}, + {580, 516, 20, 18}, + {600, 516, 20, 18}, + {620, 516, 20, 18}, + {640, 516, 20, 18}, + {660, 516, 20, 18}, + {680, 516, 20, 18}, + {700, 516, 20, 18}, + {720, 516, 20, 18}, + {740, 516, 20, 18}, + {760, 516, 20, 18}, + {780, 516, 20, 18}, + {800, 516, 20, 18}, + {820, 516, 20, 18}, + {840, 516, 20, 18}, + {860, 516, 20, 18}, + {880, 516, 20, 18}, + {900, 516, 20, 18}, + {920, 516, 20, 18}, + {940, 516, 20, 18}, + {960, 516, 20, 18}, + {980, 516, 20, 18}, + {1000, 516, 20, 18}, + {0, 535, 20, 29}, + {20, 535, 20, 29}, + {40, 535, 20, 29}, + {60, 535, 20, 29}, + {80, 535, 20, 29}, + {100, 535, 20, 29}, + {120, 535, 20, 29}, + {140, 535, 20, 29}, + {160, 535, 20, 29}, + {180, 535, 20, 29}, + {200, 535, 20, 29}, + {220, 535, 20, 29}, + {240, 535, 20, 29}, + {260, 535, 20, 29}, + {280, 535, 20, 29}, + {300, 535, 20, 29}, + {320, 535, 20, 29}, + {340, 535, 20, 29}, + {360, 535, 20, 29}, + {380, 535, 20, 29}, + {400, 535, 20, 29}, + {420, 535, 20, 29}, + {440, 535, 20, 29}, + {460, 535, 20, 29}, + {480, 535, 20, 29}, + {500, 535, 20, 29}, + {520, 535, 20, 29}, + {540, 535, 20, 29}, + {560, 535, 20, 29}, + {580, 535, 20, 29}, + {600, 535, 20, 29}, + {620, 535, 20, 29}, + {640, 535, 20, 29}, + {660, 535, 20, 29}, + {680, 535, 20, 29}, + {700, 535, 20, 29}, + {720, 535, 20, 29}, + {740, 535, 20, 29}, + {760, 535, 20, 29}, + {780, 535, 20, 29}, + {800, 535, 20, 29}, + {820, 535, 16, 29}, + {836, 535, 18, 29}, + {854, 535, 20, 29}, + {874, 535, 20, 29}, + {894, 535, 20, 29}, + {914, 535, 20, 29}, + {934, 535, 20, 29}, + {954, 535, 20, 29}, + {974, 535, 20, 29}, + {994, 535, 20, 29}, + {0, 564, 20, 18}, + {20, 564, 20, 18}, + {40, 564, 20, 18}, + {60, 564, 20, 18}, + {80, 564, 20, 18}, + {100, 564, 20, 18}, + {120, 564, 20, 18}, + {140, 564, 20, 18}, + {160, 564, 20, 18}, + {180, 564, 20, 18}, + {200, 564, 20, 18}, + {220, 564, 20, 18}, + {240, 564, 20, 18}, + {260, 564, 20, 18}, + {280, 564, 20, 18}, + {300, 564, 20, 18}, + {320, 564, 20, 18}, + {340, 564, 20, 18}, + {360, 564, 20, 18}, + {380, 564, 20, 18}, + {400, 564, 20, 18}, + {420, 564, 20, 18}, + {440, 564, 20, 18}, + {460, 564, 20, 18}, + {480, 564, 20, 18}, + {500, 564, 20, 18}, + {520, 564, 20, 18}, + {540, 564, 20, 18}, + {560, 564, 20, 18}, + {580, 564, 20, 18}, + {600, 564, 20, 18}, + {620, 564, 20, 18}, + {640, 564, 20, 18}, + {660, 564, 20, 18}, + {680, 564, 20, 18}, + {700, 564, 20, 18}, + {720, 564, 20, 18}, + {740, 564, 20, 18}, + {760, 564, 20, 18}, + {780, 564, 20, 18}, + {800, 564, 20, 18}, + {820, 564, 20, 18}, + {840, 564, 20, 18}, + {860, 564, 20, 18}, + {880, 564, 20, 18}, + {900, 564, 20, 18}, + {920, 564, 20, 18}, + {940, 564, 20, 18}, + {960, 564, 20, 18}, + {980, 564, 20, 18}, + {1000, 564, 20, 18}, + {0, 582, 20, 35}, + {20, 582, 20, 35}, + {40, 582, 20, 35}, + {60, 582, 20, 35}, + {80, 582, 15, 35}, + {95, 582, 15, 35}, + {110, 582, 16, 35}, + {126, 582, 16, 35}, + {142, 582, 14, 35}, + {156, 582, 14, 35}, + {170, 582, 14, 35}, + {184, 582, 13, 35}, + {197, 582, 11, 35}, + {208, 582, 11, 35}, + {219, 582, 11, 35}, + {230, 582, 17, 35}, + {247, 582, 17, 35}, + {264, 582, 20, 35}, + {284, 582, 20, 35}, + {304, 582, 20, 35}, + {324, 582, 20, 35}, + {344, 582, 13, 35}, + {357, 582, 20, 35}, + {377, 582, 20, 35}, + {397, 582, 20, 35}, + {417, 582, 20, 35}, + {437, 582, 20, 35}, + {457, 582, 20, 35}, + {477, 582, 20, 35}, + {497, 582, 20, 35}, + {517, 582, 20, 35}, + {537, 582, 20, 35}, + {557, 582, 20, 35}, + {577, 582, 20, 35}, + {597, 582, 20, 35}, + {617, 582, 20, 35}, + {637, 582, 20, 35}, + {657, 582, 20, 35}, + {677, 582, 20, 35}, + {697, 582, 20, 35}, + {717, 582, 20, 35}, + {737, 582, 20, 35}, + {757, 582, 20, 35}, + {777, 582, 20, 35}, + {797, 582, 20, 35}, + {817, 582, 20, 35}, + {837, 582, 17, 35}, + {854, 582, 17, 35}, + {871, 582, 17, 35}, + {888, 582, 15, 35}, + {903, 582, 20, 35}, + {923, 582, 14, 35}, + {937, 582, 19, 35}, + {956, 582, 8, 35}, + {964, 582, 20, 35}, + {984, 582, 15, 35}, + {999, 582, 17, 35}, + {0, 617, 17, 29}, + {17, 617, 20, 29}, + {37, 617, 20, 29}, + {57, 617, 17, 29}, + {74, 617, 14, 29}, + {88, 617, 16, 29}, + {104, 617, 17, 29}, + {121, 617, 20, 29}, + {141, 617, 7, 29}, + {148, 617, 17, 29}, + {165, 617, 7, 29}, + {172, 617, 16, 29}, + {188, 617, 16, 29}, + {204, 617, 16, 29}, + {220, 617, 8, 29}, + {228, 617, 19, 29}, + {247, 617, 19, 29}, + {266, 617, 19, 29}, + {285, 617, 20, 29}, + {305, 617, 19, 29}, + {324, 617, 8, 29}, + {332, 617, 15, 29}, + {347, 617, 17, 29}, + {364, 617, 15, 29}, + {379, 617, 18, 29}, + {397, 617, 17, 29}, + {414, 617, 17, 29}, + {431, 617, 19, 29}, + {450, 617, 17, 29}, + {467, 617, 20, 29}, + {487, 617, 17, 29}, + {504, 617, 15, 29}, + {519, 617, 15, 29}, + {534, 617, 13, 29}, + {547, 617, 20, 29}, + {567, 617, 20, 29}, + {587, 617, 13, 29}, + {600, 617, 20, 29}, + {620, 617, 20, 29}, + {640, 617, 20, 29}, + {660, 617, 20, 29}, + {680, 617, 20, 29}, + {700, 617, 20, 29}, + {720, 617, 13, 29}, + {733, 617, 13, 29}, + {746, 617, 13, 29}, + {759, 617, 13, 29}, + {772, 617, 13, 29}, + {785, 617, 13, 29}, + {798, 617, 20, 29}, + {818, 617, 10, 29}, + {828, 617, 18, 29}, + {846, 617, 18, 29}, + {864, 617, 17, 29}, + {881, 617, 10, 29}, + {891, 617, 14, 29}, + {905, 617, 14, 29}, + {919, 617, 14, 29}, + {933, 617, 19, 29}, + {952, 617, 17, 29}, + {969, 617, 11, 29}, + {980, 617, 11, 29}, + {991, 617, 11, 29}, + {1002, 617, 11, 29}, + {0, 646, 21, 29}, + {21, 646, 16, 29}, + {37, 646, 17, 29}, + {54, 646, 15, 29}, + {69, 646, 15, 29}, + {84, 646, 15, 29}, + {99, 646, 13, 29}, + {112, 646, 13, 29}, + {125, 646, 13, 29}, + {138, 646, 17, 29}, + {155, 646, 17, 29}, + {172, 646, 17, 29}, + {189, 646, 16, 29}, + {205, 646, 16, 29}, + {221, 646, 20, 29}, + {241, 646, 18, 29}, + {259, 646, 16, 29}, + {275, 646, 11, 29}, + {286, 646, 12, 29}, + {298, 646, 12, 29}, + {310, 646, 15, 29}, + {325, 646, 12, 29}, + {337, 646, 12, 29}, + {349, 646, 15, 29}, + {364, 646, 13, 29}, + {377, 646, 13, 29}, + {390, 646, 16, 29}, + {406, 646, 13, 29}, + {419, 646, 13, 29}, + {432, 646, 16, 29}, + {448, 646, 14, 29}, + {462, 646, 13, 29}, + {475, 646, 13, 29}, + {488, 646, 17, 29}, + {505, 646, 11, 29}, + {516, 646, 15, 29}, + {531, 646, 15, 29}, + {546, 646, 14, 29}, + {560, 646, 12, 29}, + {572, 646, 20, 29}, + {592, 646, 20, 29}, + {612, 646, 13, 29}, + {625, 646, 16, 29}, + {641, 646, 16, 29}, + {657, 646, 13, 29}, + {670, 646, 16, 29}, + {686, 646, 18, 29}, + {704, 646, 16, 29}, + {720, 646, 17, 29}, + {737, 646, 16, 29}, + {753, 646, 16, 29}, + {769, 646, 16, 29}, + {785, 646, 16, 29}, + {801, 646, 18, 29}, + {819, 646, 18, 29}, + {837, 646, 20, 29}, + {857, 646, 21, 29}, + {878, 646, 17, 29}, + {895, 646, 17, 29}, + {912, 646, 20, 29}, + {932, 646, 20, 29}, + {952, 646, 19, 29}, + {971, 646, 19, 29}, + {990, 646, 15, 29}, + {1005, 646, 17, 29}, + {0, 675, 12, 29}, + {12, 675, 13, 29}, + {25, 675, 15, 29}, + {40, 675, 13, 29}, + {53, 675, 12, 29}, + {65, 675, 14, 29}, + {79, 675, 22, 29}, + {101, 675, 20, 29}, + {121, 675, 20, 29}, + {141, 675, 20, 29}, + {161, 675, 20, 29}, + {181, 675, 20, 29}, + {201, 675, 20, 29}, + {221, 675, 20, 29}, + {241, 675, 20, 29}, + {261, 675, 20, 29}, + {281, 675, 20, 29}, + {301, 675, 20, 29}, + {321, 675, 20, 29}, + {341, 675, 20, 29}, + {361, 675, 20, 29}, + {381, 675, 20, 29}, + {401, 675, 20, 29}, + {421, 675, 20, 29}, + {441, 675, 20, 29}, + {461, 675, 20, 29}, + {481, 675, 20, 29}, + {501, 675, 20, 29}, + {521, 675, 20, 29}, + {541, 675, 20, 29}, + {561, 675, 20, 29}, + {581, 675, 20, 29}, + {601, 675, 20, 29}, + {621, 675, 20, 29}, + {641, 675, 20, 29}, + {661, 675, 20, 29}, + {681, 675, 20, 29}, + {701, 675, 20, 29}, + {721, 675, 20, 29}, + {741, 675, 20, 29}, + {761, 675, 20, 29}, + {781, 675, 20, 29}, + {801, 675, 20, 29}, + {821, 675, 20, 29}, + {841, 675, 20, 29}, + {861, 675, 20, 29}, + {881, 675, 20, 29}, + {901, 675, 20, 29}, + {921, 675, 20, 29}, + {941, 675, 20, 29}, + {961, 675, 20, 29}, + {981, 675, 20, 29}, + {1001, 675, 20, 29}, + {0, 704, 20, 29}, + {20, 704, 20, 29}, + {40, 704, 20, 29}, + {60, 704, 20, 29}, + {80, 704, 20, 29}, + {100, 704, 20, 29}, + {120, 704, 20, 29}, + {140, 704, 20, 29}, + {160, 704, 20, 29}, + {180, 704, 20, 29}, + {200, 704, 20, 29}, + {220, 704, 20, 29}, + {240, 704, 20, 29}, + {260, 704, 20, 29}, + {280, 704, 20, 29}, + {300, 704, 20, 29}, + {320, 704, 20, 29}, + {340, 704, 20, 29}, + {360, 704, 20, 29}, + {380, 704, 20, 29}, + {400, 704, 20, 29}, + {420, 704, 20, 29}, + {440, 704, 20, 29}, + {460, 704, 20, 29}, + {480, 704, 20, 29}, + {500, 704, 20, 29}, + {520, 704, 20, 29}, + {540, 704, 20, 29}, + {560, 704, 20, 29}, + {580, 704, 20, 29}, + {600, 704, 20, 29}, + {620, 704, 20, 29}, + {640, 704, 20, 29}, + {660, 704, 20, 29}, + {680, 704, 20, 29}, + {700, 704, 20, 29}, + {720, 704, 20, 29}, + {740, 704, 20, 29}, + {760, 704, 20, 29}, + {780, 704, 14, 29}, + {794, 704, 15, 29}, + {809, 704, 15, 29}, + {824, 704, 14, 29}, + {838, 704, 15, 29}, + {853, 704, 14, 29}, + {867, 704, 14, 29}, + {881, 704, 15, 29}, + {896, 704, 16, 29}, + {912, 704, 16, 29}, + {928, 704, 16, 29}, + {944, 704, 16, 29}, + {960, 704, 18, 29}, + {978, 704, 18, 29}, + {996, 704, 18, 29}, + {0, 733, 18, 29}, + {18, 733, 16, 29}, + {34, 733, 16, 29}, + {50, 733, 16, 29}, + {66, 733, 16, 29}, + {82, 733, 17, 29}, + {99, 733, 17, 29}, + {116, 733, 17, 29}, + {133, 733, 17, 29}, + {150, 733, 16, 29}, + {166, 733, 16, 29}, + {182, 733, 16, 29}, + {198, 733, 16, 29}, + {214, 733, 17, 29}, + {231, 733, 12, 29}, + {243, 733, 17, 29}, + {260, 733, 12, 29}, + {272, 733, 20, 29}, + {292, 733, 20, 29}, + {312, 733, 11, 29}, + {323, 733, 12, 29}, + {335, 733, 14, 29}, + {349, 733, 20, 29}, + {369, 733, 11, 29}, + {380, 733, 11, 29}, + {391, 733, 12, 29}, + {403, 733, 11, 29}, + {414, 733, 8, 29}, + {422, 733, 9, 29}, + {431, 733, 19, 29}, + {450, 733, 19, 29}, + {469, 733, 19, 29}, + {488, 733, 19, 29}, + {507, 733, 20, 29}, + {527, 733, 20, 29}, + {547, 733, 20, 29}, + {567, 733, 20, 29}, + {587, 733, 20, 29}, + {607, 733, 20, 29}, + {627, 733, 20, 29}, + {647, 733, 20, 29}, + {667, 733, 20, 29}, + {687, 733, 20, 29}, + {707, 733, 20, 29}, + {727, 733, 20, 29}, + {747, 733, 20, 29}, + {767, 733, 20, 29}, + {787, 733, 20, 29}, + {807, 733, 20, 29}, + {827, 733, 20, 29}, + {847, 733, 20, 29}, + {867, 733, 20, 29}, + {887, 733, 20, 29}, + {907, 733, 20, 29}, + {927, 733, 20, 29}, + {947, 733, 20, 29}, + {967, 733, 20, 29}, + {987, 733, 20, 29}, + {0, 762, 20, 29}, + {20, 762, 20, 29}, + {40, 762, 20, 29}, + {60, 762, 20, 29}, + {80, 762, 20, 29}, + {100, 762, 20, 29}, + {120, 762, 20, 29}, + {140, 762, 20, 29}, + {160, 762, 20, 29}, + {180, 762, 20, 29}, + {200, 762, 20, 29}, + {220, 762, 20, 29}, + {240, 762, 20, 29}, + {260, 762, 20, 29}, + {280, 762, 20, 29}, + {300, 762, 20, 29}, + {320, 762, 20, 29}, + {340, 762, 20, 29}, + {360, 762, 20, 29}, + {380, 762, 20, 29}, + {400, 762, 20, 29}, + {420, 762, 20, 29}, + {440, 762, 20, 29}, + {460, 762, 20, 29}, + {480, 762, 20, 29}, + {500, 762, 20, 29}, + {520, 762, 20, 29}, + {540, 762, 20, 29}, + {560, 762, 20, 29}, + {580, 762, 20, 29}, + {600, 762, 20, 29}, + {620, 762, 20, 29}, + {640, 762, 20, 29}, + {660, 762, 20, 29}, + {680, 762, 20, 29}, + {700, 762, 20, 29}, + {720, 762, 20, 29}, + {740, 762, 20, 29}, + {760, 762, 20, 29}, + {780, 762, 20, 29}, + {800, 762, 20, 29}, + {820, 762, 20, 29}, + {840, 762, 20, 29}, + {860, 762, 20, 29}, + {880, 762, 20, 29}, + {900, 762, 16, 29}, + {916, 762, 16, 29}, + {932, 762, 16, 29}, + {948, 762, 9, 29}, + {957, 762, 9, 29}, + {966, 762, 18, 29}, + {984, 762, 20, 29}, + {1004, 762, 16, 29}, + {0, 791, 13, 35}, + {13, 791, 17, 35}, + {30, 791, 20, 35}, + {50, 791, 20, 35}, + {70, 791, 20, 35}, + {90, 791, 23, 35}, + {113, 791, 23, 35}, + {136, 791, 20, 35}, + {156, 791, 20, 35}, + {176, 791, 20, 35}, + {196, 791, 23, 35}, + {219, 791, 23, 35}, + {242, 791, 23, 35}, + {265, 791, 23, 35}, + {288, 791, 23, 35}, + {311, 791, 23, 35}, + {334, 791, 23, 35}, + {357, 791, 23, 35}, + {380, 791, 16, 35}, + {396, 791, 14, 35}, + {410, 791, 11, 35}, + {421, 791, 18, 35}, + {439, 791, 18, 35}, + {457, 791, 17, 35}, + {474, 791, 11, 35}, + {485, 791, 15, 35}, + {500, 791, 16, 35}, + {516, 791, 18, 35}, + {534, 791, 12, 35}, + {546, 791, 20, 35}, + {566, 791, 20, 35}, + {586, 791, 23, 35}, + {609, 791, 23, 35}, + {632, 791, 23, 35}, + {655, 791, 17, 35}, + {672, 791, 15, 35}, + {687, 791, 18, 35}, + {705, 791, 18, 35}, + {723, 791, 20, 35}, + {743, 791, 20, 35}, + {763, 791, 20, 35}, + {783, 791, 20, 35}, + {803, 791, 20, 35}, + {823, 791, 20, 35}, + {843, 791, 20, 35}, + {863, 791, 20, 35}, + {883, 791, 20, 35}, + {903, 791, 23, 35}, + {926, 791, 23, 35}, + {949, 791, 23, 35}, + {972, 791, 18, 35}, + {990, 791, 14, 35}, + {1004, 791, 14, 35}, + {0, 826, 14, 34}, + {14, 826, 14, 34}, + {28, 826, 18, 34}, + {46, 826, 19, 34}, + {65, 826, 17, 34}, + {82, 826, 11, 34}, + {93, 826, 13, 34}, + {106, 826, 13, 34}, + {119, 826, 13, 34}, + {132, 826, 8, 34}, + {140, 826, 11, 34}, + {151, 826, 11, 34}, + {162, 826, 14, 34}, + {176, 826, 14, 34}, + {190, 826, 11, 34}, + {201, 826, 15, 34}, + {216, 826, 18, 34}, + {234, 826, 13, 34}, + {247, 826, 13, 34}, + {260, 826, 13, 34}, + {273, 826, 13, 34}, + {286, 826, 9, 34}, + {295, 826, 19, 34}, + {314, 826, 16, 34}, + {330, 826, 15, 34}, + {345, 826, 18, 34}, + {363, 826, 16, 34}, + {379, 826, 10, 34}, + {389, 826, 10, 34}, + {399, 826, 10, 34}, + {409, 826, 15, 34}, + {424, 826, 10, 34}, + {434, 826, 6, 34}, + {440, 826, 22, 34}, + {462, 826, 8, 34}, + {470, 826, 8, 34}, + {478, 826, 8, 34}, + {486, 826, 13, 34}, + {499, 826, 12, 34}, + {511, 826, 12, 34}, + {523, 826, 10, 34}, + {533, 826, 10, 34}, + {543, 826, 8, 34}, + {551, 826, 7, 34}, + {558, 826, 8, 34}, + {566, 826, 10, 34}, + {576, 826, 8, 34}, + {584, 826, 15, 34}, + {599, 826, 17, 34}, + {616, 826, 10, 34}, + {626, 826, 10, 34}, + {636, 826, 13, 34}, + {649, 826, 11, 34}, + {660, 826, 15, 34}, + {675, 826, 12, 34}, + {687, 826, 15, 34}, + {702, 826, 10, 34}, + {712, 826, 15, 34}, + {727, 826, 15, 34}, + {742, 826, 14, 34}, + {756, 826, 8, 34}, + {764, 826, 15, 34}, + {779, 826, 11, 34}, + {790, 826, 11, 34}, + {801, 826, 14, 34}, + {815, 826, 16, 34}, + {831, 826, 8, 34}, + {839, 826, 13, 34}, + {852, 826, 23, 34}, + {875, 826, 16, 34}, + {891, 826, 15, 34}, + {906, 826, 13, 34}, + {919, 826, 7, 34}, + {926, 826, 9, 34}, + {935, 826, 9, 34}, + {944, 826, 12, 34}, + {956, 826, 9, 34}, + {965, 826, 20, 34}, + {985, 826, 15, 34}, + {1000, 826, 15, 34}, + {0, 860, 14, 35}, + {14, 860, 11, 35}, + {25, 860, 13, 35}, + {38, 860, 15, 35}, + {53, 860, 13, 35}, + {66, 860, 9, 35}, + {75, 860, 17, 35}, + {92, 860, 17, 35}, + {109, 860, 16, 35}, + {125, 860, 19, 35}, + {144, 860, 15, 35}, + {159, 860, 16, 35}, + {175, 860, 16, 35}, + {191, 860, 22, 35}, + {213, 860, 12, 35}, + {225, 860, 14, 35}, + {239, 860, 13, 35}, + {252, 860, 15, 35}, + {267, 860, 10, 35}, + {277, 860, 11, 35}, + {288, 860, 12, 35}, + {300, 860, 11, 35}, + {311, 860, 13, 35}, + {324, 860, 18, 35}, + {342, 860, 17, 35}, + {359, 860, 15, 35}, + {374, 860, 9, 35}, + {383, 860, 15, 35}, + {398, 860, 13, 35}, + {411, 860, 15, 35}, + {426, 860, 13, 35}, + {439, 860, 16, 35}, + {455, 860, 17, 35}, + {472, 860, 23, 35}, + {495, 860, 23, 35}, + {518, 860, 23, 35}, + {541, 860, 23, 35}, + {564, 860, 23, 35}, + {587, 860, 23, 35}, + {610, 860, 23, 35}, + {633, 860, 23, 35}, + {656, 860, 23, 35}, + {679, 860, 23, 35}, + {702, 860, 23, 35}, + {725, 860, 23, 35}, + {748, 860, 8, 35}, + {756, 860, 14, 35}, + {770, 860, 8, 35}, + {778, 860, 14, 35}, + {792, 860, 6, 35}, + {798, 860, 14, 35}, + {812, 860, 14, 35}, + {826, 860, 14, 35}, + {840, 860, 14, 35}, + {854, 860, 14, 35}, + {868, 860, 14, 35}, + {882, 860, 14, 35}, + {896, 860, 4, 35}, + {900, 860, 5, 35}, + {905, 860, 13, 35}, + {918, 860, 13, 35}, + {931, 860, 13, 35}, + {944, 860, 13, 35}, + {957, 860, 13, 35}, + {970, 860, 13, 35}, + {983, 860, 13, 35}, + {996, 860, 13, 35}, + {1009, 860, 13, 35}, + {0, 895, 4, 29}, + {4, 895, 5, 29}, + {9, 895, 10, 29}, + {19, 895, 18, 29}, + {37, 895, 18, 29}, + {55, 895, 18, 29}, + {73, 895, 3, 29}, + {76, 895, 4, 29}, + {80, 895, 7, 29}, + {87, 895, 12, 29}, + {99, 895, 14, 29}, + {113, 895, 14, 29}, + {127, 895, 14, 29}, + {141, 895, 14, 29}, + {155, 895, 14, 29}, + {169, 895, 14, 29}, + {183, 895, 14, 29}, + {197, 895, 11, 29}, + {208, 895, 11, 29}, + {219, 895, 11, 29}, + {230, 895, 11, 29}, + {241, 895, 12, 29}, + {253, 895, 12, 29}, + {265, 895, 12, 29}, + {277, 895, 13, 29}, + {290, 895, 13, 29}, + {303, 895, 14, 29}, + {317, 895, 14, 29}, + {331, 895, 14, 29}, + {345, 895, 14, 29}, + {359, 895, 13, 29}, + {372, 895, 13, 29}, + {385, 895, 13, 29}, + {398, 895, 13, 29}, + {411, 895, 13, 29}, + {424, 895, 13, 29}, + {437, 895, 14, 29}, + {451, 895, 14, 29}, + {465, 895, 14, 29}, + {479, 895, 14, 29}, + {493, 895, 14, 29}, + {507, 895, 12, 29}, + {519, 895, 12, 29}, + {531, 895, 12, 29}, + {543, 895, 12, 29}, + {555, 895, 14, 29}, + {569, 895, 14, 29}, + {583, 895, 14, 29}, + {597, 895, 14, 29}, + {611, 895, 14, 29}, + {625, 895, 13, 29}, + {638, 895, 13, 29}, + {651, 895, 12, 29}, + {663, 895, 12, 29}, + {675, 895, 12, 29}, + {687, 895, 14, 29}, + {701, 895, 13, 29}, + {714, 895, 14, 29}, + {728, 895, 14, 29}, + {742, 895, 15, 29}, + {757, 895, 15, 29}, + {772, 895, 15, 29}, + {787, 895, 23, 29}, + {810, 895, 23, 29}, + {833, 895, 23, 29}, + {856, 895, 23, 29}, + {879, 895, 23, 29}, + {902, 895, 23, 29}, + {925, 895, 23, 29}, + {948, 895, 23, 29}, + {971, 895, 23, 29}, + {994, 895, 23, 29}, + {0, 924, 23, 29}, + {23, 924, 20, 29}, + {43, 924, 20, 29}, + {63, 924, 20, 29}, + {83, 924, 20, 29}, + {103, 924, 20, 29}, + {123, 924, 20, 29}, + {143, 924, 20, 29}, + {163, 924, 20, 29}, + {183, 924, 20, 29}, + {203, 924, 20, 29}, + {223, 924, 20, 29}, + {243, 924, 20, 29}, + {263, 924, 23, 29}, + {286, 924, 23, 29}, + {309, 924, 23, 29}, + {332, 924, 23, 29}, + {355, 924, 23, 29}, + {378, 924, 23, 29}, + {401, 924, 23, 29}, + {424, 924, 23, 29}, + {447, 924, 23, 29}, + {470, 924, 23, 29}, + {493, 924, 23, 29}, + {516, 924, 23, 29}, + {539, 924, 23, 29}, + {562, 924, 23, 29}, + {585, 924, 23, 29}, + {608, 924, 23, 29}, + {631, 924, 23, 29}, + {654, 924, 23, 29}, + {677, 924, 23, 29}, + {700, 924, 23, 29}, + {723, 924, 13, 29}, + {736, 924, 6, 29}, + {742, 924, 13, 29}, + {755, 924, 6, 29}, + {761, 924, 13, 29}, + {774, 924, 9, 29}, + {783, 924, 13, 29}, + {796, 924, 9, 29}, + {805, 924, 15, 29}, + {820, 924, 13, 29}, + {833, 924, 15, 29}, + {848, 924, 13, 29}, + {861, 924, 23, 29}, + {884, 924, 23, 29}, + {907, 924, 23, 29}, + {930, 924, 23, 29}, + {953, 924, 14, 29}, + {967, 924, 6, 29}, + {973, 924, 14, 29}, + {987, 924, 6, 29}, + {993, 924, 14, 29}, + {1007, 924, 7, 29}, + {0, 953, 14, 29}, + {14, 953, 7, 29}, + {21, 953, 14, 29}, + {35, 953, 8, 29}, + {43, 953, 14, 29}, + {57, 953, 8, 29}, + {65, 953, 14, 29}, + {79, 953, 10, 29}, + {89, 953, 14, 29}, + {103, 953, 10, 29}, + {113, 953, 14, 29}, + {127, 953, 9, 29}, + {136, 953, 14, 29}, + {150, 953, 9, 29}, + {159, 953, 13, 29}, + {172, 953, 9, 29}, + {181, 953, 13, 29}, + {194, 953, 9, 29}, + {203, 953, 13, 29}, + {216, 953, 9, 29}, + {225, 953, 13, 29}, + {238, 953, 9, 29}, + {247, 953, 13, 29}, + {260, 953, 11, 29}, + {271, 953, 13, 29}, + {284, 953, 11, 29}, + {295, 953, 16, 29}, + {311, 953, 11, 29}, + {322, 953, 16, 29}, + {338, 953, 11, 29}, + {349, 953, 13, 29}, + {362, 953, 9, 29}, + {371, 953, 13, 29}, + {384, 953, 9, 29}, + {393, 953, 8, 29}, + {401, 953, 10, 29}, + {411, 953, 8, 29}, + {419, 953, 10, 29}, + {429, 953, 6, 29}, + {435, 953, 13, 29}, + {448, 953, 6, 29}, + {454, 953, 13, 29}, + {467, 953, 9, 29}, + {476, 953, 16, 29}, + {492, 953, 9, 29}, + {501, 953, 16, 29}, + {517, 953, 17, 29}, + {534, 953, 16, 29}, + {550, 953, 17, 29}, + {567, 953, 16, 29}, + {583, 953, 23, 29}, + {606, 953, 23, 29}, + {629, 953, 23, 29}, + {652, 953, 23, 29}, + {675, 953, 23, 29}, + {698, 953, 23, 29}, + {721, 953, 23, 29}, + {744, 953, 23, 29}, + {767, 953, 13, 29}, + {780, 953, 8, 29}, + {788, 953, 13, 29}, + {801, 953, 8, 29}, + {809, 953, 11, 29}, + {820, 953, 11, 29}, + {831, 953, 11, 29}, + {842, 953, 11, 29}, + {853, 953, 17, 29}, + {870, 953, 8, 29}, + {878, 953, 23, 29}, + {901, 953, 23, 29}, + {924, 953, 23, 29}, + {947, 953, 23, 29}, + {970, 953, 23, 29}, + {993, 953, 23, 29}, + {0, 982, 13, 29}, + {13, 982, 11, 29}, + {24, 982, 13, 29}, + {37, 982, 11, 29}, + {48, 982, 10, 29}, + {58, 982, 10, 29}, + {68, 982, 10, 29}, + {78, 982, 10, 29}, + {88, 982, 13, 29}, + {101, 982, 11, 29}, + {112, 982, 13, 29}, + {125, 982, 11, 29}, + {136, 982, 10, 29}, + {146, 982, 10, 29}, + {156, 982, 10, 29}, + {166, 982, 10, 29}, + {176, 982, 13, 29}, + {189, 982, 11, 29}, + {200, 982, 13, 29}, + {213, 982, 11, 29}, + {224, 982, 11, 29}, + {235, 982, 11, 29}, + {246, 982, 11, 29}, + {257, 982, 11, 29}, + {268, 982, 13, 29}, + {281, 982, 11, 29}, + {292, 982, 13, 29}, + {305, 982, 11, 29}, + {316, 982, 11, 29}, + {327, 982, 11, 29}, + {338, 982, 11, 29}, + {349, 982, 11, 29}, + {360, 982, 13, 29}, + {373, 982, 11, 29}, + {384, 982, 13, 29}, + {397, 982, 11, 29}, + {408, 982, 12, 29}, + {420, 982, 12, 29}, + {432, 982, 12, 29}, + {444, 982, 12, 29}, + {456, 982, 23, 29}, + {479, 982, 23, 29}, + {502, 982, 23, 29}, + {525, 982, 23, 29}, + {548, 982, 23, 29}, + {571, 982, 23, 29}, + {594, 982, 23, 29}, + {617, 982, 23, 29}, + {640, 982, 6, 29}, + {646, 982, 9, 29}, + {655, 982, 6, 29}, + {661, 982, 9, 29}, + {670, 982, 9, 29}, + {679, 982, 13, 29}, + {692, 982, 9, 29}, + {701, 982, 13, 29}, + {714, 982, 13, 29}, + {727, 982, 8, 29}, + {735, 982, 13, 29}, + {748, 982, 8, 29}, + {756, 982, 7, 29}, + {763, 982, 5, 29}, + {768, 982, 4, 29}, + {772, 982, 4, 29}, + {776, 982, 16, 29}, + {792, 982, 16, 29}, + {808, 982, 16, 29}, + {824, 982, 16, 29}, + {840, 982, 16, 29}, + {856, 982, 16, 29}, + {872, 982, 16, 29}, + {888, 982, 16, 29}, + {904, 982, 16, 29}, + {920, 982, 16, 29}, + {936, 982, 16, 29}, + {952, 982, 16, 29}, + {968, 982, 7, 29}, + {975, 982, 6, 29}, + {981, 982, 23, 29}, + {0, 1011, 23, 21}, + {23, 1011, 23, 21}, + {46, 1011, 23, 21}, + {69, 1011, 23, 21}, + {92, 1011, 23, 21}, + {115, 1011, 23, 21}, + {138, 1011, 23, 21}, + {161, 1011, 23, 21}, + {184, 1011, 23, 21}, + {207, 1011, 23, 21}, + {230, 1011, 23, 21}, + {253, 1011, 23, 21}, + {276, 1011, 23, 21}, + {299, 1011, 23, 21}, + {322, 1011, 23, 21}, + {345, 1011, 23, 21}, + {368, 1011, 23, 21}, + {391, 1011, 23, 21}, + {414, 1011, 23, 21}, + {437, 1011, 23, 21}, + {460, 1011, 23, 21}, + {483, 1011, 23, 21}, + {506, 1011, 23, 21}, + {529, 1011, 23, 21}, + {552, 1011, 23, 21}, + {575, 1011, 23, 21}, + {598, 1011, 23, 21}, + {621, 1011, 23, 21}, + {644, 1011, 23, 21}, + {667, 1011, 23, 21}, + {690, 1011, 23, 21}, + {713, 1011, 23, 21}, + {736, 1011, 23, 21}, + {759, 1011, 23, 21}, + {782, 1011, 23, 21}, + {805, 1011, 23, 21}, + {828, 1011, 23, 21}, + {851, 1011, 23, 21}, + {874, 1011, 23, 21}, + {897, 1011, 23, 21}, + {920, 1011, 23, 21}, + {943, 1011, 23, 21}, + {966, 1011, 23, 21}, + {989, 1011, 23, 21}, + {0, 1032, 23, 22}, + {23, 1032, 23, 22}, + {46, 1032, 23, 22}, + {69, 1032, 23, 22}, + {92, 1032, 23, 22}, + {115, 1032, 23, 22}, + {138, 1032, 23, 22}, + {161, 1032, 23, 22}, + {184, 1032, 23, 22}, + {207, 1032, 23, 22}, + {230, 1032, 23, 22}, + {253, 1032, 23, 22}, + {276, 1032, 23, 22}, + {299, 1032, 23, 22}, + {322, 1032, 23, 22}, + {345, 1032, 23, 22}, + {368, 1032, 23, 22}, + {391, 1032, 23, 22}, + {414, 1032, 23, 22}, + {437, 1032, 23, 22}, + {460, 1032, 23, 22}, + {483, 1032, 23, 22}, + {506, 1032, 23, 22}, + {529, 1032, 23, 22}, + {552, 1032, 23, 22}, + {575, 1032, 23, 22}, + {598, 1032, 23, 22}, + {621, 1032, 23, 22}, + {644, 1032, 23, 22}, + {667, 1032, 23, 22}, + {690, 1032, 23, 22}, + {713, 1032, 23, 22}, + {736, 1032, 23, 22}, + {759, 1032, 23, 22}, + {782, 1032, 23, 22}, + {805, 1032, 23, 22}, + {828, 1032, 23, 22}, + {851, 1032, 23, 22}, + {874, 1032, 23, 22}, + {897, 1032, 23, 22}, + {920, 1032, 23, 22}, + {943, 1032, 23, 22}, + {966, 1032, 23, 22}, + {989, 1032, 23, 22}, + {0, 1054, 23, 21}, + {23, 1054, 23, 21}, + {46, 1054, 23, 21}, + {69, 1054, 23, 21}, + {92, 1054, 23, 21}, + {115, 1054, 20, 21}, + {135, 1054, 20, 21}, + {155, 1054, 20, 21}, + {175, 1054, 20, 21}, + {195, 1054, 20, 21}, + {215, 1054, 20, 21}, + {235, 1054, 20, 21}, + {255, 1054, 20, 21}, + {275, 1054, 20, 21}, + {295, 1054, 20, 21}, + {315, 1054, 20, 21}, + {335, 1054, 20, 21}, + {355, 1054, 20, 21}, + {375, 1054, 20, 21}, + {395, 1054, 20, 21}, + {415, 1054, 20, 21}, + {435, 1054, 20, 21}, + {455, 1054, 20, 21}, + {475, 1054, 20, 21}, + {495, 1054, 20, 21}, + {515, 1054, 20, 21}, + {535, 1054, 20, 21}, + {555, 1054, 20, 21}, + {575, 1054, 20, 21}, + {595, 1054, 20, 21}, + {615, 1054, 20, 21}, + {635, 1054, 20, 21}, + {655, 1054, 20, 21}, + {675, 1054, 20, 21}, + {695, 1054, 20, 21}, + {715, 1054, 20, 21}, + {735, 1054, 20, 21}, + {755, 1054, 20, 21}, + {775, 1054, 20, 21}, + {795, 1054, 20, 21}, + {815, 1054, 20, 21}, + {835, 1054, 20, 21}, + {855, 1054, 20, 21}, + {875, 1054, 20, 21}, + {895, 1054, 20, 21}, + {915, 1054, 20, 21}, + {935, 1054, 20, 21}, + {955, 1054, 20, 21}, + {975, 1054, 20, 21}, + {995, 1054, 20, 21}, + {0, 1075, 20, 29}, + {20, 1075, 20, 29}, + {40, 1075, 14, 29}, + {54, 1075, 20, 29}, + {74, 1075, 20, 29}, + {94, 1075, 20, 29}, + {114, 1075, 20, 29}, + {134, 1075, 20, 29}, + {154, 1075, 20, 29}, + {174, 1075, 20, 29}, + {194, 1075, 20, 29}, + {214, 1075, 20, 29}, + {234, 1075, 20, 29}, + {254, 1075, 17, 29}, + {271, 1075, 20, 29}, + {291, 1075, 20, 29}, + {311, 1075, 20, 29}, + {331, 1075, 20, 29}, + {351, 1075, 20, 29}, + {371, 1075, 20, 29}, + {391, 1075, 20, 29}, + {411, 1075, 20, 29}, + {431, 1075, 20, 29}, + {451, 1075, 20, 29}, + {471, 1075, 20, 29}, + {491, 1075, 20, 29}, + {511, 1075, 20, 29}, + {531, 1075, 20, 29}, + {551, 1075, 20, 29}, + {571, 1075, 20, 29}, + {591, 1075, 20, 29}, + {611, 1075, 20, 29}, + {631, 1075, 20, 29}, + {651, 1075, 20, 29}, + {671, 1075, 20, 29}, + {691, 1075, 20, 29}, + {711, 1075, 20, 29}, + {731, 1075, 20, 29}, + {751, 1075, 20, 29}, + {771, 1075, 20, 29}, + {791, 1075, 20, 29}, + {811, 1075, 20, 29}, + {831, 1075, 20, 29}, + {851, 1075, 20, 29}, + {871, 1075, 20, 29}, + {891, 1075, 20, 29}, + {911, 1075, 20, 29}, + {931, 1075, 20, 29}, + {951, 1075, 20, 29}, + {971, 1075, 20, 29}, + {991, 1075, 20, 29}, + {0, 1104, 20, 21}, + {20, 1104, 20, 21}, + {40, 1104, 20, 21}, + {60, 1104, 20, 21}, + {80, 1104, 20, 21}, + {100, 1104, 20, 21}, + {120, 1104, 20, 21}, + {140, 1104, 20, 21}, + {160, 1104, 20, 21}, + {180, 1104, 20, 21}, + {200, 1104, 20, 21}, + {220, 1104, 20, 21}, + {240, 1104, 20, 21}, + {260, 1104, 23, 21}, + {283, 1104, 20, 21}, + {303, 1104, 20, 21}, + {323, 1104, 20, 21}, + {343, 1104, 20, 21}, + {363, 1104, 20, 21}, + {383, 1104, 20, 21}, + {403, 1104, 20, 21}, + {423, 1104, 20, 21}, + {443, 1104, 20, 21}, + {463, 1104, 20, 21}, + {483, 1104, 20, 21}, + {503, 1104, 20, 21}, + {523, 1104, 20, 21}, + {543, 1104, 20, 21}, + {563, 1104, 20, 21}, + {583, 1104, 20, 21}, + {603, 1104, 20, 21}, + {623, 1104, 20, 21}, + {643, 1104, 20, 21}, + {663, 1104, 20, 21}, + {683, 1104, 20, 21}, + {703, 1104, 20, 21}, + {723, 1104, 20, 21}, + {743, 1104, 20, 21}, + {763, 1104, 20, 21}, + {783, 1104, 20, 21}, + {803, 1104, 20, 21}, + {823, 1104, 20, 21}, + {843, 1104, 20, 21}, + {863, 1104, 20, 21}, + {883, 1104, 20, 21}, + {903, 1104, 20, 21}, + {923, 1104, 20, 21}, + {943, 1104, 20, 21}, + {963, 1104, 20, 21}, + {983, 1104, 20, 21}, + {1003, 1104, 20, 21}, + {0, 1125, 20, 21}, + {20, 1125, 20, 21}, + {40, 1125, 20, 21}, + {60, 1125, 20, 21}, + {80, 1125, 20, 21}, + {100, 1125, 20, 21}, + {120, 1125, 20, 21}, + {140, 1125, 20, 21}, + {160, 1125, 20, 21}, + {180, 1125, 20, 21}, + {200, 1125, 20, 21}, + {220, 1125, 20, 21}, + {240, 1125, 20, 21}, + {260, 1125, 20, 21}, + {280, 1125, 20, 21}, + {300, 1125, 20, 21}, + {320, 1125, 20, 21}, + {340, 1125, 20, 21}, + {360, 1125, 20, 21}, + {380, 1125, 20, 21}, + {400, 1125, 20, 21}, + {420, 1125, 20, 21}, + {440, 1125, 20, 21}, + {460, 1125, 20, 21}, + {480, 1125, 20, 21}, + {500, 1125, 20, 21}, + {520, 1125, 20, 21}, + {540, 1125, 20, 21}, + {560, 1125, 20, 21}, + {580, 1125, 20, 21}, + {600, 1125, 20, 21}, + {620, 1125, 20, 21}, + {640, 1125, 20, 21}, + {660, 1125, 20, 21}, + {680, 1125, 20, 21}, + {700, 1125, 20, 21}, + {720, 1125, 20, 21}, + {740, 1125, 20, 21}, + {760, 1125, 20, 21}, + {780, 1125, 20, 21}, + {800, 1125, 20, 21}, + {820, 1125, 20, 21}, + {840, 1125, 20, 21}, + {860, 1125, 20, 21}, + {880, 1125, 20, 21}, + {900, 1125, 23, 21}, + {923, 1125, 20, 21}, + {943, 1125, 20, 21}, + {963, 1125, 20, 21}, + {983, 1125, 20, 21}, + {1003, 1125, 20, 21}, + {0, 1146, 20, 21}, + {20, 1146, 20, 21}, + {40, 1146, 20, 21}, + {60, 1146, 20, 21}, + {80, 1146, 20, 21}, + {100, 1146, 20, 21}, + {120, 1146, 20, 21}, + {140, 1146, 20, 21}, + {160, 1146, 20, 21}, + {180, 1146, 20, 21}, + {200, 1146, 20, 21}, + {220, 1146, 20, 21}, + {240, 1146, 20, 21}, + {260, 1146, 20, 21}, + {280, 1146, 20, 21}, + {300, 1146, 20, 21}, + {320, 1146, 20, 21}, + {340, 1146, 20, 21}, + {360, 1146, 20, 21}, + {380, 1146, 20, 21}, + {400, 1146, 20, 21}, + {420, 1146, 20, 21}, + {440, 1146, 20, 21}, + {460, 1146, 20, 21}, + {480, 1146, 20, 21}, + {500, 1146, 20, 21}, + {520, 1146, 20, 21}, + {540, 1146, 20, 21}, + {560, 1146, 20, 21}, + {580, 1146, 20, 21}, + {600, 1146, 20, 21}, + {620, 1146, 20, 21}, + {640, 1146, 20, 21}, + {660, 1146, 20, 21}, + {680, 1146, 20, 21}, + {700, 1146, 20, 21}, + {720, 1146, 20, 21}, + {740, 1146, 20, 21}, + {760, 1146, 20, 21}, + {780, 1146, 20, 21}, + {800, 1146, 20, 21}, + {820, 1146, 20, 21}, + {840, 1146, 20, 21}, + {860, 1146, 20, 21}, + {880, 1146, 20, 21}, + {900, 1146, 20, 21}, + {920, 1146, 23, 21}, + {943, 1146, 23, 21}, + {966, 1146, 23, 21}, + {989, 1146, 23, 21}, + {0, 1167, 23, 21}, + {23, 1167, 23, 21}, + {46, 1167, 23, 21}, + {69, 1167, 23, 21}, + {92, 1167, 23, 21}, + {115, 1167, 23, 21}, + {138, 1167, 23, 21}, + {161, 1167, 23, 21}, + {184, 1167, 23, 21}, + {207, 1167, 23, 21}, + {230, 1167, 23, 21}, + {253, 1167, 23, 21}, + {276, 1167, 23, 21}, + {299, 1167, 23, 21}, + {322, 1167, 23, 21}, + {345, 1167, 23, 21}, + {368, 1167, 23, 21}, + {391, 1167, 23, 21}, + {414, 1167, 23, 21}, + {437, 1167, 23, 21}, + {460, 1167, 23, 21}, + {483, 1167, 23, 21}, + {506, 1167, 23, 21}, + {529, 1167, 23, 21}, + {552, 1167, 23, 21}, + {575, 1167, 23, 21}, + {598, 1167, 23, 21}, + {621, 1167, 23, 21}, + {644, 1167, 23, 21}, + {667, 1167, 23, 21}, + {690, 1167, 23, 21}, + {713, 1167, 23, 21}, + {736, 1167, 23, 21}, + {759, 1167, 23, 21}, + {782, 1167, 23, 21}, + {805, 1167, 23, 21}, + {828, 1167, 23, 21}, + {851, 1167, 23, 21}, + {874, 1167, 23, 21}, + {897, 1167, 23, 21}, + {920, 1167, 23, 21}, + {943, 1167, 23, 21}, + {966, 1167, 23, 21}, + {989, 1167, 23, 21}, + {0, 1188, 23, 21}, + {23, 1188, 23, 21}, + {46, 1188, 23, 21}, + {69, 1188, 23, 21}, + {92, 1188, 23, 21}, + {115, 1188, 23, 21}, + {138, 1188, 23, 21}, + {161, 1188, 23, 21}, + {184, 1188, 23, 21}, + {207, 1188, 23, 21}, + {230, 1188, 23, 21}, + {253, 1188, 23, 21}, + {276, 1188, 23, 21}, + {299, 1188, 23, 21}, + {322, 1188, 23, 21}, + {345, 1188, 23, 21}, + {368, 1188, 23, 21}, + {391, 1188, 23, 21}, + {414, 1188, 23, 21}, + {437, 1188, 23, 21}, + {460, 1188, 23, 21}, + {483, 1188, 23, 21}, + {506, 1188, 23, 21}, + {529, 1188, 23, 21}, + {552, 1188, 23, 21}, + {575, 1188, 23, 21}, + {598, 1188, 23, 21}, + {621, 1188, 23, 21}, + {644, 1188, 23, 21}, + {667, 1188, 23, 21}, + {690, 1188, 23, 21}, + {713, 1188, 23, 21}, + {736, 1188, 23, 21}, + {759, 1188, 23, 21}, + {782, 1188, 23, 21}, + {805, 1188, 23, 21}, + {828, 1188, 23, 21}, + {851, 1188, 23, 21}, + {874, 1188, 23, 21}, + {897, 1188, 23, 21}, + {920, 1188, 23, 21}, + {943, 1188, 23, 21}, + {966, 1188, 23, 21}, + {989, 1188, 23, 21}, + {0, 1209, 23, 21}, + {23, 1209, 23, 21}, + {46, 1209, 23, 21}, + {69, 1209, 23, 21}, + {92, 1209, 23, 21}, + {115, 1209, 23, 21}, + {138, 1209, 23, 21}, + {161, 1209, 23, 21}, + {184, 1209, 23, 21}, + {207, 1209, 23, 21}, + {230, 1209, 23, 21}, + {253, 1209, 23, 21}, + {276, 1209, 23, 21}, + {299, 1209, 23, 21}, + {322, 1209, 23, 21}, + {345, 1209, 23, 21}, + {368, 1209, 23, 21}, + {391, 1209, 23, 21}, + {414, 1209, 23, 21}, + {437, 1209, 23, 21}, + {460, 1209, 20, 21}, + {480, 1209, 20, 21}, + {500, 1209, 20, 21}, + {520, 1209, 20, 21}, + {540, 1209, 20, 21}, + {560, 1209, 23, 21}, + {583, 1209, 23, 21}, + {606, 1209, 23, 21}, + {629, 1209, 20, 21}, + {649, 1209, 20, 21}, + {669, 1209, 20, 21}, + {689, 1209, 23, 21}, + {712, 1209, 23, 21}, + {735, 1209, 23, 21}, + {758, 1209, 23, 21}, + {781, 1209, 23, 21}, + {804, 1209, 20, 21}, + {824, 1209, 20, 21}, + {844, 1209, 20, 21}, + {864, 1209, 20, 21}, + {884, 1209, 20, 21}, + {904, 1209, 20, 21}, + {924, 1209, 20, 21}, + {944, 1209, 23, 21}, + {967, 1209, 23, 21}, + {990, 1209, 23, 21}, + {0, 1230, 23, 21}, + {23, 1230, 23, 21}, + {46, 1230, 23, 21}, + {69, 1230, 23, 21}, + {92, 1230, 23, 21}, + {115, 1230, 23, 21}, + {138, 1230, 20, 21}, + {158, 1230, 20, 21}, + {178, 1230, 20, 21}, + {198, 1230, 20, 21}, + {218, 1230, 20, 21}, + {238, 1230, 20, 21}, + {258, 1230, 20, 21}, + {278, 1230, 20, 21}, + {298, 1230, 20, 21}, + {318, 1230, 20, 21}, + {338, 1230, 20, 21}, + {358, 1230, 20, 21}, + {378, 1230, 20, 21}, + {398, 1230, 20, 21}, + {418, 1230, 20, 21}, + {438, 1230, 20, 21}, + {458, 1230, 20, 21}, + {478, 1230, 20, 21}, + {498, 1230, 20, 21}, + {518, 1230, 20, 21}, + {538, 1230, 20, 21}, + {558, 1230, 20, 21}, + {578, 1230, 20, 21}, + {598, 1230, 20, 21}, + {618, 1230, 20, 21}, + {638, 1230, 23, 21}, + {661, 1230, 23, 21}, + {684, 1230, 23, 21}, + {707, 1230, 23, 21}, + {730, 1230, 23, 21}, + {753, 1230, 23, 21}, + {776, 1230, 23, 21}, + {799, 1230, 20, 21}, + {819, 1230, 20, 21}, + {839, 1230, 20, 21}, + {859, 1230, 20, 21}, + {879, 1230, 20, 21}, + {899, 1230, 20, 21}, + {919, 1230, 20, 21}, + {939, 1230, 23, 21}, + {962, 1230, 23, 21}, + {985, 1230, 23, 21}, + {0, 1251, 23, 21}, + {23, 1251, 23, 21}, + {46, 1251, 23, 21}, + {69, 1251, 23, 21}, + {92, 1251, 23, 21}, + {115, 1251, 23, 21}, + {138, 1251, 20, 21}, + {158, 1251, 20, 21}, + {178, 1251, 20, 21}, + {198, 1251, 23, 21}, + {221, 1251, 23, 21}, + {244, 1251, 23, 21}, + {267, 1251, 23, 21}, + {290, 1251, 23, 21}, + {313, 1251, 23, 21}, + {336, 1251, 23, 21}, + {359, 1251, 23, 21}, + {382, 1251, 23, 21}, + {405, 1251, 23, 21}, + {428, 1251, 23, 21}, + {451, 1251, 23, 21}, + {474, 1251, 23, 21}, + {497, 1251, 20, 21}, + {517, 1251, 20, 21}, + {537, 1251, 20, 21}, + {557, 1251, 20, 21}, + {577, 1251, 20, 21}, + {597, 1251, 20, 21}, + {617, 1251, 20, 21}, + {637, 1251, 23, 21}, + {660, 1251, 23, 21}, + {683, 1251, 23, 21}, + {706, 1251, 23, 21}, + {729, 1251, 23, 21}, + {752, 1251, 23, 21}, + {775, 1251, 23, 21}, + {798, 1251, 23, 21}, + {821, 1251, 23, 21}, + {844, 1251, 23, 21}, + {867, 1251, 23, 21}, + {890, 1251, 23, 21}, + {913, 1251, 23, 21}, + {936, 1251, 23, 21}, + {959, 1251, 23, 21}, + {982, 1251, 23, 21}, + {0, 1272, 23, 21}, + {23, 1272, 23, 21}, + {46, 1272, 23, 21}, + {69, 1272, 23, 21}, + {92, 1272, 23, 21}, + {115, 1272, 23, 21}, + {138, 1272, 23, 21}, + {161, 1272, 23, 21}, + {184, 1272, 23, 21}, + {207, 1272, 23, 21}, + {230, 1272, 23, 21}, + {253, 1272, 23, 21}, + {276, 1272, 23, 21}, + {299, 1272, 23, 21}, + {322, 1272, 23, 21}, + {345, 1272, 23, 21}, + {368, 1272, 23, 21}, + {391, 1272, 23, 21}, + {414, 1272, 23, 21}, + {437, 1272, 23, 21}, + {460, 1272, 23, 21}, + {483, 1272, 23, 21}, + {506, 1272, 23, 21}, + {529, 1272, 23, 21}, + {552, 1272, 23, 21}, + {575, 1272, 23, 21}, + {598, 1272, 23, 21}, + {621, 1272, 23, 21}, + {644, 1272, 23, 21}, + {667, 1272, 23, 21}, + {690, 1272, 23, 21}, + {713, 1272, 23, 21}, + {736, 1272, 23, 21}, + {759, 1272, 23, 21}, + {782, 1272, 23, 21}, + {805, 1272, 23, 21}, + {828, 1272, 23, 21}, + {851, 1272, 23, 21}, + {874, 1272, 23, 21}, + {897, 1272, 23, 21}, + {920, 1272, 23, 21}, + {943, 1272, 23, 21}, + {966, 1272, 23, 21}, + {989, 1272, 23, 21}, + {0, 1293, 23, 21}, + {23, 1293, 23, 21}, + {46, 1293, 23, 21}, + {69, 1293, 23, 21}, + {92, 1293, 23, 21}, + {115, 1293, 23, 21}, + {138, 1293, 23, 21}, + {161, 1293, 23, 21}, + {184, 1293, 23, 21}, + {207, 1293, 23, 21}, + {230, 1293, 23, 21}, + {253, 1293, 23, 21}, + {276, 1293, 23, 21}, + {299, 1293, 23, 21}, + {322, 1293, 23, 21}, + {345, 1293, 23, 21}, + {368, 1293, 23, 21}, + {391, 1293, 23, 21}, + {414, 1293, 23, 21}, + {437, 1293, 23, 21}, + {460, 1293, 23, 21}, + {483, 1293, 23, 21}, + {506, 1293, 23, 21}, + {529, 1293, 23, 21}, + {552, 1293, 23, 21}, + {575, 1293, 23, 21}, + {598, 1293, 23, 21}, + {621, 1293, 23, 21}, + {644, 1293, 23, 21}, + {667, 1293, 23, 21}, + {690, 1293, 23, 21}, + {713, 1293, 23, 21}, + {736, 1293, 23, 21}, + {759, 1293, 23, 21}, + {782, 1293, 23, 21}, + {805, 1293, 23, 21}, + {828, 1293, 23, 21}, + {851, 1293, 23, 21}, + {874, 1293, 23, 21}, + {897, 1293, 23, 21}, + {920, 1293, 23, 21}, + {943, 1293, 23, 21}, + {966, 1293, 23, 21}, + {989, 1293, 23, 21}, + {0, 1314, 23, 21}, + {23, 1314, 23, 21}, + {46, 1314, 23, 21}, + {69, 1314, 23, 21}, + {92, 1314, 23, 21}, + {115, 1314, 23, 21}, + {138, 1314, 23, 21}, + {161, 1314, 23, 21}, + {184, 1314, 23, 21}, + {207, 1314, 23, 21}, + {230, 1314, 23, 21}, + {253, 1314, 23, 21}, + {276, 1314, 23, 21}, + {299, 1314, 23, 21}, + {322, 1314, 23, 21}, + {345, 1314, 23, 21}, + {368, 1314, 23, 21}, + {391, 1314, 23, 21}, + {414, 1314, 23, 21}, + {437, 1314, 23, 21}, + {460, 1314, 23, 21}, + {483, 1314, 23, 21}, + {506, 1314, 23, 21}, + {529, 1314, 23, 21}, + {552, 1314, 23, 21}, + {575, 1314, 23, 21}, + {598, 1314, 23, 21}, + {621, 1314, 23, 21}, + {644, 1314, 23, 21}, + {667, 1314, 23, 21}, + {690, 1314, 23, 21}, + {713, 1314, 23, 21}, + {736, 1314, 23, 21}, + {759, 1314, 23, 21}, + {782, 1314, 23, 21}, + {805, 1314, 23, 21}, + {828, 1314, 23, 21}, + {851, 1314, 23, 21}, + {874, 1314, 23, 21}, + {897, 1314, 23, 21}, + {920, 1314, 23, 21}, + {943, 1314, 23, 21}, + {966, 1314, 23, 21}, + {989, 1314, 23, 21}, + {0, 1335, 23, 21}, + {23, 1335, 23, 21}, + {46, 1335, 23, 21}, + {69, 1335, 23, 21}, + {92, 1335, 23, 21} + }; + + bool codepoint_is_emoji(uint32_t codepoint) { + return codepoint >= 0x1F000 && codepoint <= 0x1FB6F; + } + + EmojiRectangle emoji_get_extents(uint32_t codepoint) { + assert(codepoint_is_emoji(codepoint)); + return emoji_extents[codepoint - 0x1F000]; + } +} diff --git a/generated/Emoji.hpp b/generated/Emoji.hpp new file mode 100644 index 0000000..89ebde3 --- /dev/null +++ b/generated/Emoji.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +// This file was automatically generated with generate-emoji-sprite.py, do not edit manually! + +namespace QuickMedia { + struct EmojiRectangle { + int x, y; + int width, height; + }; + + bool codepoint_is_emoji(uint32_t codepoint); + EmojiRectangle emoji_get_extents(uint32_t codepoint); +} \ No newline at end of file diff --git a/images/emoji.png b/images/emoji.png new file mode 100644 index 0000000..8bb210f Binary files /dev/null and b/images/emoji.png differ diff --git a/include/Body.hpp b/include/Body.hpp index 236a02d..43e2946 100644 --- a/include/Body.hpp +++ b/include/Body.hpp @@ -174,7 +174,7 @@ namespace QuickMedia { BodyItem* get_selected() const; std::shared_ptr get_selected_shared(); - // Returns null if not visible item + // Returns null if no visible items. This is the item we can see the end of BodyItem* get_last_fully_visible_item(); void clamp_selection(); @@ -205,6 +205,7 @@ namespace QuickMedia { void set_page_scroll(float scroll) { page_scroll = scroll; } float get_page_scroll() const { return page_scroll; } + // This is the item we can see the end of bool is_last_item_fully_visible() const { return last_item_fully_visible; } bool is_body_full_with_items() const { return items_cut_off; } diff --git a/include/FontLoader.hpp b/include/FontLoader.hpp deleted file mode 100644 index bff0f18..0000000 --- a/include/FontLoader.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -namespace sf { - class Font; -} - -namespace QuickMedia::FontLoader { - enum class FontType { - LATIN, - LATIN_BOLD, - CJK, - EMOJI - }; - - // Note: not thread-safe - sf::Font* get_font(FontType font_type); -} \ No newline at end of file diff --git a/include/ResourceLoader.hpp b/include/ResourceLoader.hpp new file mode 100644 index 0000000..a332ba4 --- /dev/null +++ b/include/ResourceLoader.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace sf { + class Font; + class Texture; +} + +namespace QuickMedia { + void set_resource_loader_root_path(const char *resource_root); +} + +namespace QuickMedia::FontLoader { + enum class FontType { + LATIN, + LATIN_BOLD, + CJK, + EMOJI + }; + + // Note: not thread-safe + sf::Font* get_font(FontType font_type); +} + +namespace QuickMedia::TextureLoader { + // Note: not thread-safe + sf::Texture* get_texture(const char *filepath); +} \ No newline at end of file diff --git a/include/Text.hpp b/include/Text.hpp index f102c59..135a89c 100644 --- a/include/Text.hpp +++ b/include/Text.hpp @@ -139,7 +139,7 @@ namespace QuickMedia sf::String str; // TODO: Remove this for non-editable text??? also replace with std::string? then we get more efficient editing of text const bool bold_font; unsigned int characterSize; - sf::VertexArray vertices[2]; + sf::VertexArray vertices[3]; float maxWidth; sf::Vector2f position; sf::Color color; diff --git a/plugins/Fourchan.hpp b/plugins/Fourchan.hpp index b9e5b74..903d534 100644 --- a/plugins/Fourchan.hpp +++ b/plugins/Fourchan.hpp @@ -14,11 +14,12 @@ namespace QuickMedia { const std::string resources_root; }; - class FourchanThreadListPage : public Page { + class FourchanThreadListPage : public LazyFetchPage { public: - FourchanThreadListPage(Program *program, std::string title, std::string board_id) : Page(program), title(std::move(title)), board_id(std::move(board_id)) {} + FourchanThreadListPage(Program *program, std::string title, std::string board_id) : LazyFetchPage(program), title(std::move(title)), board_id(std::move(board_id)) {} const char* get_title() const override { return title.c_str(); } PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override; + PluginResult lazy_fetch(BodyItems &result_items) override; const std::string title; const std::string board_id; diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 71d9664..8e96c54 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -256,7 +256,7 @@ namespace QuickMedia { MatrixRoomTagsPage *room_tags_page; MatrixInvitesPage *invites_page; private: - void update_room_description(RoomData *room, Messages &new_messages, bool is_initial_sync); + void update_room_description(RoomData *room, Messages &new_messages, bool is_initial_sync, bool sync_is_cache); void update_pending_room_messages(MatrixPageType page_type); private: struct RoomMessagesData { diff --git a/src/Body.cpp b/src/Body.cpp index b456841..5c2a66c 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -1,7 +1,7 @@ #include "../include/Body.hpp" #include "../include/QuickMedia.hpp" #include "../include/Scale.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" #include "../plugins/Plugin.hpp" #include #include diff --git a/src/Entry.cpp b/src/Entry.cpp index cc05aa0..c18006f 100644 --- a/src/Entry.cpp +++ b/src/Entry.cpp @@ -1,5 +1,5 @@ #include "../include/Entry.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" #include #include #include diff --git a/src/FontLoader.cpp b/src/FontLoader.cpp deleted file mode 100644 index ca33377..0000000 --- a/src/FontLoader.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "../include/FontLoader.hpp" -#include -#include -#include - -static std::array, 3> font_cache; - -namespace QuickMedia::FontLoader { - sf::Font* get_font(FontType font_type) { - sf::Font *font = font_cache[(size_t)font_type].get(); - if(!font) { - auto new_font = std::make_unique(); - std::vector noto_directories; - std::string font_file_name; - switch(font_type) { - case FontType::LATIN: { - noto_directories.push_back("/usr/share/fonts/noto"); - noto_directories.push_back("/usr/share/fonts/truetype/noto"); - font_file_name = "NotoSans-Regular.ttf"; - break; - } - case FontType::LATIN_BOLD: { - noto_directories.push_back("/usr/share/fonts/noto"); - noto_directories.push_back("/usr/share/fonts/truetype/noto"); - font_file_name = "NotoSans-Bold.ttf"; - break; - } - case FontType::CJK: { - noto_directories.push_back("/usr/share/fonts/noto-cjk"); - noto_directories.push_back("/usr/share/fonts/truetype/noto-cjk"); - font_file_name = "NotoSansCJK-Regular.ttc"; - break; - } - case FontType::EMOJI: { - noto_directories.push_back("/usr/share/fonts/noto"); - noto_directories.push_back("/usr/share/fonts/truetype/noto"); - font_file_name = "NotoColorEmoji.ttf"; - break; - } - } - - for(const std::string ¬o_dir : noto_directories) { - if(new_font->loadFromFile(noto_dir + "/" + font_file_name)) - break; - } - - font_cache[(size_t)font_type] = std::move(new_font); - font = font_cache[(size_t)font_type].get(); - } - return font; - } -} \ No newline at end of file diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index be03781..8704c15 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -2,7 +2,7 @@ #include "../include/Notification.hpp" #include "../include/Storage.hpp" #include "../include/SfmlFixes.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" #include "../plugins/Manga.hpp" #include #include diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index c9ab3e1..f494d35 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -20,7 +20,7 @@ #include "../include/Entry.hpp" #include "../include/NetUtils.hpp" #include "../include/SfmlFixes.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" #include "../include/AsyncTask.hpp" #include "../external/hash-library/sha256.h" @@ -340,6 +340,8 @@ namespace QuickMedia { resources_root = "../../../"; } + set_resource_loader_root_path(resources_root.c_str()); + if(!circle_mask_shader.loadFromFile(resources_root + "shaders/circle_mask.glsl", sf::Shader::Type::Fragment)) { fprintf(stderr, "Failed to load %s/shaders/circle_mask.glsl", resources_root.c_str()); abort(); diff --git a/src/ResourceLoader.cpp b/src/ResourceLoader.cpp new file mode 100644 index 0000000..9a6060d --- /dev/null +++ b/src/ResourceLoader.cpp @@ -0,0 +1,79 @@ +#include "../include/ResourceLoader.hpp" +#include +#include +#include +#include +#include + +static std::string resource_root; +static std::array, 3> font_cache; +static std::unordered_map> texture_cache; + +namespace QuickMedia { + void set_resource_loader_root_path(const char *new_resource_root) { + resource_root = new_resource_root; + } +} + +namespace QuickMedia::FontLoader { + sf::Font* get_font(FontType font_type) { + sf::Font *font = font_cache[(size_t)font_type].get(); + if(!font) { + auto new_font = std::make_unique(); + std::vector noto_directories; + std::string font_file_name; + switch(font_type) { + case FontType::LATIN: { + noto_directories.push_back("/usr/share/fonts/noto"); + noto_directories.push_back("/usr/share/fonts/truetype/noto"); + font_file_name = "NotoSans-Regular.ttf"; + break; + } + case FontType::LATIN_BOLD: { + noto_directories.push_back("/usr/share/fonts/noto"); + noto_directories.push_back("/usr/share/fonts/truetype/noto"); + font_file_name = "NotoSans-Bold.ttf"; + break; + } + case FontType::CJK: { + noto_directories.push_back("/usr/share/fonts/noto-cjk"); + noto_directories.push_back("/usr/share/fonts/truetype/noto-cjk"); + font_file_name = "NotoSansCJK-Regular.ttc"; + break; + } + case FontType::EMOJI: { + noto_directories.push_back("/usr/share/fonts/noto"); + noto_directories.push_back("/usr/share/fonts/truetype/noto"); + font_file_name = "NotoColorEmoji.ttf"; + break; + } + } + + for(const std::string ¬o_dir : noto_directories) { + if(new_font->loadFromFile(noto_dir + "/" + font_file_name)) + break; + } + + font_cache[(size_t)font_type] = std::move(new_font); + font = font_cache[(size_t)font_type].get(); + } + return font; + } +} + +namespace QuickMedia::TextureLoader { + sf::Texture* get_texture(const char *filepath) { + assert(!resource_root.empty()); + std::string str = filepath; + auto it = texture_cache.find(str); + if(it != texture_cache.end()) + return it->second.get(); + + auto new_texture = std::make_unique(); + sf::Texture *result = new_texture.get(); + if(!new_texture->loadFromFile(resource_root + str)) + fprintf(stderr, "Failed to load image: %s%s\n", resource_root.c_str(), filepath); + texture_cache[str] = std::move(new_texture); + return result; + } +} \ No newline at end of file diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index dea9951..9b02903 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -1,6 +1,6 @@ #include "../include/SearchBar.hpp" #include "../include/Scale.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" #include #include #include diff --git a/src/Text.cpp b/src/Text.cpp index b463f92..539f211 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -1,5 +1,6 @@ #include "../include/Text.hpp" -#include "../include/FontLoader.hpp" +#include "../include/ResourceLoader.hpp" +#include "../generated/Emoji.hpp" #include #include #include @@ -46,6 +47,7 @@ namespace QuickMedia { vertices[0].setPrimitiveType(sf::PrimitiveType::Quads); vertices[1].setPrimitiveType(sf::PrimitiveType::Quads); + vertices[2].setPrimitiveType(sf::PrimitiveType::Quads); setString(std::move(_str)); } @@ -226,9 +228,17 @@ namespace QuickMedia return size; } - static size_t find_end_of_non_cjk(const sf::Uint32 *str, size_t size) { + static size_t find_end_of_emoji(const sf::Uint32 *str, size_t size) { for(size_t i = 0; i < size; ++i) { - if(is_cjk_codepoint(str[i])) + if(!codepoint_is_emoji(str[i])) + return i; + } + return size; + } + + static size_t find_end_of_non_cjk_and_non_emoji(const sf::Uint32 *str, size_t size) { + for(size_t i = 0; i < size; ++i) { + if(is_cjk_codepoint(str[i]) || codepoint_is_emoji(str[i])) return i; } return size; @@ -240,13 +250,18 @@ namespace QuickMedia size_t size = str.getSize(); while(index < size) { size_t offset; - bool is_cjk = is_cjk_codepoint(str[index]); - if(is_cjk) + TextElement::TextType text_type = TextElement::TextType::LATIN; + if(is_cjk_codepoint(str[index])) { + text_type = TextElement::TextType::CJK; offset = find_end_of_cjk(str.getData() + index + 1, size - index - 1); - else - offset = find_end_of_non_cjk(str.getData() + index + 1, size - index - 1); + } else if(codepoint_is_emoji(str[index])) { + text_type = TextElement::TextType::EMOJI; + offset = find_end_of_emoji(str.getData() + index + 1, size - index - 1); + } else { + offset = find_end_of_non_cjk_and_non_emoji(str.getData() + index + 1, size - index - 1); + } textElements.push_back({ StringViewUtf32(str.getData() + index, offset + 1), TextElement::Type::TEXT }); - textElements.back().text_type = is_cjk ? TextElement::TextType::CJK : TextElement::TextType::LATIN; + textElements.back().text_type = text_type; index += 1 + offset; } } @@ -317,6 +332,7 @@ namespace QuickMedia vertices_linear.clear(); vertices[0].clear(); vertices[1].clear(); + vertices[2].clear(); boundingBox = sf::FloatRect(); sf::Font *latin_font; @@ -325,7 +341,8 @@ namespace QuickMedia else latin_font = FontLoader::get_font(FontLoader::FontType::LATIN); - float hspace = latin_font->getGlyph(' ', characterSize, false).advance + characterSpacing; + float latin_font_height = latin_font->getGlyph(' ', characterSize, false).advance; + float hspace = latin_font_height + characterSpacing; float vspace = latin_font->getLineSpacing(characterSize); // TODO: What about japanese font??? sf::Vector2f glyphPos; @@ -338,6 +355,35 @@ namespace QuickMedia if(textElement.text_type == TextElement::TextType::CJK) { ff = FontLoader::get_font(FontLoader::FontType::CJK); vertices_index = 1; + } else if(textElement.text_type == TextElement::TextType::EMOJI) { + vertices_index = 2; + textElement.position = glyphPos; + for(size_t i = 0; i < textElement.text.size; ++i) + { + sf::Uint32 codePoint = textElement.text[i]; + int vertexStart = vertices[vertices_index].getVertexCount(); + EmojiRectangle emoji_rec = emoji_get_extents(codePoint); + + const float font_height_offset = -latin_font_height * 1.0f; + sf::Vector2f vertexTopLeft(glyphPos.x, glyphPos.y + font_height_offset - emoji_rec.height * 0.5f); + sf::Vector2f vertexTopRight(glyphPos.x + emoji_rec.width, glyphPos.y + font_height_offset - emoji_rec.height * 0.5f); + sf::Vector2f vertexBottomLeft(glyphPos.x, glyphPos.y + font_height_offset + emoji_rec.height * 0.5f); + sf::Vector2f vertexBottomRight(glyphPos.x + emoji_rec.width, glyphPos.y + font_height_offset + emoji_rec.height * 0.5f); + + sf::Vector2f textureTopLeft(emoji_rec.x, emoji_rec.y); + sf::Vector2f textureTopRight(emoji_rec.x + emoji_rec.width, emoji_rec.y); + sf::Vector2f textureBottomLeft(emoji_rec.x, emoji_rec.y + emoji_rec.height); + sf::Vector2f textureBottomRight(emoji_rec.x + emoji_rec.width, emoji_rec.y + emoji_rec.height); + + vertices[vertices_index].append({ vertexTopLeft, sf::Color::White, textureTopLeft }); + vertices[vertices_index].append({ vertexTopRight, sf::Color::White, textureTopRight }); + vertices[vertices_index].append({ vertexBottomRight, sf::Color::White, textureBottomRight }); + vertices[vertices_index].append({ vertexBottomLeft, sf::Color::White, textureBottomLeft }); + + glyphPos.x += emoji_rec.width + characterSpacing; + vertices_linear.push_back({vertices_index, vertexStart, 0, codePoint}); + } + continue; } //vertices[vertices_index].resize(vertices[vertices_index].getVertexCount() + 4 * textElement.text.size); // TODO: Precalculate @@ -818,6 +864,13 @@ namespace QuickMedia states.texture = &font->getTexture(characterSize); target.draw(vertices[i], states); } + + if(vertices[2].getVertexCount() > 0) { + sf::RenderStates states; + states.transform.translate(pos); + states.texture = TextureLoader::get_texture("images/emoji.png"); + target.draw(vertices[2], states); + } if(!editable) return true; pos.y -= floor(vspace * 2.0f); diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp index d042a2a..2c62ba1 100644 --- a/src/plugins/Fourchan.cpp +++ b/src/plugins/Fourchan.cpp @@ -135,139 +135,7 @@ namespace QuickMedia { } PluginResult FourchanBoardsPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - Json::Value json_root; - DownloadResult result = download_json(json_root, fourchan_url + url + "/catalog.json", {}, true); - if(result != DownloadResult::OK) return download_result_to_plugin_result(result); - - if(!json_root.isArray()) - return PluginResult::ERR; - - BodyItems result_items; - - for(const Json::Value &page_data : json_root) { - if(!page_data.isObject()) - continue; - - const Json::Value &threads = page_data["threads"]; - if(!threads.isArray()) - continue; - - for(const Json::Value &thread : threads) { - if(!thread.isObject()) - continue; - - const Json::Value &sub = thread["sub"]; - const char *sub_begin = ""; - const char *sub_end = sub_begin; - sub.getString(&sub_begin, &sub_end); - - const Json::Value &com = thread["com"]; - const char *comment_begin = ""; - const char *comment_end = comment_begin; - com.getString(&comment_begin, &comment_end); - - const Json::Value &thread_num = thread["no"]; - if(!thread_num.isNumeric()) - continue; - - std::string title_text; - extract_comment_pieces(sub_begin, sub_end - sub_begin, - [&title_text](const CommentPiece &cp) { - switch(cp.type) { - case CommentPiece::Type::TEXT: - title_text.append(cp.text.data, cp.text.size); - break; - case CommentPiece::Type::QUOTE: - title_text += '>'; - title_text.append(cp.text.data, cp.text.size); - //comment_text += '\n'; - break; - case CommentPiece::Type::QUOTELINK: { - title_text.append(cp.text.data, cp.text.size); - break; - } - case CommentPiece::Type::LINE_CONTINUE: { - if(!title_text.empty() && title_text.back() == '\n') { - title_text.pop_back(); - } - break; - } - } - } - ); - if(!title_text.empty() && title_text.back() == '\n') - title_text.back() = ' '; - html_unescape_sequences(title_text); - - std::string comment_text; - extract_comment_pieces(comment_begin, comment_end - comment_begin, - [&comment_text](const CommentPiece &cp) { - switch(cp.type) { - case CommentPiece::Type::TEXT: - comment_text.append(cp.text.data, cp.text.size); - break; - case CommentPiece::Type::QUOTE: - comment_text += '>'; - comment_text.append(cp.text.data, cp.text.size); - //comment_text += '\n'; - break; - case CommentPiece::Type::QUOTELINK: { - comment_text.append(cp.text.data, cp.text.size); - break; - } - case CommentPiece::Type::LINE_CONTINUE: { - if(!comment_text.empty() && comment_text.back() == '\n') { - comment_text.pop_back(); - } - break; - } - } - } - ); - html_unescape_sequences(comment_text); - // TODO: Do the same when wrapping is implemented - // TODO: Remove this - int num_lines = 0; - for(size_t i = 0; i < comment_text.size(); ++i) { - if(comment_text[i] == '\n') { - ++num_lines; - if(num_lines == 6) { - comment_text = comment_text.substr(0, i) + " (...)"; - break; - } - } - } - auto body_item = BodyItem::create(std::move(comment_text)); - body_item->set_author(std::move(title_text)); - body_item->url = std::to_string(thread_num.asInt64()); - - const Json::Value &ext = thread["ext"]; - const Json::Value &tim = thread["tim"]; - if(tim.isNumeric() && ext.isString()) { - std::string ext_str = ext.asString(); - if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg" || ext_str == ".webm" || ext_str == ".mp4" || ext_str == ".gif") { - } else { - fprintf(stderr, "TODO: Support file extension: %s\n", ext_str.c_str()); - } - // "s" means small, that's the url 4chan uses for thumbnails. - // thumbnails always has .jpg extension even if they are gifs or webm. - body_item->thumbnail_url = fourchan_image_url + url + "/" + std::to_string(tim.asInt64()) + "s.jpg"; - - sf::Vector2i thumbnail_size(64, 64); - const Json::Value &tn_w = thread["tn_w"]; - const Json::Value &tn_h = thread["tn_h"]; - if(tn_w.isNumeric() && tn_h.isNumeric()) - thumbnail_size = sf::Vector2i(tn_w.asInt() * 0.5, tn_h.asInt() * 0.5); - body_item->thumbnail_size = std::move(thumbnail_size); - } - - result_items.push_back(std::move(body_item)); - } - } - - auto body = create_body(); - body->items = std::move(result_items); - result_tabs.push_back(Tab{std::move(body), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + result_tabs.push_back(Tab{create_body(), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } @@ -462,6 +330,138 @@ namespace QuickMedia { return PluginResult::OK; } + PluginResult FourchanThreadListPage::lazy_fetch(BodyItems &result_items) { + Json::Value json_root; + DownloadResult result = download_json(json_root, fourchan_url + board_id + "/catalog.json?s=Index", {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + + if(!json_root.isArray()) + return PluginResult::ERR; + + for(const Json::Value &page_data : json_root) { + if(!page_data.isObject()) + continue; + + const Json::Value &threads = page_data["threads"]; + if(!threads.isArray()) + continue; + + for(const Json::Value &thread : threads) { + if(!thread.isObject()) + continue; + + const Json::Value &sub = thread["sub"]; + const char *sub_begin = ""; + const char *sub_end = sub_begin; + sub.getString(&sub_begin, &sub_end); + + const Json::Value &com = thread["com"]; + const char *comment_begin = ""; + const char *comment_end = comment_begin; + com.getString(&comment_begin, &comment_end); + + const Json::Value &thread_num = thread["no"]; + if(!thread_num.isNumeric()) + continue; + + std::string title_text; + extract_comment_pieces(sub_begin, sub_end - sub_begin, + [&title_text](const CommentPiece &cp) { + switch(cp.type) { + case CommentPiece::Type::TEXT: + title_text.append(cp.text.data, cp.text.size); + break; + case CommentPiece::Type::QUOTE: + title_text += '>'; + title_text.append(cp.text.data, cp.text.size); + //comment_text += '\n'; + break; + case CommentPiece::Type::QUOTELINK: { + title_text.append(cp.text.data, cp.text.size); + break; + } + case CommentPiece::Type::LINE_CONTINUE: { + if(!title_text.empty() && title_text.back() == '\n') { + title_text.pop_back(); + } + break; + } + } + } + ); + if(!title_text.empty() && title_text.back() == '\n') + title_text.back() = ' '; + html_unescape_sequences(title_text); + + std::string comment_text; + extract_comment_pieces(comment_begin, comment_end - comment_begin, + [&comment_text](const CommentPiece &cp) { + switch(cp.type) { + case CommentPiece::Type::TEXT: + comment_text.append(cp.text.data, cp.text.size); + break; + case CommentPiece::Type::QUOTE: + comment_text += '>'; + comment_text.append(cp.text.data, cp.text.size); + //comment_text += '\n'; + break; + case CommentPiece::Type::QUOTELINK: { + comment_text.append(cp.text.data, cp.text.size); + break; + } + case CommentPiece::Type::LINE_CONTINUE: { + if(!comment_text.empty() && comment_text.back() == '\n') { + comment_text.pop_back(); + } + break; + } + } + } + ); + html_unescape_sequences(comment_text); + // TODO: Do the same when wrapping is implemented + // TODO: Remove this + int num_lines = 0; + for(size_t i = 0; i < comment_text.size(); ++i) { + if(comment_text[i] == '\n') { + ++num_lines; + if(num_lines == 6) { + comment_text = comment_text.substr(0, i) + " (...)"; + break; + } + } + } + auto body_item = BodyItem::create(std::move(comment_text)); + body_item->set_author(std::move(title_text)); + body_item->url = std::to_string(thread_num.asInt64()); + + const Json::Value &ext = thread["ext"]; + const Json::Value &tim = thread["tim"]; + if(tim.isNumeric() && ext.isString()) { + std::string ext_str = ext.asString(); + if(ext_str == ".png" || ext_str == ".jpg" || ext_str == ".jpeg" || ext_str == ".webm" || ext_str == ".mp4" || ext_str == ".gif") { + } else { + fprintf(stderr, "TODO: Support file extension: %s\n", ext_str.c_str()); + } + // "s" means small, that's the url 4chan uses for thumbnails. + // thumbnails always has .jpg extension even if they are gifs or webm. + body_item->thumbnail_url = fourchan_image_url + board_id + "/" + std::to_string(tim.asInt64()) + "s.jpg"; + + sf::Vector2i thumbnail_size(64, 64); + const Json::Value &tn_w = thread["tn_w"]; + const Json::Value &tn_h = thread["tn_h"]; + if(tn_w.isNumeric() && tn_h.isNumeric()) + thumbnail_size = sf::Vector2i(tn_w.asInt() * 0.5, tn_h.asInt() * 0.5); + body_item->thumbnail_size = std::move(thumbnail_size); + } + + result_items.push_back(std::move(body_item)); + } + } + + return PluginResult::OK; + } + PluginResult FourchanThreadPage::login(const std::string &token, const std::string &pin, std::string &response_msg) { response_msg.clear(); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 1d0e1df..6dabad9 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -455,7 +455,7 @@ namespace QuickMedia { }); } - void MatrixQuickMedia::update_room_description(RoomData *room, Messages &new_messages, bool is_initial_sync) { + void MatrixQuickMedia::update_room_description(RoomData *room, Messages &new_messages, bool is_initial_sync, bool sync_is_cache) { time_t read_marker_message_timestamp = 0; std::shared_ptr me = matrix->get_me(room); if(me) { @@ -485,7 +485,7 @@ namespace QuickMedia { if(!room_body_item) return; - if(last_unread_message) { + if(last_unread_message && !sync_is_cache) { std::string room_desc = "Unread: " + matrix->message_get_author_displayname(last_unread_message) + ": " + extract_first_line_elipses(last_unread_message->body, 150); int unread_notification_count = room->unread_notification_count; if(unread_notification_count > 0) @@ -523,7 +523,7 @@ namespace QuickMedia { } } - update_room_description(room, messages, is_initial_sync); + update_room_description(room, messages, is_initial_sync, it.second.sync_is_cache); } pending_room_messages.clear(); } -- cgit v1.2.3