Add pdfio
This commit is contained in:
@@ -7,6 +7,58 @@ struct Library {
|
|||||||
Array<S8_String> defines;
|
Array<S8_String> defines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Library PreparePdfio(S8_String zlib_include_path) {
|
||||||
|
Library l = {};
|
||||||
|
l.include_paths.add("../src/external/pdfio");
|
||||||
|
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-aes.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-array.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-common.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-content.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-crypto.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-dict.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-file.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-md5.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-object.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-page.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-rc4.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-sha256.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-stream.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-string.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-token.c");
|
||||||
|
l.sources.add("../src/external/pdfio/pdfio-value.c");
|
||||||
|
l.sources.add("../src/external/pdfio/ttf.c");
|
||||||
|
|
||||||
|
l.objects.add("pdfio-aes.obj");
|
||||||
|
l.objects.add("pdfio-array.obj");
|
||||||
|
l.objects.add("pdfio-common.obj");
|
||||||
|
l.objects.add("pdfio-content.obj");
|
||||||
|
l.objects.add("pdfio-crypto.obj");
|
||||||
|
l.objects.add("pdfio-dict.obj");
|
||||||
|
l.objects.add("pdfio-file.obj");
|
||||||
|
l.objects.add("pdfio-md5.obj");
|
||||||
|
l.objects.add("pdfio-object.obj");
|
||||||
|
l.objects.add("pdfio-page.obj");
|
||||||
|
l.objects.add("pdfio-rc4.obj");
|
||||||
|
l.objects.add("pdfio-sha256.obj");
|
||||||
|
l.objects.add("pdfio-stream.obj");
|
||||||
|
l.objects.add("pdfio-string.obj");
|
||||||
|
l.objects.add("pdfio-token.obj");
|
||||||
|
l.objects.add("pdfio-value.obj");
|
||||||
|
l.objects.add("ttf.obj");
|
||||||
|
|
||||||
|
if (!OS_FileExists(l.objects[0])) {
|
||||||
|
Array<S8_String> cmd = {};
|
||||||
|
cmd.add("cl.exe -c -nologo -Zi -MP -FC ");
|
||||||
|
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
||||||
|
cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(zlib_include_path)));
|
||||||
|
cmd += l.sources;
|
||||||
|
Run(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
Library PrepareZLib() {
|
Library PrepareZLib() {
|
||||||
Library l = {};
|
Library l = {};
|
||||||
|
|
||||||
@@ -43,9 +95,11 @@ Library PrepareZLib() {
|
|||||||
l.objects.add("uncompr.obj");
|
l.objects.add("uncompr.obj");
|
||||||
l.objects.add("zutil.obj");
|
l.objects.add("zutil.obj");
|
||||||
|
|
||||||
|
l.objects.add("Advapi32.lib");
|
||||||
|
|
||||||
if (!OS_FileExists(l.objects[0])) {
|
if (!OS_FileExists(l.objects[0])) {
|
||||||
Array<S8_String> cmd = {};
|
Array<S8_String> cmd = {};
|
||||||
cmd.add("cl.exe -c -nologo -Zi -MP -FC ");
|
cmd.add("cl.exe -c -nologo -Zi -MP -FC -O2 ");
|
||||||
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
||||||
cmd += l.sources;
|
cmd += l.sources;
|
||||||
Run(cmd);
|
Run(cmd);
|
||||||
@@ -76,7 +130,7 @@ Library PrepareIMGUI(S8_String sdl_inc_path) {
|
|||||||
|
|
||||||
if (!OS_FileExists(l.objects[0])) {
|
if (!OS_FileExists(l.objects[0])) {
|
||||||
Array<S8_String> cmd = {};
|
Array<S8_String> cmd = {};
|
||||||
cmd.add("cl.exe -c -nologo -Zi -MP -FC ");
|
cmd.add("cl.exe -c -nologo -Zi -MP -FC -O2 ");
|
||||||
cmd.add(Fmt("-I %.*s", S8_Expand(sdl_inc_path)));
|
cmd.add(Fmt("-I %.*s", S8_Expand(sdl_inc_path)));
|
||||||
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
||||||
cmd += l.sources;
|
cmd += l.sources;
|
||||||
@@ -103,7 +157,7 @@ Library PrepareGlad() {
|
|||||||
l.objects.add("glad.obj");
|
l.objects.add("glad.obj");
|
||||||
if (!OS_FileExists(l.objects[0])) {
|
if (!OS_FileExists(l.objects[0])) {
|
||||||
Array<S8_String> cmd = {};
|
Array<S8_String> cmd = {};
|
||||||
cmd.add("cl.exe -c -nologo -Zi -MP -FC ");
|
cmd.add("cl.exe -c -nologo -Zi -MP -FC -O2 ");
|
||||||
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
For(l.include_paths) cmd.add(S8_Format(Perm, "-I %.*s ", S8_Expand(it)));
|
||||||
cmd += l.sources;
|
cmd += l.sources;
|
||||||
Run(cmd);
|
Run(cmd);
|
||||||
@@ -135,6 +189,8 @@ int main() {
|
|||||||
|
|
||||||
Array<Library> libs = {};
|
Array<Library> libs = {};
|
||||||
libs.add(PrepareSDL());
|
libs.add(PrepareSDL());
|
||||||
|
libs.add(PrepareZLib());
|
||||||
|
libs.add(PreparePdfio(libs[1].include_paths[0]));
|
||||||
libs.add(PrepareGlad());
|
libs.add(PrepareGlad());
|
||||||
libs.add(PrepareIMGUI(libs[0].include_paths[0]));
|
libs.add(PrepareIMGUI(libs[0].include_paths[0]));
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
/*
|
||||||
|
@todo: pdf files
|
||||||
|
@todo: config with preload_files, initial_query, style
|
||||||
|
@todo: help menu and config menu
|
||||||
|
|
||||||
|
@todo: check for number of cores before creating threads
|
||||||
|
@todo:
|
||||||
|
*/
|
||||||
|
|
||||||
#define BASIC_IMPL
|
#define BASIC_IMPL
|
||||||
#include "../basic/basic.h"
|
#include "../basic/basic.h"
|
||||||
#include "../basic/filesystem.h"
|
#include "../basic/filesystem.h"
|
||||||
@@ -18,6 +27,66 @@ WorkQueue MainWorkQueue;
|
|||||||
#include "loading_thread.cpp"
|
#include "loading_thread.cpp"
|
||||||
#include "searching_thread.cpp"
|
#include "searching_thread.cpp"
|
||||||
|
|
||||||
|
#include <pdfio.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
extern "C" void OutputDebugStringA(const char *);
|
||||||
|
void Printf(const char *string, ...) {
|
||||||
|
Scratch scratch;
|
||||||
|
STRING_FORMAT(scratch, string, result);
|
||||||
|
OutputDebugStringA(result.data);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define Printf(...) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void TestPdfio() {
|
||||||
|
const char *filename = "C:/Users/Karol/Desktop/Hegels-Logic.pdf";
|
||||||
|
pdfio_file_t *file = pdfioFileOpen(filename, NULL, NULL, NULL, NULL);
|
||||||
|
Assert(file);
|
||||||
|
defer { pdfioFileClose(file); };
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
size_t page_count = pdfioFileGetNumPages(file);
|
||||||
|
Printf("%s: %u pages\n", filename, (unsigned)page_count);
|
||||||
|
for (size_t page_i = 0; page_i < page_count; page_i += 1) {
|
||||||
|
pdfio_obj_t *obj = pdfioFileGetPage(file, page_i);
|
||||||
|
if (obj == NULL) continue;
|
||||||
|
|
||||||
|
if (page_i > 110) __debugbreak();
|
||||||
|
|
||||||
|
size_t num_streams = pdfioPageGetNumStreams(obj);
|
||||||
|
Printf("%s: page%u=%p, num_streams=%u\n", filename, (unsigned)page_i, obj, (unsigned)num_streams);
|
||||||
|
for (size_t stream_i = 0; stream_i < num_streams; stream_i += 1) {
|
||||||
|
pdfio_stream_t *st = pdfioPageOpenStream(obj, stream_i, true);
|
||||||
|
if (st == NULL) continue;
|
||||||
|
Printf("%s: page%u st%u=%p\n", filename, (unsigned)page_i, (unsigned)stream_i, st);
|
||||||
|
defer { pdfioStreamClose(st); };
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
while (pdfioStreamGetToken(st, buffer, sizeof(buffer))) {
|
||||||
|
if (buffer[0] == '(') {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
Printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Printf("%s", buffer + 1);
|
||||||
|
} else if (!strcmp(buffer, "Td") || !strcmp(buffer, "TD") || !strcmp(buffer, "T*") || !strcmp(buffer, "\'") || !strcmp(buffer, "\"")) {
|
||||||
|
Printf("\n");
|
||||||
|
first = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first) {
|
||||||
|
Printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__debugbreak();
|
||||||
|
}
|
||||||
|
|
||||||
void UISearchResults(Array<String> filenames) {
|
void UISearchResults(Array<String> filenames) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Array<String> matches = LockSearchResults();
|
Array<String> matches = LockSearchResults();
|
||||||
@@ -106,6 +175,9 @@ int main(int, char **) {
|
|||||||
InitScratch();
|
InitScratch();
|
||||||
InitArena(&Perm);
|
InitArena(&Perm);
|
||||||
|
|
||||||
|
// TestPdfio();
|
||||||
|
// return 0;
|
||||||
|
|
||||||
XInitLoading();
|
XInitLoading();
|
||||||
InitSearch();
|
InitSearch();
|
||||||
ThreadStartupInfo infos[16] = {};
|
ThreadStartupInfo infos[16] = {};
|
||||||
@@ -131,7 +203,7 @@ int main(int, char **) {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
SDL_Window *window = SDL_CreateWindow("Transcript browser", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
|
SDL_Window *window = SDL_CreateWindow("Transcript browser", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 600, window_flags);
|
||||||
if (window == nullptr) {
|
if (window == nullptr) {
|
||||||
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
|
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
|
||||||
return -1;
|
return -1;
|
||||||
@@ -141,7 +213,6 @@ int main(int, char **) {
|
|||||||
SDL_GL_MakeCurrent(window, gl_context);
|
SDL_GL_MakeCurrent(window, gl_context);
|
||||||
|
|
||||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||||
Assert(0);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +235,6 @@ int main(int, char **) {
|
|||||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||||
io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
|
io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
|
||||||
|
|
||||||
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
|
||||||
|
|
||||||
bool show_loaded_files = false;
|
bool show_loaded_files = false;
|
||||||
bool set_focus_to_input = true;
|
bool set_focus_to_input = true;
|
||||||
int64_t frame = -1;
|
int64_t frame = -1;
|
||||||
@@ -189,43 +258,61 @@ int main(int, char **) {
|
|||||||
#endif
|
#endif
|
||||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
if (event.type == SDL_KEYDOWN) {
|
if (event.type == SDL_KEYDOWN) {
|
||||||
if (event.key.keysym.sym == SDLK_RETURN) {
|
switch (event.key.keysym.sym) {
|
||||||
enter_press = true;
|
case SDLK_UP:
|
||||||
} else if (event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_DOWN) {
|
case SDLK_DOWN:
|
||||||
|
case SDLK_PAGEUP:
|
||||||
|
case SDLK_PAGEDOWN:
|
||||||
set_focus_to_list = true;
|
set_focus_to_list = true;
|
||||||
} else if (event.key.keysym.sym == SDLK_BACKSPACE) {
|
break;
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
case SDLK_DELETE:
|
||||||
set_focus_to_input = true;
|
set_focus_to_input = true;
|
||||||
} else if (event.key.keysym.sym == SDLK_TAB) {
|
case SDLK_RETURN:
|
||||||
|
enter_press = true;
|
||||||
|
break;
|
||||||
|
case SDLK_TAB:
|
||||||
tab_press = true;
|
tab_press = true;
|
||||||
} else if (event.key.keysym.sym == SDLK_F1) {
|
break;
|
||||||
|
case SDLK_F1:
|
||||||
f1_press = true;
|
f1_press = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (event.type == SDL_KEYUP) {
|
|
||||||
|
|
||||||
} else if (event.type == SDL_TEXTINPUT) {
|
} else if (event.type == SDL_TEXTINPUT) {
|
||||||
set_focus_to_input = true;
|
set_focus_to_input = true;
|
||||||
|
} else if (event.type == SDL_QUIT) {
|
||||||
|
done = true;
|
||||||
|
} else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) {
|
||||||
|
done = true;
|
||||||
}
|
}
|
||||||
if (event.type == SDL_QUIT)
|
|
||||||
done = true;
|
|
||||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
|
|
||||||
done = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ImGui::ShowDemoWindow();
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
|
|
||||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse;
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse;
|
||||||
const ImGuiViewport *main_viewport = ImGui::GetMainViewport();
|
const ImGuiViewport *main_viewport = ImGui::GetMainViewport();
|
||||||
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowSize(ImVec2(main_viewport->Size.x, 20), ImGuiCond_Always);
|
ImGui::SetNextWindowSize(ImVec2(main_viewport->Size.x, 40), ImGuiCond_Always);
|
||||||
|
|
||||||
ImGui::Begin("input", NULL, window_flags);
|
ImGui::Begin("input", NULL, window_flags);
|
||||||
if (ImGui::Button("Show loaded files") || f1_press) {
|
|
||||||
show_loaded_files = !show_loaded_files;
|
if (show_loaded_files) {
|
||||||
|
if (ImGui::Button("Show search results (F1)") || f1_press) {
|
||||||
|
show_loaded_files = !show_loaded_files;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::Button("Show loaded files (F1)") || f1_press) {
|
||||||
|
show_loaded_files = !show_loaded_files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (set_focus_to_input) ImGui::SetKeyboardFocusHere(0);
|
if (set_focus_to_input) ImGui::SetKeyboardFocusHere(0);
|
||||||
if (tab_press && ImGui::IsWindowFocused()) set_focus_to_list = true;
|
if (tab_press && ImGui::IsWindowFocused()) set_focus_to_list = true;
|
||||||
@@ -247,8 +334,8 @@ int main(int, char **) {
|
|||||||
{
|
{
|
||||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse;
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse;
|
||||||
const ImGuiViewport *main_viewport = ImGui::GetMainViewport();
|
const ImGuiViewport *main_viewport = ImGui::GetMainViewport();
|
||||||
ImGui::SetNextWindowPos(ImVec2(0, 30), ImGuiCond_Always);
|
ImGui::SetNextWindowPos(ImVec2(0, 35), ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowSize(ImVec2(main_viewport->Size.x, main_viewport->Size.y - 30), ImGuiCond_Always);
|
ImGui::SetNextWindowSize(ImVec2(main_viewport->Size.x, main_viewport->Size.y - 35), ImGuiCond_Always);
|
||||||
|
|
||||||
ImGui::Begin("result", NULL, window_flags);
|
ImGui::Begin("result", NULL, window_flags);
|
||||||
if (!ImGui::IsWindowFocused() && set_focus_to_list) ImGui::SetKeyboardFocusHere(0);
|
if (!ImGui::IsWindowFocused() && set_focus_to_list) ImGui::SetKeyboardFocusHere(0);
|
||||||
@@ -259,11 +346,11 @@ int main(int, char **) {
|
|||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Rendering
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||||
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
glClearColor(1, 1, 1, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ WORK_FUNCTION(SearchForMatchesWork) {
|
|||||||
int64_t index = 0;
|
int64_t index = 0;
|
||||||
while (Seek(buffer, find, &index, SeekFlag_IgnoreCase)) {
|
while (Seek(buffer, find, &index, SeekFlag_IgnoreCase)) {
|
||||||
String found = {buffer.data + index, find.len};
|
String found = {buffer.data + index, find.len};
|
||||||
|
if (search_thread_stop_searching != SearchThreadStopSearching) break;
|
||||||
Matches.bounded_add(found);
|
Matches.bounded_add(found);
|
||||||
buffer = buffer.skip(index + find.len);
|
buffer = buffer.skip(index + find.len);
|
||||||
if (search_thread_stop_searching != SearchThreadStopSearching) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user