From ef79bbde537d6b9c745a7d86cb9df1d04c35590d Mon Sep 17 00:00:00 2001 From: PCSX* teams Date: Tue, 16 Nov 2010 14:15:22 +0200 Subject: pcsxr-1.9.92 --- gui/AboutDlg.c | 109 +++++ gui/AboutDlg.h | 24 + gui/Cheat.c | 1176 ++++++++++++++++++++++++++++++++++++++++++++++ gui/Cheat.h | 25 + gui/ConfDlg.c | 889 +++++++++++++++++++++++++++++++++++ gui/ConfDlg.h | 50 ++ gui/Config.c | 180 +++++++ gui/DebugMemory.c | 312 +++++++++++++ gui/DebugMemory.h | 24 + gui/Gtk2Gui.c | 944 +++++++++++++++++++++++++++++++++++++ gui/Linux.h | 67 +++ gui/LnxMain.c | 568 ++++++++++++++++++++++ gui/Makefile.am | 24 + gui/Makefile.in | 538 +++++++++++++++++++++ gui/MemcardDlg.c | 755 ++++++++++++++++++++++++++++++ gui/MemcardDlg.h | 24 + gui/Plugin.c | 390 ++++++++++++++++ gui/nopic.h | 1345 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 18 files changed, 7444 insertions(+) create mode 100644 gui/AboutDlg.c create mode 100644 gui/AboutDlg.h create mode 100644 gui/Cheat.c create mode 100644 gui/Cheat.h create mode 100644 gui/ConfDlg.c create mode 100644 gui/ConfDlg.h create mode 100644 gui/Config.c create mode 100644 gui/DebugMemory.c create mode 100644 gui/DebugMemory.h create mode 100644 gui/Gtk2Gui.c create mode 100644 gui/Linux.h create mode 100644 gui/LnxMain.c create mode 100644 gui/Makefile.am create mode 100644 gui/Makefile.in create mode 100644 gui/MemcardDlg.c create mode 100644 gui/MemcardDlg.h create mode 100644 gui/Plugin.c create mode 100644 gui/nopic.h (limited to 'gui') diff --git a/gui/AboutDlg.c b/gui/AboutDlg.c new file mode 100644 index 0000000..88979cf --- /dev/null +++ b/gui/AboutDlg.c @@ -0,0 +1,109 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include "Linux.h" +#include + +#if GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 12 +#define gtk_about_dialog_set_program_name gtk_about_dialog_set_name +#endif + +#define ABOUT_VERSION "1.9.92" + +void RunAboutDialog(void) { + GtkWidget *AboutDlg; + + const gchar *authors[] = { + "PCSX-Reloaded Team:", + "edgbla ", + "Wei Mingzhi ", + "", + "Contributors:", + "Dario", + "Firnis", + "Gabriele Gorla", + "Peter Collingbourne", + "shalma", + "Tristin Celestin", + "(See the included AUTHORS file for more details.)", + "", + "PCSX-df Team:", + "Ryan Schultz ", + "Andrew Burton ", + "Stephen Chao ", + "Stefan Sikora ", + "", + "PCSX Team:", + "Linuzappz ", + "Shadow", + "Pete Bernert", + "NoComp", + "Nik3d", + NULL + }; + + const gchar *artists[] = { + "Ryan Schultz ", + "", + "Icon Design:", + "Romain Lafourcade", + NULL + }; + + const gchar *documenters[] = { + "Ryan Schultz ", + NULL + }; + + const gchar *copyright = N_( + "(C) 1999-2003 PCSX Team\n" + "(C) 2005-2009 PCSX-df Team\n" + "(C) 2009-2010 PCSX-Reloaded Team"); + + const gchar *license = N_( + "This program is free software; you can redistribute it and/or modify " + "it under the terms of the GNU General Public License as published by " + "the Free Software Foundation; either version 2 of the License, or " + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful, " + "but WITHOUT ANY WARRANTY; without even the implied warranty of " + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License " + "along with this program; if not, write to the Free Software " + "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA."); + + AboutDlg = gtk_about_dialog_new(); + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(AboutDlg), "PCSX-Reloaded"); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(AboutDlg), ABOUT_VERSION); + gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(AboutDlg), "http://pcsxr.codeplex.com/"); + gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(AboutDlg), "http://pcsxr.codeplex.com/"); + gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(AboutDlg), authors); + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(AboutDlg), _(copyright)); + gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(AboutDlg), documenters); + gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(AboutDlg), artists); + gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(AboutDlg), _("translator-credits")); + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG (AboutDlg), _("A PlayStation emulator.")); + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(AboutDlg), _(license)); + gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(AboutDlg), TRUE); + + gtk_dialog_run(GTK_DIALOG(AboutDlg)); + gtk_widget_destroy(AboutDlg); +} diff --git a/gui/AboutDlg.h b/gui/AboutDlg.h new file mode 100644 index 0000000..e8b82af --- /dev/null +++ b/gui/AboutDlg.h @@ -0,0 +1,24 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef ABOUTDLG_H +#define ABOUTDLG_H + +void RunAboutDialog(void); + +#endif diff --git a/gui/Cheat.c b/gui/Cheat.c new file mode 100644 index 0000000..4047e2f --- /dev/null +++ b/gui/Cheat.c @@ -0,0 +1,1176 @@ +/* Cheat Support for PCSX-Reloaded + * Copyright (C) 2009, Wei Mingzhi . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "Linux.h" + +#include "../libpcsxcore/cheat.h" +#include "../libpcsxcore/psxmem.h" + +GtkWidget *CheatListDlg = NULL; +GtkWidget *CheatSearchDlg = NULL; + +static void LoadCheatListItems(int index) { + GtkListStore *store = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING); + GtkTreeIter iter; + GtkWidget *widget; + GladeXML *xml; + + int i; + + xml = glade_get_widget_tree(CheatListDlg); + widget = glade_xml_get_widget(xml, "GtkCList_Cheat"); + + for (i = 0; i < NumCheats; i++) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, Cheats[i].Enabled, 1, Cheats[i].Descr, -1); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(widget), TRUE); + gtk_widget_show(widget); + + if (index >= NumCheats) { + index = NumCheats - 1; + } + + if (index >= 0) { + GtkTreePath *path; + GtkTreeSelection *sel; + + path = gtk_tree_path_new_from_indices(index, -1); + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + + gtk_tree_selection_select_path(sel, path); + gtk_tree_path_free(path); + } +} + +static void CheatList_TreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) { + GladeXML *xml; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + + gboolean selected; + int i; + + selected = gtk_tree_selection_get_selected(selection, &model, &iter); + + if (selected) { + path = gtk_tree_model_get_path(model, &iter); + i = *gtk_tree_path_get_indices(path); + gtk_tree_path_free(path); + + // If a row was selected, and the row is not blank, we can now enable + // some of the disabled widgets + xml = glade_get_widget_tree(CheatListDlg); + + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "editbutton1")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "delbutton1")), TRUE); + } else { + xml = glade_get_widget_tree(CheatListDlg); + + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "editbutton1")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "delbutton1")), FALSE); + } + + gtk_widget_set_sensitive (GTK_WIDGET(glade_xml_get_widget(xml, "savebutton1")), NumCheats); +} + +static void OnCheatListDlg_AddClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *dlg; + GtkWidget *box, *scroll, *label, *descr_edit, *code_edit; + + dlg = gtk_dialog_new_with_buttons(_("Add New Cheat"), GTK_WINDOW(CheatListDlg), + GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + + gtk_window_set_default_size(GTK_WINDOW(dlg), 350, 350); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + + label = gtk_label_new(_("Cheat Description:")); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + descr_edit = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 5); + gtk_widget_show(descr_edit); + + label = gtk_label_new(_("Cheat Code:")); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + code_edit = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(code_edit), GTK_WRAP_CHAR); + + scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), code_edit); + gtk_widget_show(code_edit); + + gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 5); + gtk_widget_show(scroll); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit)); + GtkTextIter s, e; + char *codetext; + + gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(b), &s, &e); + codetext = strdup(gtk_text_buffer_get_text(GTK_TEXT_BUFFER(b), &s, &e, FALSE)); + + if (AddCheat(gtk_entry_get_text(GTK_ENTRY(descr_edit)), codetext) != 0) { + SysErrorMessage(_("Error"), _("Invalid cheat code!")); + } + + LoadCheatListItems(NumCheats - 1); + + free(codetext); + } + + gtk_widget_destroy(dlg); +} + +static void OnCheatListDlg_EditClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *dlg; + GtkWidget *box, *scroll, *label, *descr_edit, *code_edit; + GladeXML *xml; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + + gboolean selected; + int index, i; + char buf[8192]; + char *p = buf; + + xml = glade_get_widget_tree(CheatListDlg); + widget = glade_xml_get_widget(xml, "GtkCList_Cheat"); + + selected = gtk_tree_selection_get_selected( + gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), + &model, &iter); + + if (!selected) { + return; + } + + path = gtk_tree_model_get_path(model, &iter); + index = *gtk_tree_path_get_indices(path); + gtk_tree_path_free(path); + + dlg = gtk_dialog_new_with_buttons(_("Edit Cheat"), GTK_WINDOW(CheatListDlg), + GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + + gtk_window_set_default_size(GTK_WINDOW(dlg), 350, 350); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + + label = gtk_label_new(_("Cheat Description:")); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + descr_edit = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(descr_edit), Cheats[index].Descr); + gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 5); + gtk_widget_show(descr_edit); + + label = gtk_label_new(_("Cheat Code:")); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + code_edit = gtk_text_view_new(); + + for (i = Cheats[index].First; i < Cheats[index].First + Cheats[index].n; i++) { + sprintf(p, "%.8X %.4X\n", CheatCodes[i].Addr, CheatCodes[i].Val); + p += 14; + *p = '\0'; + } + + gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit)), + buf, -1); + + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(code_edit), GTK_WRAP_CHAR); + + scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), code_edit); + gtk_widget_show(code_edit); + + gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 5); + gtk_widget_show(scroll); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit)); + GtkTextIter s, e; + char *codetext; + + gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(b), &s, &e); + codetext = strdup(gtk_text_buffer_get_text(GTK_TEXT_BUFFER(b), &s, &e, FALSE)); + + if (EditCheat(index, gtk_entry_get_text(GTK_ENTRY(descr_edit)), codetext) != 0) { + SysErrorMessage(_("Error"), _("Invalid cheat code!")); + } + + LoadCheatListItems(index); + + free(codetext); + } + + gtk_widget_destroy(dlg); +} + +static void OnCheatListDlg_DelClicked(GtkWidget *widget, gpointer user_data) { + GladeXML *xml; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + + gboolean selected; + int i = -1; + + xml = glade_get_widget_tree(CheatListDlg); + widget = glade_xml_get_widget(xml, "GtkCList_Cheat"); + + selected = gtk_tree_selection_get_selected( + gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), + &model, &iter); + + if (selected) { + path = gtk_tree_model_get_path(model, &iter); + i = *gtk_tree_path_get_indices(path); + gtk_tree_path_free(path); + + RemoveCheat(i); + } + + LoadCheatListItems(i); // FIXME: should remove it from the list directly + // rather than regenerating the whole list +} + +static void OnCheatListDlg_EnableToggled(GtkWidget *widget, gchar *path, gpointer user_data) { + int i = atoi(path); + + assert(i >= 0 && i < NumCheats); + Cheats[i].Enabled ^= 1; + + LoadCheatListItems(i); // FIXME: should modify it in the list directly + // rather than regenerating the whole list +} + +static void OnCheatListDlg_OpenClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *chooser; + gchar *filename; + + GtkFileFilter *filter; + + chooser = gtk_file_chooser_dialog_new (_("Open Cheat File"), + NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + filename = g_build_filename(getenv("HOME"), CHEATS_DIR, NULL); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), filename); + g_free(filename); + + filter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filter, "*.cht"); + gtk_file_filter_set_name (filter, _("PCSX Cheat Code Files (*.cht)")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filter, "*"); + gtk_file_filter_set_name (filter, _("All Files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter); + + if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); + gtk_widget_destroy (GTK_WIDGET (chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + } else { + gtk_widget_destroy (GTK_WIDGET (chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + return; + } + + LoadCheats(filename); + + g_free(filename); + + LoadCheatListItems(-1); +} + +static void OnCheatListDlg_SaveClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *chooser; + gchar *filename; + GtkFileFilter *filter; + + chooser = gtk_file_chooser_dialog_new(_("Save Cheat File"), + NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + filename = g_build_filename(getenv("HOME"), CHEATS_DIR, NULL); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), filename); + g_free(filename); + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.cht"); + gtk_file_filter_set_name(filter, _("PCSX Cheat Code Files (*.cht)")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + + filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_filter_set_name(filter, _("All Files (*.*)")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); + gtk_widget_destroy (GTK_WIDGET(chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + } else { + gtk_widget_destroy (GTK_WIDGET(chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + return; + } + + SaveCheats(filename); + + g_free(filename); +} + +static void OnCheatListDlg_CloseClicked() { + gtk_widget_destroy(CheatListDlg); + CheatListDlg = NULL; +} + +// run the cheat list dialog +void RunCheatListDialog() { + GladeXML *xml; + GtkWidget *widget; + GtkTreeSelection *treesel; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "CheatListDlg", NULL); + if (!xml) { + g_warning(_("Error: Glade interface could not be loaded!")); + return; + } + + CheatListDlg = glade_xml_get_widget(xml, "CheatListDlg"); + gtk_window_set_title(GTK_WINDOW(CheatListDlg), _("Cheat Codes")); + + widget = glade_xml_get_widget(xml, "GtkCList_Cheat"); + + // column for enable + renderer = gtk_cell_renderer_toggle_new(); + column = gtk_tree_view_column_new_with_attributes(_("Enable"), + renderer, "active", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + + g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(OnCheatListDlg_EnableToggled), 0); + + // column for description + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Description"), + renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + + LoadCheatListItems(-1); + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + gtk_tree_selection_set_mode(treesel, GTK_SELECTION_SINGLE); + g_signal_connect_data(G_OBJECT (treesel), "changed", + G_CALLBACK (CheatList_TreeSelectionChanged), + NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "addbutton1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatListDlg_AddClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "editbutton1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatListDlg_EditClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "delbutton1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatListDlg_DelClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "loadbutton1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatListDlg_OpenClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "savebutton1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatListDlg_SaveClicked), xml, NULL, G_CONNECT_AFTER); + + // Setup a handler for when Close or Cancel is clicked + g_signal_connect_data(GTK_OBJECT(CheatListDlg), "response", + GTK_SIGNAL_FUNC(OnCheatListDlg_CloseClicked), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); + + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "savebutton1")), NumCheats); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "editbutton1")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "delbutton1")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "editbutton1")), FALSE); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define SEARCH_EQUALVAL 0 +#define SEARCH_NOTEQUALVAL 1 +#define SEARCH_RANGE 2 +#define SEARCH_INCBY 3 +#define SEARCH_DECBY 4 +#define SEARCH_INC 5 +#define SEARCH_DEC 6 +#define SEARCH_DIFFERENT 7 +#define SEARCH_NOCHANGE 8 + +#define SEARCHTYPE_8BIT 0 +#define SEARCHTYPE_16BIT 1 +#define SEARCHTYPE_32BIT 2 + +#define SEARCHBASE_DEC 0 +#define SEARCHBASE_HEX 1 + +static char current_search = SEARCH_EQUALVAL; +static char current_searchtype = SEARCHTYPE_8BIT; +static char current_searchbase = SEARCHBASE_DEC; +static uint32_t current_valuefrom = 0; +static uint32_t current_valueto = 0; + +// update the cheat search dialog +static void UpdateCheatSearchDialog() { + GladeXML *xml; + char buf[256]; + int i; + u32 addr; + GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING); + GtkTreeIter iter; + GtkWidget *widget; + + xml = glade_get_widget_tree(CheatSearchDlg); + widget = glade_xml_get_widget(xml, "GtkCList_Result"); + + gtk_combo_box_set_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_searchfor")), current_search); + gtk_combo_box_set_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_datatype")), current_searchtype); + gtk_combo_box_set_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_database")), current_searchbase); + + if (current_searchbase == SEARCHBASE_DEC) { + sprintf(buf, "%u", current_valuefrom); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value")), buf); + sprintf(buf, "%u", current_valueto); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto")), buf); + } + else { + sprintf(buf, "%X", current_valuefrom); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value")), buf); + sprintf(buf, "%X", current_valueto); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto")), buf); + } + + if (current_search == SEARCH_RANGE) { + gtk_widget_show(GTK_WIDGET(glade_xml_get_widget(xml, "label_valueto"))); + gtk_widget_show(GTK_WIDGET(glade_xml_get_widget(xml, "entry_valueto"))); + } + else { + gtk_widget_hide(GTK_WIDGET(glade_xml_get_widget(xml, "label_valueto"))); + gtk_widget_hide(GTK_WIDGET(glade_xml_get_widget(xml, "entry_valueto"))); + } + + if (current_search >= SEARCH_INC) { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "entry_value")), FALSE); + } + else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "entry_value")), TRUE); + } + + if (current_search >= SEARCH_INCBY && prevM == NULL) { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_start")), FALSE); + } + else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_start")), TRUE); + } + + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_freeze")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_modify")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_copy")), FALSE); + + if (prevM != NULL) { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "combo_datatype")), FALSE); + + if (NumSearchResults > 100) { + // too many results to be shown + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, _("Too many addresses found."), -1); + gtk_widget_set_sensitive(widget, FALSE); + } + else { + for (i = 0; i < NumSearchResults; i++) { + addr = SearchResults[i]; + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + sprintf(buf, _("%.8X Current: %u (%.2X), Previous: %u (%.2X)"), + addr, PSXMu8(addr), PSXMu8(addr), PrevMu8(addr), PrevMu8(addr)); + break; + + case SEARCHTYPE_16BIT: + sprintf(buf, _("%.8X Current: %u (%.4X), Previous: %u (%.4X)"), + addr, PSXMu16(addr), PSXMu16(addr), PrevMu16(addr), PrevMu16(addr)); + break; + + case SEARCHTYPE_32BIT: + sprintf(buf, _("%.8X Current: %u (%.8X), Previous: %u (%.8X)"), + addr, PSXMu32(addr), PSXMu32(addr), PrevMu32(addr), PrevMu32(addr)); + break; + + default: + assert(FALSE); // impossible + break; + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, buf, -1); + } + gtk_widget_set_sensitive(widget, TRUE); + } + + sprintf(buf, _("Founded Addresses: %d"), NumSearchResults); + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml, "label_resultsfound")), buf); + } + else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "combo_datatype")), TRUE); + gtk_widget_set_sensitive(widget, FALSE); + + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml, "label_resultsfound")), + _("Enter the values and start your search.")); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(widget), TRUE); + gtk_widget_show(widget); +} + +// get the current selected result index in the list +static int GetSelectedResultIndex() { + GladeXML *xml; + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gboolean selected; + int i; + + xml = glade_get_widget_tree(CheatSearchDlg); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(glade_xml_get_widget(xml, "GtkCList_Result"))); + selected = gtk_tree_selection_get_selected(selection, &model, &iter); + + if (!selected) { + return -1; + } + + path = gtk_tree_model_get_path(model, &iter); + i = *gtk_tree_path_get_indices(path); + gtk_tree_path_free(path); + + assert(i < NumSearchResults); + return i; +} + +// add cheat code to freeze the value +static void OnCheatSearchDlg_FreezeClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *dlg; + GtkWidget *box, *hbox, *label, *descr_edit, *value_edit; + char buf[256]; + u32 addr, val = 0; + + addr = SearchResults[GetSelectedResultIndex()]; + + dlg = gtk_dialog_new_with_buttons(_("Freeze value"), GTK_WINDOW(CheatListDlg), + GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + + label = gtk_label_new(_("Description:")); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + descr_edit = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 10); + gtk_widget_show(descr_edit); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 15); + + label = gtk_label_new(_("Value:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + value_edit = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), value_edit, FALSE, FALSE, 10); + gtk_widget_show(value_edit); + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + val = PSXMu8(addr); + break; + + case SEARCHTYPE_16BIT: + val = PSXMu16(addr); + break; + + case SEARCHTYPE_32BIT: + val = PSXMu32(addr); + break; + + default: + assert(FALSE); // should not reach here + break; + } + + sprintf(buf, "%u", val); + gtk_entry_set_text(GTK_ENTRY(value_edit), buf); + + sprintf(buf, "%.8X", addr); + gtk_entry_set_text(GTK_ENTRY(descr_edit), buf); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(value_edit)), "%u", &val); + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + if (val > (u32)0xFF) { + val = 0xFF; + } + sprintf(buf, "%.8X %.4X", (addr & 0x1FFFFF) | (CHEAT_CONST8 << 24), val); + break; + + case SEARCHTYPE_16BIT: + if (val > (u32)0xFFFF) { + val = 0xFFFF; + } + sprintf(buf, "%.8X %.4X", (addr & 0x1FFFFF) | (CHEAT_CONST16 << 24), val); + break; + + case SEARCHTYPE_32BIT: + sprintf(buf, "%.8X %.4X\n%.8X %.4X", + (addr & 0x1FFFFF) | (CHEAT_CONST16 << 24), val & 0xFFFF, + ((addr + 2) & 0x1FFFFF) | (CHEAT_CONST16 << 24), ((val & 0xFFFF0000) >> 16) & 0xFFFF); + break; + + default: + assert(FALSE); // should not reach here + break; + } + + if (AddCheat(gtk_entry_get_text(GTK_ENTRY(descr_edit)), buf) == 0) { + Cheats[NumCheats - 1].Enabled = 1; + } + } + + gtk_widget_destroy(dlg); +} + +// modify the value on the fly +static void OnCheatSearchDlg_ModifyClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *dlg; + GtkWidget *box, *hbox, *label, *value_edit; + char buf[256]; + u32 addr, val = 0; + + addr = SearchResults[GetSelectedResultIndex()]; + + dlg = gtk_dialog_new_with_buttons(_("Modify value"), GTK_WINDOW(CheatListDlg), + GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5); + + label = gtk_label_new(_("New value:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); + gtk_widget_show(label); + + value_edit = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), value_edit, FALSE, FALSE, 10); + gtk_widget_show(value_edit); + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + val = PSXMu8(addr); + break; + + case SEARCHTYPE_16BIT: + val = PSXMu16(addr); + break; + + case SEARCHTYPE_32BIT: + val = PSXMu32(addr); + break; + + default: + assert(FALSE); // should not reach here + break; + } + + sprintf(buf, "%u", val); + gtk_entry_set_text(GTK_ENTRY(value_edit), buf); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(value_edit)), "%u", &val); + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + if (val > 0xFF) { + val = 0xFF; + } + psxMemWrite8(addr, (u8)val); + break; + + case SEARCHTYPE_16BIT: + if (val > 0xFFFF) { + val = 0xFFFF; + } + psxMemWrite16(addr, (u16)val); + break; + + case SEARCHTYPE_32BIT: + psxMemWrite32(addr, (u32)val); + break; + + default: + assert(FALSE); // should not reach here + break; + } + + UpdateCheatSearchDialog(); + } + + gtk_widget_destroy(dlg); +} + +// copy the selected address to clipboard +static void OnCheatSearchDlg_CopyClicked(GtkWidget *widget, gpointer user_data) { + int i; + char buf[9]; + + i = GetSelectedResultIndex(); + assert(i != -1); + + sprintf(buf, "%8X", SearchResults[i]); + buf[8] = '\0'; + + gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buf, 8); +} + +// preform the search +static void OnCheatSearchDlg_SearchClicked(GtkWidget *widget, gpointer user_data) { + GladeXML *xml; + + xml = glade_get_widget_tree(CheatSearchDlg); + + current_search = gtk_combo_box_get_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_searchfor"))); + current_searchtype = gtk_combo_box_get_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_datatype"))); + current_searchbase = gtk_combo_box_get_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_database"))); + current_valuefrom = 0; + current_valueto = 0; + + if (current_searchbase == SEARCHBASE_DEC) { + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value"))), "%u", ¤t_valuefrom); + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto"))), "%u", ¤t_valueto); + } + else { + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value"))), "%x", ¤t_valuefrom); + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto"))), "%x", ¤t_valueto); + } + + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + if (current_valuefrom > (u32)0xFF) { + current_valuefrom = 0xFF; + } + if (current_valueto > (u32)0xFF) { + current_valueto = 0xFF; + } + break; + + case SEARCHTYPE_16BIT: + if (current_valuefrom > (u32)0xFFFF) { + current_valuefrom = 0xFFFF; + } + if (current_valueto > (u32)0xFFFF) { + current_valueto = 0xFFFF; + } + break; + } + + if (current_search == SEARCH_RANGE && current_valuefrom > current_valueto) { + u32 t = current_valuefrom; + current_valuefrom = current_valueto; + current_valueto = t; + } + + switch (current_search) { + case SEARCH_EQUALVAL: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchEqual8((u8)current_valuefrom); + break; + + case SEARCHTYPE_16BIT: + CheatSearchEqual16((u16)current_valuefrom); + break; + + case SEARCHTYPE_32BIT: + CheatSearchEqual32((u32)current_valuefrom); + break; + } + break; + + case SEARCH_NOTEQUALVAL: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchNotEqual8((u8)current_valuefrom); + break; + + case SEARCHTYPE_16BIT: + CheatSearchNotEqual16((u16)current_valuefrom); + break; + + case SEARCHTYPE_32BIT: + CheatSearchNotEqual32((u32)current_valuefrom); + break; + } + break; + + case SEARCH_RANGE: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchRange8((u8)current_valuefrom, (u8)current_valueto); + break; + + case SEARCHTYPE_16BIT: + CheatSearchRange16((u16)current_valuefrom, (u16)current_valueto); + break; + + case SEARCHTYPE_32BIT: + CheatSearchRange32((u32)current_valuefrom, (u32)current_valueto); + break; + } + break; + + case SEARCH_INCBY: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchIncreasedBy8((u8)current_valuefrom); + break; + + case SEARCHTYPE_16BIT: + CheatSearchIncreasedBy16((u16)current_valuefrom); + break; + + case SEARCHTYPE_32BIT: + CheatSearchIncreasedBy32((u32)current_valuefrom); + break; + } + break; + + case SEARCH_DECBY: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchDecreasedBy8((u8)current_valuefrom); + break; + + case SEARCHTYPE_16BIT: + CheatSearchDecreasedBy16((u16)current_valuefrom); + break; + + case SEARCHTYPE_32BIT: + CheatSearchDecreasedBy32((u32)current_valuefrom); + break; + } + break; + + case SEARCH_INC: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchIncreased8(); + break; + + case SEARCHTYPE_16BIT: + CheatSearchIncreased16(); + break; + + case SEARCHTYPE_32BIT: + CheatSearchIncreased32(); + break; + } + break; + + case SEARCH_DEC: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchDecreased8(); + break; + + case SEARCHTYPE_16BIT: + CheatSearchDecreased16(); + break; + + case SEARCHTYPE_32BIT: + CheatSearchDecreased32(); + break; + } + break; + + case SEARCH_DIFFERENT: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchDifferent8(); + break; + + case SEARCHTYPE_16BIT: + CheatSearchDifferent16(); + break; + + case SEARCHTYPE_32BIT: + CheatSearchDifferent32(); + break; + } + break; + + case SEARCH_NOCHANGE: + switch (current_searchtype) { + case SEARCHTYPE_8BIT: + CheatSearchNoChange8(); + break; + + case SEARCHTYPE_16BIT: + CheatSearchNoChange16(); + break; + + case SEARCHTYPE_32BIT: + CheatSearchNoChange32(); + break; + } + break; + + default: + assert(FALSE); // not possible + break; + } + + UpdateCheatSearchDialog(); +} + +// restart the search +static void OnCheatSearchDlg_RestartClicked(GtkWidget *widget, gpointer user_data) { + FreeCheatSearchResults(); + FreeCheatSearchMem(); + + current_search = SEARCH_EQUALVAL; + current_searchtype = SEARCHTYPE_8BIT; + current_searchbase = SEARCHBASE_DEC; + current_valuefrom = 0; + current_valueto = 0; + + UpdateCheatSearchDialog(); +} + +// close the cheat search window +static void OnCheatSearchDlg_CloseClicked(GtkWidget *widget, gpointer user_data) { + gtk_widget_destroy(CheatSearchDlg); + CheatSearchDlg = NULL; +} + +static void OnCheatSearchDlg_SearchForChanged(GtkWidget *widget, gpointer user_data) { + GladeXML *xml; + + xml = glade_get_widget_tree(CheatSearchDlg); + + if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) == SEARCH_RANGE) { + gtk_widget_show(GTK_WIDGET(glade_xml_get_widget(xml, "label_valueto"))); + gtk_widget_show(GTK_WIDGET(glade_xml_get_widget(xml, "entry_valueto"))); + } + else { + gtk_widget_hide(GTK_WIDGET(glade_xml_get_widget(xml, "label_valueto"))); + gtk_widget_hide(GTK_WIDGET(glade_xml_get_widget(xml, "entry_valueto"))); + } + + if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) >= SEARCH_INC) { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "entry_value")), FALSE); + } + else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "entry_value")), TRUE); + } + + if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) >= SEARCH_INCBY && prevM == NULL) { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_start")), FALSE); + } + else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_start")), TRUE); + } +} + +static void OnCheatSearchDlg_DataBaseChanged(GtkWidget *widget, gpointer user_data) { + u32 val; + char buf[256]; + GladeXML *xml; + + xml = glade_get_widget_tree(CheatSearchDlg); + + if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) == SEARCHBASE_DEC) { + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value"))), "%x", &val); + sprintf(buf, "%u", val); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value")), buf); + + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto"))), "%x", &val); + sprintf(buf, "%u", val); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto")), buf); + } + else { + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value"))), "%u", &val); + sprintf(buf, "%X", val); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_value")), buf); + + val = 0; + sscanf(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto"))), "%u", &val); + sprintf(buf, "%X", val); + gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xml, "entry_valueto")), buf); + } +} + +static void CheatSearch_TreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) { + GladeXML *xml; + + xml = glade_get_widget_tree(CheatSearchDlg); + + if (GetSelectedResultIndex() != -1) { + // If a row was selected, we can now enable some of the disabled widgets + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_freeze")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_modify")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_copy")), TRUE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_freeze")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_modify")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "btn_copy")), FALSE); + } +} + +// run the cheat search dialog +void RunCheatSearchDialog() { + GladeXML *xml; + GtkWidget *widget; + GtkCellRenderer *renderer; + GtkTreeSelection *treesel; + GtkTreeViewColumn *column; + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "CheatSearchDlg", NULL); + if (!xml) { + g_warning(_("Error: Glade interface could not be loaded!")); + return; + } + + CheatSearchDlg = glade_xml_get_widget(xml, "CheatSearchDlg"); + gtk_window_set_title(GTK_WINDOW(CheatSearchDlg), _("Cheat Search")); + + widget = glade_xml_get_widget(xml, "GtkCList_Result"); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes(_("Search Results"), + renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + gtk_tree_selection_set_mode (treesel, GTK_SELECTION_SINGLE); + g_signal_connect_data(G_OBJECT(treesel), "changed", + G_CALLBACK(CheatSearch_TreeSelectionChanged), + NULL, NULL, G_CONNECT_AFTER); + + UpdateCheatSearchDialog(); + + widget = glade_xml_get_widget(xml, "btn_freeze"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_FreezeClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_modify"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_ModifyClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_copy"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_CopyClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_start"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_SearchClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_restart"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_RestartClicked), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "combo_searchfor"); + g_signal_connect_data(GTK_OBJECT(widget), "changed", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_SearchForChanged), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "combo_database"); + g_signal_connect_data(GTK_OBJECT(widget), "changed", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_DataBaseChanged), xml, NULL, G_CONNECT_AFTER); + + g_signal_connect_data(GTK_OBJECT(CheatSearchDlg), "response", + GTK_SIGNAL_FUNC(OnCheatSearchDlg_CloseClicked), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); +} diff --git a/gui/Cheat.h b/gui/Cheat.h new file mode 100644 index 0000000..f0990af --- /dev/null +++ b/gui/Cheat.h @@ -0,0 +1,25 @@ +/* Cheat Support for PCSX-Reloaded + * Copyright (C) 2009, Wei Mingzhi . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_CHEAT_H +#define GUI_CHEAT_H + +void RunCheatListDialog(); +void RunCheatSearchDialog(); + +#endif diff --git a/gui/ConfDlg.c b/gui/ConfDlg.c new file mode 100644 index 0000000..6b2aee4 --- /dev/null +++ b/gui/ConfDlg.c @@ -0,0 +1,889 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Linux.h" +#include "ConfDlg.h" + +#include "../libpcsxcore/plugins.h" + +static void OnBiosPath_Changed(GtkWidget *wdg, gpointer data); +static void OnConf_Clicked(GtkDialog *dialog, gint arg1, gpointer user_data); +static void OnPluginPath_Changed(GtkWidget *wdg, gpointer data); +static void OnConfConf_Pad1About(GtkWidget *widget, gpointer user_data); +static void OnConfConf_Pad2About(GtkWidget *widget, gpointer user_data); +static void OnConfConf_Pad1Conf(GtkWidget *widget, gpointer user_data); +static void OnConfConf_Pad2Conf(GtkWidget *widget, gpointer user_data); +static void OnNet_Conf(GtkWidget *widget, gpointer user_data); +static void OnNet_About(GtkWidget *widget, gpointer user_data); +static void on_configure_plugin(GtkWidget *widget, gpointer user_data); +static void on_about_plugin(GtkWidget *widget, gpointer user_data); +static void UpdatePluginsBIOS_UpdateGUI(GladeXML *xml); +static void FindNetPlugin(GladeXML *xml); + +PSEgetLibType PSE_getLibType = NULL; +PSEgetLibVersion PSE_getLibVersion = NULL; +PSEgetLibName PSE_getLibName = NULL; + +GtkWidget *ConfDlg = NULL; +GtkWidget *NetDlg = NULL; +GtkWidget *controlwidget = NULL; + +PluginConf GpuConfS; +PluginConf SpuConfS; +PluginConf CdrConfS; +PluginConf Pad1ConfS; +PluginConf Pad2ConfS; +PluginConf NetConfS; +PluginConf BiosConfS; + +#define FindComboText(combo, list, conf) \ + if (strlen(conf) > 0) { \ + int i; \ + for (i = 2; i < 255; i += 2) { \ + if (!strcmp(conf, list[i - 2])) { \ + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i / 2 - 1); \ + break; \ + } \ + } \ + } + +#define GetComboText(combo, list, conf) \ + { \ + int row; \ + row = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); \ + strcpy(conf, (char *)list[row * 2]); \ + } + +void ConfigurePlugins() { + if (!UseGui) { + /* How do we get here if we're not running the GUI? */ + /* Ryan: we're going to imagine that someday, there will be a way + * to configure plugins from the commandline */ + printf("ERROR: Plugins cannot be configured without the GUI."); + return; + } + + GladeXML *xml; + GtkWidget *widget; + + gchar *path; + + UpdatePluginsBIOS(); + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "ConfDlg", NULL); + + if (!xml) { + g_warning(_("Error: Glade interface could not be loaded!")); + return; + } + + UpdatePluginsBIOS_UpdateGUI(xml); + + ConfDlg = glade_xml_get_widget(xml, "ConfDlg"); + + gtk_window_set_title(GTK_WINDOW(ConfDlg), _("Configure PCSX")); + + /* Set the paths in the file choosers to be based on the saved configurations */ + widget = glade_xml_get_widget(xml, "GtkFileChooser_Bios"); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget), Config.BiosDir); + + widget = glade_xml_get_widget(xml, "GtkFileChooser_Plugin"); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget), Config.PluginsDir); + + if (strlen(Config.PluginsDir) == 0) { + if((path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget))) != NULL) { + strcpy(Config.PluginsDir, path); + g_free(path); + } + } + + widget = glade_xml_get_widget(xml, "btn_ConfGpu"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_configure_plugin), (gpointer) PSE_LT_GPU, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_ConfSpu"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_configure_plugin), (gpointer) PSE_LT_SPU, NULL, G_CONNECT_AFTER); + + /* ADB TODO Does pad 1 and 2 need to be different? */ + widget = glade_xml_get_widget(xml, "btn_ConfPad1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConfConf_Pad1Conf), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_ConfPad2"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConfConf_Pad2Conf), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_ConfCdr"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_configure_plugin), (gpointer) PSE_LT_CDR, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutGpu"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_about_plugin), (gpointer) PSE_LT_GPU, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutSpu"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_about_plugin), (gpointer) PSE_LT_SPU, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutPad1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConfConf_Pad1About), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutPad2"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConfConf_Pad2About), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutCdr"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(on_about_plugin), (gpointer) PSE_LT_CDR, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkFileChooser_Bios"); + g_signal_connect_data(GTK_OBJECT(widget), "current_folder_changed", + GTK_SIGNAL_FUNC(OnBiosPath_Changed), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkFileChooser_Plugin"); + g_signal_connect_data(GTK_OBJECT(widget), "current_folder_changed", + GTK_SIGNAL_FUNC(OnPluginPath_Changed), xml, NULL, G_CONNECT_AFTER); + + g_signal_connect_data(GTK_OBJECT(ConfDlg), "response", + GTK_SIGNAL_FUNC(OnConf_Clicked), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); +} + +void OnNet_Clicked(GtkDialog *dialog, gint arg1, gpointer user_data) { + GetComboText(NetConfS.Combo, NetConfS.plist, Config.Net); + SaveConfig(); + gtk_widget_destroy(GTK_WIDGET(dialog)); + NetDlg = NULL; +} + +void OnConf_Net() { + GladeXML *xml; + GtkWidget *widget; + + if (NetDlg != NULL) { + gtk_window_present (GTK_WINDOW (NetDlg)); + return; + } + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "NetDlg", NULL); + + if (!xml) { + g_warning(_("Error: Glade interface could not be loaded!")); + return; + } + + NetDlg = glade_xml_get_widget(xml, "NetDlg"); + + FindNetPlugin(xml); + + /* Setup a handler for when Close or Cancel is clicked */ + g_signal_connect_data(GTK_OBJECT(NetDlg), "response", + GTK_SIGNAL_FUNC(OnNet_Clicked), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_ConfNet"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnNet_Conf), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_AboutNet"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnNet_About), xml, NULL, G_CONNECT_AFTER); +} + +void OnConf_Graphics() { + void *drv; + GPUconfigure conf; + char Plugin[MAXPATHLEN]; + + sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Gpu); + drv = SysLoadLibrary(Plugin); + if (drv == NULL) { printf("Error with file %s\n", Plugin); return; } + + while (gtk_events_pending()) gtk_main_iteration(); + + conf = (GPUconfigure)SysLoadSym(drv, "GPUconfigure"); + if (conf != NULL) { + conf(); + } + else + SysInfoMessage (_("No configuration required"), _("This plugin doesn't need to be configured.")); + + SysCloseLibrary(drv); +} + +void OnConf_Sound() { + void *drv; + SPUconfigure conf; + char Plugin[MAXPATHLEN]; + + sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Spu); + drv = SysLoadLibrary(Plugin); + if (drv == NULL) { printf("Error with file %s\n", Plugin); return; } + + while (gtk_events_pending()) gtk_main_iteration(); + + conf = (GPUconfigure)SysLoadSym(drv, "SPUconfigure"); + if (conf != NULL) { + conf(); + } + else + SysInfoMessage (_("No configuration required"), _("This plugin doesn't need to be configured.")); + + SysCloseLibrary(drv); +} + +void OnConf_CdRom() { + void *drv; + CDRconfigure conf; + char Plugin[MAXPATHLEN]; + + sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr); + drv = SysLoadLibrary(Plugin); + if (drv == NULL) { printf("Error with file %s\n", Plugin); return; } + + while (gtk_events_pending()) gtk_main_iteration(); + + conf = (GPUconfigure)SysLoadSym(drv, "CDRconfigure"); + if (conf != NULL) { + conf(); + } + else + SysInfoMessage (_("No configuration required"), _("This plugin doesn't need to be configured.")); + + SysCloseLibrary(drv); +} + +void OnConf_Pad() { + void *drv; + PADconfigure conf; + char Plugin[MAXPATHLEN]; + + sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad1); + drv = SysLoadLibrary(Plugin); + if (drv == NULL) { printf("Error with file %s\n", Plugin); return; } + + while (gtk_events_pending()) gtk_main_iteration(); + + conf = (GPUconfigure)SysLoadSym(drv, "PADconfigure"); + if (conf != NULL) { + conf(); + } + else + SysInfoMessage (_("No configuration required"), _("This plugin doesn't need to be configured.")); + + SysCloseLibrary(drv); + + if (strcmp(Config.Pad1, Config.Pad2) != 0) { + sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad2); + drv = SysLoadLibrary(Plugin); + if (drv == NULL) { printf("Error with file %s\n", Plugin); return; } + + while (gtk_events_pending()) gtk_main_iteration(); + + conf = (GPUconfigure)SysLoadSym(drv, "PADconfigure"); + if (conf != NULL) { + conf(); + } + + SysCloseLibrary(drv); + } +} + +static int all_config_set() { + int retval; + + if ((strlen(Config.Gpu) != 0) && + (strlen(Config.Spu) != 0) && + (strlen(Config.Cdr) != 0) && + (strlen(Config.Pad1) != 0) && + (strlen(Config.Pad2) != 0)) + retval = TRUE; + else + retval = FALSE; + + return retval; +} + +/* TODO Check whether configuration is required when we choose the plugin, and set the state of the + button appropriately. New gtk tooltip API should allow us to put a tooltip explanation for + disabled widgets */ +/* TODO If combo screen hasn't been opened and the user chooses the menu config option, confs.Combo will be null and cause a segfault */ +#define ConfPlugin(src, confs, plugin, name, parent) { \ + void *drv; \ + src conf; \ + gchar *filename; \ + \ + GetComboText(confs.Combo, confs.plist, plugin); \ + filename = g_build_filename (getenv("HOME"), PLUGINS_DIR, plugin, NULL); \ + /*printf("Configuring plugin %s\n", filename);*/ \ + drv = SysLoadLibrary(filename); \ + if (drv == NULL) {printf("Error with file %s\n", filename);return; } \ +\ + while (gtk_events_pending()) gtk_main_iteration(); \ + conf = (src) SysLoadSym(drv, name); \ + if (conf) { \ + conf(); \ + } else \ + SysInfoMessage (_("No configuration required"), _("This plugin doesn't need to be configured.")); \ + SysCloseLibrary(drv); \ + g_free (filename); \ +} + +static void on_configure_plugin(GtkWidget *widget, gpointer user_data) { + gint plugin_type = (int) user_data; + + while (gtk_events_pending()) + gtk_main_iteration(); + if (all_config_set() == TRUE) { + switch (plugin_type) { + case PSE_LT_GPU: + ConfPlugin(GPUconfigure, GpuConfS, Config.Gpu, "GPUconfigure", ConfDlg); + break; + case PSE_LT_SPU: + ConfPlugin(SPUconfigure, SpuConfS, Config.Spu, "SPUconfigure", ConfDlg); + break; + case PSE_LT_CDR: + ConfPlugin(CDRconfigure, CdrConfS, Config.Cdr, "CDRconfigure", ConfDlg); + break; + } + } else + ConfigurePlugins(); +} + +static void on_about_plugin(GtkWidget *widget, gpointer user_data) { + gint plugin_type = (int) user_data; + + while (gtk_events_pending()) + gtk_main_iteration(); + if (all_config_set() == TRUE) { + switch (plugin_type) { + case PSE_LT_GPU: + ConfPlugin(GPUconfigure, GpuConfS, Config.Gpu, "GPUabout", ConfDlg); + break; + case PSE_LT_SPU: + ConfPlugin(SPUconfigure, SpuConfS, Config.Spu, "SPUabout", ConfDlg); + break; + case PSE_LT_CDR: + ConfPlugin(CDRconfigure, CdrConfS, Config.Cdr, "CDRabout", ConfDlg); + break; + } + } else + ConfigurePlugins(); +} + +static void OnConfConf_Pad1About(GtkWidget *widget, gpointer user_data) { + ConfPlugin(PADabout, Pad1ConfS, Config.Pad1, "PADabout", ConfDlg); +} + +static void OnConfConf_Pad2About(GtkWidget *widget, gpointer user_data) { + ConfPlugin(PADabout, Pad2ConfS, Config.Pad2, "PADabout", ConfDlg); +} + +static void OnConfConf_Pad1Conf(GtkWidget *widget, gpointer user_data) { + ConfPlugin(PADabout, Pad1ConfS, Config.Pad1, "PADconfigure", ConfDlg); +} + +static void OnConfConf_Pad2Conf(GtkWidget *widget, gpointer user_data) { + ConfPlugin(PADabout, Pad2ConfS, Config.Pad2, "PADconfigure", ConfDlg); +} + +static void OnNet_Conf(GtkWidget *widget, gpointer user_data) { + ConfPlugin(NETconfigure, NetConfS, Config.Net, "NETconfigure", NetDlg); +} + +static void OnNet_About(GtkWidget *widget, gpointer user_data) { + ConfPlugin(NETabout, NetConfS, Config.Net, "NETabout", NetDlg); +} + +static void OnPluginPath_Changed(GtkWidget *wdg, gpointer data) { + gchar *path; + + path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (wdg)); + strcpy(Config.PluginsDir, path); + UpdatePluginsBIOS(); + UpdatePluginsBIOS_UpdateGUI(data); + + g_free(path); +} + +static void OnBiosPath_Changed(GtkWidget *wdg, gpointer data) { + gchar *foldername; + + foldername = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (wdg)); + strcpy(Config.BiosDir, foldername); + + UpdatePluginsBIOS(); + UpdatePluginsBIOS_UpdateGUI(data); + + g_free(foldername); +} + +void OnConf_Clicked(GtkDialog *dialog, gint arg1, gpointer user_data) { + GetComboText(GpuConfS.Combo, GpuConfS.plist, Config.Gpu); + GetComboText(SpuConfS.Combo, SpuConfS.plist, Config.Spu); + GetComboText(CdrConfS.Combo, CdrConfS.plist, Config.Cdr); + GetComboText(Pad1ConfS.Combo, Pad1ConfS.plist, Config.Pad1); + GetComboText(Pad2ConfS.Combo, Pad2ConfS.plist, Config.Pad2); + GetComboText(BiosConfS.Combo, BiosConfS.plist, Config.Bios); + + SaveConfig(); + + gtk_widget_destroy(ConfDlg); + ConfDlg = NULL; +} + +#define ComboAddPlugin(type) { \ + type##ConfS.plugins += 2; \ + strcpy(type##ConfS.plist[type##ConfS.plugins - 1], name); \ + strcpy(type##ConfS.plist[type##ConfS.plugins - 2], ent->d_name); \ + type##ConfS.glist = g_list_append(type##ConfS.glist, type##ConfS.plist[type##ConfS.plugins-1]); \ +} + +void populate_combo_box(GtkWidget *widget, GList *list) { + GtkListStore *store; + GtkCellRenderer *renderer; + store = gtk_list_store_new(1, G_TYPE_STRING); + + // Clear existing data from combo box + gtk_cell_layout_clear(GTK_CELL_LAYOUT(widget)); + + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, FALSE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0); + + while (list != NULL) { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, (char *)list->data, -1); + list = list->next; + } + + gtk_combo_box_set_model(GTK_COMBO_BOX(widget), GTK_TREE_MODEL(store)); +} + +#define ConfCreatePConf(name, type) \ + /* Populate the relevant combo widget with the list of plugins. \ + If no plugins available, disable the combo and its controls. \ + Note that the Bios plugin has no About/Conf control. */ \ + type##ConfS.Combo = glade_xml_get_widget(xml, "GtkCombo_" name); \ + if (type##ConfS.glist != NULL) { \ + populate_combo_box (type##ConfS.Combo, type##ConfS.glist); \ + FindComboText(type##ConfS.Combo, type##ConfS.plist, Config.type); \ + gtk_widget_set_sensitive (type##ConfS.Combo, TRUE); \ + if (g_ascii_strcasecmp (name, "Bios") != 0) { \ + controlwidget = glade_xml_get_widget(xml, "btn_Conf" name); \ + gtk_widget_set_sensitive (controlwidget, TRUE); \ + controlwidget = glade_xml_get_widget(xml, "btn_About" name); \ + gtk_widget_set_sensitive (controlwidget, TRUE); \ + } \ + } else { \ + if (g_ascii_strcasecmp (name, "Bios") != 0) { \ + gtk_cell_layout_clear (GTK_CELL_LAYOUT (type##ConfS.Combo)); \ + gtk_widget_set_sensitive (type##ConfS.Combo, FALSE); \ + controlwidget = glade_xml_get_widget(xml, "btn_Conf" name); \ + gtk_widget_set_sensitive (controlwidget, FALSE); \ + controlwidget = glade_xml_get_widget(xml, "btn_About" name); \ + gtk_widget_set_sensitive (controlwidget, FALSE); \ + } \ + } + +int plugin_is_available(gchar *plugin) { + int retval; + gchar *pluginfile; + struct stat stbuf; + + pluginfile = g_strconcat(getenv("HOME"), PLUGINS_DIR, plugin, NULL); + + if (stat(pluginfile, &stbuf) == -1) + retval = FALSE; + else + retval = TRUE; + + g_free(pluginfile); + + return retval; +} + +int plugins_configured() { + // make sure there are choices for all of the plugins!! + if (all_config_set() == FALSE) + return FALSE; + + // and make sure they can all be accessed + // if they can't be, wipe the variable and return FALSE + if (plugin_is_available (Config.Gpu) == FALSE) { Config.Gpu[0] = '\0'; return FALSE; } + if (plugin_is_available (Config.Spu) == FALSE) { Config.Spu[0] = '\0'; return FALSE; } + if (plugin_is_available (Config.Cdr) == FALSE) { Config.Cdr[0] = '\0'; return FALSE; } + if (plugin_is_available (Config.Pad1) == FALSE) { Config.Pad1[0] = '\0'; return FALSE; } + if (plugin_is_available (Config.Pad2) == FALSE) { Config.Pad2[0] = '\0'; return FALSE; } + + // if everything is happy, return TRUE + return TRUE; +} + +int is_valid_bios_file(gchar *filename) { + int valid; + struct stat buf; + + if ((stat(filename, &buf) == -1) || (buf.st_size != (1024*512))) + valid = FALSE; + else { + valid = TRUE; + } + + return valid; +} + +// Add the name of the BIOS file to the drop-down list. This will +// be the filename, not the full path to the file +void add_bios_to_list(gchar *bios_name, gchar *internal_name) { + BiosConfS.plugins += 2; + strcpy(BiosConfS.plist[BiosConfS.plugins - 1], bios_name); + strcpy(BiosConfS.plist[BiosConfS.plugins - 2], internal_name); + BiosConfS.glist = g_list_append(BiosConfS.glist, BiosConfS.plist[BiosConfS.plugins - 1]); +} + +void scan_bios_dir(gchar *dirname) { + DIR *dir; + struct dirent *ent; + gchar *filename; + + dir = opendir(dirname); + if (dir == NULL) { + SysMessage(_("Could not open BIOS directory: '%s'\n"), dirname); + return; + } + + while ((ent = readdir(dir)) != NULL) { + filename = g_build_filename(dirname, ent->d_name, NULL); + if (is_valid_bios_file(filename)) + add_bios_to_list(g_path_get_basename(filename), g_path_get_basename (filename)); + g_free(filename); + } + closedir(dir); +} + +void UpdatePluginsBIOS() { + DIR *dir; + struct dirent *ent; + void *Handle; + char name[256]; + gchar *linkname; + + GpuConfS.plugins = 0; SpuConfS.plugins = 0; CdrConfS.plugins = 0; + Pad1ConfS.plugins = 0; Pad2ConfS.plugins = 0; BiosConfS.plugins = 0; + GpuConfS.glist = NULL; SpuConfS.glist = NULL; CdrConfS.glist = NULL; + Pad1ConfS.glist = NULL; Pad2ConfS.glist = NULL; BiosConfS.glist = NULL; + GpuConfS.plist[0][0] = '\0'; SpuConfS.plist[0][0] = '\0'; CdrConfS.plist[0][0] = '\0'; + Pad1ConfS.plist[0][0] = '\0'; Pad2ConfS.plist[0][0] = '\0'; BiosConfS.plist[0][0] = '\0'; + + // Load and get plugin info + dir = opendir(Config.PluginsDir); + if (dir == NULL) { + printf(_("Could not open directory: '%s'\n"), Config.PluginsDir); + return; + } + while ((ent = readdir(dir)) != NULL) { + long type, v; + linkname = g_build_filename(Config.PluginsDir, ent->d_name, NULL); + + // only libraries past this point, not config tools + if (strstr(linkname, ".so") == NULL && strstr(linkname, ".dylib") == NULL) + continue; + + Handle = dlopen(linkname, RTLD_NOW); + if (Handle == NULL) { + printf("%s\n", dlerror()); + g_free(linkname); + continue; + } + + PSE_getLibType = (PSEgetLibType)dlsym(Handle, "PSEgetLibType"); + if (PSE_getLibType == NULL) { + if (strstr(linkname, "gpu") != NULL) type = PSE_LT_GPU; + else if (strstr(linkname, "cdr") != NULL) type = PSE_LT_CDR; + else if (strstr(linkname, "spu") != NULL) type = PSE_LT_SPU; + else if (strstr(linkname, "pad") != NULL) type = PSE_LT_PAD; + else { g_free(linkname); continue; } + } + else type = PSE_getLibType(); + + PSE_getLibName = (PSEgetLibName) dlsym(Handle, "PSEgetLibName"); + if (PSE_getLibName != NULL) { + sprintf(name, "%s", PSE_getLibName()); + PSE_getLibVersion = (PSEgetLibVersion) dlsym(Handle, "PSEgetLibVersion"); + if (PSE_getLibVersion != NULL) { + char ver[32]; + + v = PSE_getLibVersion(); + sprintf(ver, " %ld.%ld.%ld", v >> 16, (v >> 8) & 0xff, v & 0xff); + strcat(name, ver); + } + } + else strcpy(name, ent->d_name); + + if (type & PSE_LT_CDR) + ComboAddPlugin(Cdr); + if (type & PSE_LT_GPU) + ComboAddPlugin(Gpu); + if (type & PSE_LT_SPU) + ComboAddPlugin(Spu); + if (type & PSE_LT_PAD) { + PADquery query = (PADquery)dlsym(Handle, "PADquery"); + if (query() & 0x1) { + ComboAddPlugin(Pad1); + } + if (query() & 0x2) { + ComboAddPlugin(Pad2); + } + } + g_free(linkname); + } + closedir(dir); + + scan_bios_dir(Config.BiosDir); + + // The BIOS list always contains the PCSX internal BIOS + add_bios_to_list(_("Simulate PSX BIOS"), "HLE"); +} + +static void UpdatePluginsBIOS_UpdateGUI(GladeXML *xml) { + // Populate the plugin combo boxes + ConfCreatePConf("Gpu", Gpu); + ConfCreatePConf("Spu", Spu); + ConfCreatePConf("Pad1", Pad1); + ConfCreatePConf("Pad2", Pad2); + ConfCreatePConf("Cdr", Cdr); + ConfCreatePConf("Bios", Bios); +} + +static void FindNetPlugin(GladeXML *xml) { + DIR *dir; + struct dirent *ent; + void *Handle; + char plugin[MAXPATHLEN],name[MAXPATHLEN]; + + NetConfS.plugins = 0; + NetConfS.glist = NULL; + + NetConfS.plugins += 2; + strcpy(NetConfS.plist[NetConfS.plugins - 1], "Disabled"); + strcpy(NetConfS.plist[NetConfS.plugins - 2], "Disabled"); + NetConfS.glist = g_list_append(NetConfS.glist, NetConfS.plist[NetConfS.plugins - 1]); + + dir = opendir(Config.PluginsDir); + if (dir == NULL) + SysMessage(_("Could not open directory: '%s'\n"), Config.PluginsDir); + else { + /* ADB TODO Replace the following with a function */ + while ((ent = readdir(dir)) != NULL) { + long type, v; + + sprintf(plugin, "%s/%s", Config.PluginsDir, ent->d_name); + + if (strstr(plugin, ".so") == NULL && strstr(plugin, ".dylib") == NULL) + continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) continue; + + PSE_getLibType = (PSEgetLibType) dlsym(Handle, "PSEgetLibType"); + if (PSE_getLibType == NULL) { + if (strstr(plugin, "net") != NULL) type = PSE_LT_NET; + else continue; + } + else type = PSE_getLibType(); + + PSE_getLibName = (PSEgetLibName) dlsym(Handle, "PSEgetLibName"); + if (PSE_getLibName != NULL) { + sprintf(name, "%s", PSE_getLibName()); + PSE_getLibVersion = (PSEgetLibVersion) dlsym(Handle, "PSEgetLibVersion"); + if (PSE_getLibVersion != NULL) { + char ver[32]; + + v = PSE_getLibVersion(); + sprintf(ver, " %ld.%ld.%ld",v>>16,(v>>8)&0xff,v&0xff); + strcat(name, ver); + } + } + else strcpy(name, ent->d_name); + + if (type & PSE_LT_NET) { + ComboAddPlugin(Net); + } + } + closedir(dir); + + ConfCreatePConf("Net", Net); + } +} + +GtkWidget *CpuDlg; +GtkWidget *PsxCombo; +GList *psxglist; +char *psxtypes[] = { + "NTSC", + "PAL" +}; + +// When the auto-detect CPU type is selected, disable the NTSC/PAL selection +static void OnCpu_PsxAutoClicked (GtkWidget *widget, gpointer user_data) { + GtkWidget *combo; + GladeXML *xml = user_data; + combo = glade_xml_get_widget(xml, "GtkCombo_PsxType"); + + gtk_widget_set_sensitive (combo, + !(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))); +} + +// When the interpreter core is deselected, disable the debugger checkbox +static void OnCpu_CpuClicked(GtkWidget *widget, gpointer user_data) { + GtkWidget *check; + GladeXML *xml = user_data; + check = glade_xml_get_widget(xml, "GtkCheckButton_Dbg"); + + // Debugger is only working with interpreter not recompiler, so let's set it + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), FALSE); + + gtk_widget_set_sensitive (check, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))); +} + +void OnCpu_Clicked(GtkDialog *dialog, gint arg1, gpointer user_data) { + GtkWidget *widget; + GladeXML *xml = user_data; + int tmp; + long t; + + widget = glade_xml_get_widget(xml, "GtkCombo_PsxType"); + + // If nothing chosen, default to NTSC + tmp = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); + if (tmp == -1) + tmp = PSX_TYPE_NTSC; + + if (!strcmp("NTSC", psxtypes[tmp])) + Config.PsxType = PSX_TYPE_NTSC; + else + Config.PsxType = PSX_TYPE_PAL; + + Config.Xa = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Xa"))); + Config.Sio = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Sio"))); + Config.Mdec = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Mdec"))); + Config.Cdda = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_CDDA"))); + Config.PsxAuto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_PsxAuto"))); + + t = Config.Debug; + Config.Debug = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Dbg"))); + if (t != Config.Debug) { + if (Config.Debug) StartDebugger(); + else StopDebugger(); + } + + t = Config.Cpu; + Config.Cpu = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Cpu"))); + if (t != Config.Cpu) { + psxCpu->Shutdown(); +#ifdef PSXREC + if (Config.Cpu == CPU_INTERPRETER) { + psxCpu = &psxInt; + } + else psxCpu = &psxRec; +#else + psxCpu = &psxInt; +#endif + if (psxCpu->Init() == -1) { + SysClose(); + exit(1); + } + psxCpu->Reset(); + } + + Config.PsxOut = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_PsxOut"))); + Config.SpuIrq = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_SpuIrq"))); + Config.RCntFix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_RCntFix"))); + Config.VSyncWA = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_VSyncWA"))); + + SaveConfig(); + + gtk_widget_destroy(CpuDlg); + CpuDlg = NULL; +} + +void OnConf_Cpu() { + GladeXML *xml; + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "CpuDlg", NULL); + + if (!xml) { + g_warning("We could not load the interface!"); + return; + } + + CpuDlg = glade_xml_get_widget(xml, "CpuDlg"); + + PsxCombo = glade_xml_get_widget(xml, "GtkCombo_PsxType"); + gtk_combo_box_set_active(GTK_COMBO_BOX (PsxCombo), Config.PsxType); + gtk_widget_set_sensitive(GTK_WIDGET (PsxCombo), !Config.PsxAuto); + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Xa")), Config.Xa); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Sio")), Config.Sio); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Mdec")), Config.Mdec); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_CDDA")), Config.Cdda); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_PsxAuto")), Config.PsxAuto); + + g_signal_connect_data(GTK_OBJECT(glade_xml_get_widget(xml, "GtkCheckButton_PsxAuto")), "toggled", + GTK_SIGNAL_FUNC(OnCpu_PsxAutoClicked), xml, NULL, G_CONNECT_AFTER); + +#ifdef PSXREC + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_Cpu")), Config.Cpu); + + g_signal_connect_data(GTK_OBJECT(glade_xml_get_widget(xml, "GtkCheckButton_Cpu")), "toggled", + GTK_SIGNAL_FUNC(OnCpu_CpuClicked), xml, NULL, G_CONNECT_AFTER); +#else + Config.Cpu = CPU_INTERPRETER; + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_Cpu")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET (glade_xml_get_widget(xml, "GtkCheckButton_Cpu")), FALSE); +#endif + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_Dbg")), Config.Cpu && Config.Debug); + gtk_widget_set_sensitive(GTK_WIDGET (glade_xml_get_widget(xml, "GtkCheckButton_Dbg")), Config.Cpu); + + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_PsxOut")), Config.PsxOut); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_SpuIrq")), Config.SpuIrq); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_RCntFix")), Config.RCntFix); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_VSyncWA")), Config.VSyncWA); + + // Setup a handler for when Close or Cancel is clicked + g_signal_connect_data(GTK_OBJECT(CpuDlg), "response", + GTK_SIGNAL_FUNC(OnCpu_Clicked), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); +} diff --git a/gui/ConfDlg.h b/gui/ConfDlg.h new file mode 100644 index 0000000..56afc28 --- /dev/null +++ b/gui/ConfDlg.h @@ -0,0 +1,50 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef CONFDLG_H +#define CONFDLG_H + +// Helper Functions +void UpdatePluginsBIOS(); + +// Functions Callbacks +void OnConf_Graphics(); +void OnConf_Sound(); +void OnConf_CdRom(); +void OnConf_Pad(); +void OnConf_Cpu(); +void OnConf_Net(); + +void ConfigurePlugins(); + +typedef struct { + GtkWidget *Combo; + GList *glist; + char plist[255][255]; /* TODO Comment this out */ + int plugins; /* TODO Comment this out and replace with glist count */ +} PluginConf; + +extern PluginConf GpuConfS; +extern PluginConf SpuConfS; +extern PluginConf CdrConfS; +extern PluginConf Pad1ConfS; +extern PluginConf Pad2ConfS; +extern PluginConf NetConfS; +extern PluginConf BiosConfS; + +#endif diff --git a/gui/Config.c b/gui/Config.c new file mode 100644 index 0000000..aff4f1e --- /dev/null +++ b/gui/Config.c @@ -0,0 +1,180 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "Linux.h" + +/* TODO escaping/unescaping would be nice, as would maxchars */ +static void GetValue(char *src, char *name, char *outvar) { + char *tmp; + + *outvar = 0; + tmp = strstr(src, name); + if (tmp == NULL) return; + + tmp += strlen(name); + while ((*tmp == ' ') || (*tmp == '=')) tmp++; + + while (*tmp != '\n' && *tmp != 0) + *outvar++ = *tmp++; + + *outvar = 0; + return; +} + +static long GetValuel(char *src, char *name) { + char *tmp = strstr(src, name); + if (tmp != NULL) { + tmp += strlen(name); + while ((*tmp == ' ') || (*tmp == '=')) tmp++; + if (*tmp != '\n') return atol(tmp); + } + return 0; +} + +static boolean GetValueb(char *src, char *name) { + char *tmp = strstr(src, name); + if (tmp != NULL) { + tmp += strlen(name); + while ((*tmp == ' ') || (*tmp == '=')) tmp++; + if (*tmp != '\n') return (atoi(tmp) != 0); + } + return FALSE; +} + +#define SetValue(name, var) \ + fprintf(f, "%s = %s\n", name, var); + +#define SetValuel(name, var) \ + fprintf(f, "%s = %x\n", name, var); + +#define SetValueb(name, var) \ + fprintf(f, "%s = %d\n", name, (var) ? 1 : 0); + +int LoadConfig(PcsxConfig *Conf) { + struct stat buf; + FILE *f; + int size; + char *data; + + /* TODO local var called cfgfile */ + + // Ryan says: use dotdir, dotdir is GOOD + // No giant homedir names + strncpy(cfgfile, getenv("HOME"), 200); + strcat(cfgfile, PCSX_DOT_DIR); + + // proceed to load the cfg file + // append its name + strcat(cfgfile, cfgfile_basename); + + // file is now ~/.pcsx/pcsx.cfg (or whatever cfgfile_basename is) + if (stat(cfgfile, &buf) == -1) { + // the config file doesn't exist! + /* TODO Error checking? */ + printf("Configuration file %s couldn't be found\n", cfgfile); + return -1; + } + + size = buf.st_size; + + /* TODO Error checking for the next two lines, and at least log failures */ + f = fopen(cfgfile, "r"); + if (f == NULL) return -1; + + data = (char *)malloc(size + 1); + if (data == NULL) return -1; + + fread(data, 1, buf.st_size, f); + fclose(f); + + data[size] = '\0'; + + GetValue(data, "Bios", Config.Bios); + GetValue(data, "Gpu", Config.Gpu); + GetValue(data, "Spu", Config.Spu); + GetValue(data, "Cdr", Config.Cdr); + GetValue(data, "Pad1", Config.Pad1); + GetValue(data, "Pad2", Config.Pad2); + GetValue(data, "Net", Config.Net); + GetValue(data, "Mcd1", Config.Mcd1); + GetValue(data, "Mcd2", Config.Mcd2); + GetValue(data, "BiosDir", Config.BiosDir); + GetValue(data, "PluginsDir", Config.PluginsDir); + + Config.Xa = GetValueb(data, "Xa"); + Config.Sio = GetValueb(data, "Sio"); + Config.Mdec = GetValueb(data, "Mdec"); + Config.PsxAuto = GetValueb(data, "PsxAuto"); + Config.Cdda = GetValueb(data, "Cdda"); + Config.Debug = GetValueb(data, "Dbg"); + Config.PsxOut = GetValueb(data, "PsxOut"); + Config.SpuIrq = GetValueb(data, "SpuIrq"); + Config.RCntFix = GetValueb(data, "RCntFix"); + Config.VSyncWA = GetValueb(data, "VSyncWA"); + + Config.Cpu = GetValuel(data, "Cpu"); + Config.PsxType = GetValuel(data, "PsxType"); + + free(data); + + return 0; +} + +void SaveConfig() { + FILE *f; + + /* TODO Error checking for the next two lines, and at least log + failures - suggest a file dialog to specify a new file or + create a new file */ + f = fopen(cfgfile, "w"); + if (f == NULL) return; + + SetValue("Bios", Config.Bios); + SetValue("Gpu", Config.Gpu); + SetValue("Spu", Config.Spu); + SetValue("Cdr", Config.Cdr); + SetValue("Net", Config.Net); + SetValue("Pad1", Config.Pad1); + SetValue("Pad2", Config.Pad2); + SetValue("Mcd1", Config.Mcd1); + SetValue("Mcd2", Config.Mcd2); + SetValue("BiosDir", Config.BiosDir); + SetValue("PluginsDir", Config.PluginsDir); + + SetValueb("Xa", Config.Xa); + SetValueb("Sio", Config.Sio); + SetValueb("Mdec", Config.Mdec); + SetValueb("PsxAuto", Config.PsxAuto); + SetValueb("Cdda", Config.Cdda); + SetValueb("Dbg", Config.Debug); + SetValueb("PsxOut", Config.PsxOut); + SetValueb("SpuIrq", Config.SpuIrq); + SetValueb("RCntFix", Config.RCntFix); + SetValueb("VSyncWA", Config.VSyncWA); + + SetValuel("Cpu", Config.Cpu); + SetValuel("PsxType", Config.PsxType); + + fclose(f); +} diff --git a/gui/DebugMemory.c b/gui/DebugMemory.c new file mode 100644 index 0000000..e001057 --- /dev/null +++ b/gui/DebugMemory.c @@ -0,0 +1,312 @@ +/* Memory Viewer/Dumper for PCSX-Reloaded + * Copyright (C) 2010, Wei Mingzhi . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include "Linux.h" +#include "../libpcsxcore/psxmem.h" +#include + +#define MEMVIEW_MAX_LINES 256 + +static GtkWidget *MemViewDlg = NULL; +static u32 MemViewAddress = 0; + +static void UpdateMemViewDlg() { + s32 start, end; + int i; + char bufaddr[9], bufdata[16][3], buftext[17]; + + GtkListStore *store = gtk_list_store_new(18, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING); + + GtkTreeIter iter; + GtkWidget *widget; + GladeXML *xml; + + xml = glade_get_widget_tree(MemViewDlg); + + MemViewAddress &= 0x1fffff; + + sprintf(buftext, "%.8X", MemViewAddress | 0x80000000); + widget = glade_xml_get_widget(xml, "entry_address"); + gtk_entry_set_text(GTK_ENTRY(widget), buftext); + + start = MemViewAddress & 0x1ffff0; + end = start + MEMVIEW_MAX_LINES * 16; + + if (end > 0x1fffff) end = 0x1fffff; + + widget = glade_xml_get_widget(xml, "GtkCList_MemView"); + + buftext[16] = '\0'; + + while (start < end) { + sprintf(bufaddr, "%.8X", start | 0x80000000); + + for (i = 0; i < 16; i++) { + buftext[i] = psxMs8(start + i); + sprintf(bufdata[i], "%.2X", (u8)buftext[i]); + if ((u8)buftext[i] < 32 || (u8)buftext[i] >= 127) + buftext[i] = '.'; + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, bufaddr, 1, bufdata[0], + 2, bufdata[1], 3, bufdata[2], 4, bufdata[3], 5, bufdata[4], + 6, bufdata[5], 7, bufdata[6], 8, bufdata[7], 9, bufdata[8], + 10, bufdata[9], 11, bufdata[10], 12, bufdata[11], 13, bufdata[12], + 14, bufdata[13], 15, bufdata[14], 16, bufdata[15], 17, buftext, -1); + + start += 16; + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(widget), TRUE); + gtk_widget_show(widget); +} + +static void MemView_Go() { + GtkWidget *widget; + GladeXML *xml; + + xml = glade_get_widget_tree(MemViewDlg); + widget = glade_xml_get_widget(xml, "entry_address"); + + sscanf(gtk_entry_get_text(GTK_ENTRY(widget)), "%x", &MemViewAddress); + + UpdateMemViewDlg(); +} + +static void MemView_Dump() { + GtkWidget *dlg; + GtkWidget *box, *table, *label, *start_edit, *length_edit; + char buf[10]; + + dlg = gtk_dialog_new_with_buttons(_("Memory Dump"), GTK_WINDOW(MemViewDlg), + GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + + table = gtk_table_new(2, 2, FALSE); + + label = gtk_label_new(_("Start Address (Hexadecimal):")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5); + gtk_widget_show(label); + + start_edit = gtk_entry_new_with_max_length(8); + sprintf(buf, "%.8X", MemViewAddress | 0x80000000); + gtk_entry_set_text(GTK_ENTRY(start_edit), buf); + gtk_table_attach(GTK_TABLE(table), start_edit, 1, 2, 0, 1, 0, 0, 5, 5); + gtk_widget_show(start_edit); + + label = gtk_label_new(_("Length (Decimal):")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5); + gtk_widget_show(label); + + length_edit = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), length_edit, 1, 2, 1, 2, 0, 0, 5, 5); + gtk_widget_show(length_edit); + + gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 5); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + s32 start = 0, length = 0; + + sscanf(gtk_entry_get_text(GTK_ENTRY(start_edit)), "%x", &start); + sscanf(gtk_entry_get_text(GTK_ENTRY(length_edit)), "%d", &length); + + start &= 0x1fffff; + + if (start + length > 0x1fffff) { + length = 0x1fffff - start; + } + + if (length > 0) { + GtkWidget *file_chooser = gtk_file_chooser_dialog_new(_("Dump to File"), + NULL, GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), getenv("HOME")); + + if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) { + gchar *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); + FILE *fp = fopen(file, "wb"); + + if (fp != NULL) { + fwrite(&psxM[start], 1, length, fp); + fclose(fp); + } else { + SysMessage(_("Error writing to %s!"), file); + } + + g_free(file); + } + + gtk_widget_destroy(file_chooser); + } + } + + gtk_widget_destroy(dlg); +} + +static void MemView_Patch() { + GtkWidget *dlg; + GtkWidget *box, *table, *label, *addr_edit, *val_edit; + char buf[10]; + + dlg = gtk_dialog_new_with_buttons(_("Memory Patch"), GTK_WINDOW(MemViewDlg), + GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + + box = GTK_WIDGET(GTK_DIALOG(dlg)->vbox); + + table = gtk_table_new(2, 2, FALSE); + + label = gtk_label_new(_("Address (Hexadecimal):")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5); + gtk_widget_show(label); + + addr_edit = gtk_entry_new_with_max_length(8); + sprintf(buf, "%.8X", MemViewAddress | 0x80000000); + gtk_entry_set_text(GTK_ENTRY(addr_edit), buf); + gtk_table_attach(GTK_TABLE(table), addr_edit, 1, 2, 0, 1, 0, 0, 5, 5); + gtk_widget_show(addr_edit); + + label = gtk_label_new(_("Value (Hexa string):")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5); + gtk_widget_show(label); + + val_edit = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), val_edit, 1, 2, 1, 2, 0, 0, 5, 5); + gtk_widget_show(val_edit); + + gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 5); + + gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER); + gtk_widget_show_all(dlg); + + if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) { + u32 addr = 0xffffffff, val = 0; + const char *p = gtk_entry_get_text(GTK_ENTRY(val_edit)); + int r = strlen(p); + + sscanf(gtk_entry_get_text(GTK_ENTRY(addr_edit)), "%x", &addr); + + if (r > 0 && addr != 0xffffffff) { + addr &= 0x1fffff; + MemViewAddress = addr; + + while (r > 0 && addr <= 0x1fffff) { + sscanf(p, "%2x", &val); + p += 2; + r -= 2; + + while (r > 0 && (*p == '\t' || *p == ' ')) { + p++; + r--; + } + + psxMemWrite8(addr, (u8)val); + addr++; + } + + UpdateMemViewDlg(); + } + } + + gtk_widget_destroy(dlg); +} + +// close the memory viewer window +static void MemView_Close(GtkWidget *widget, gpointer user_data) { + gtk_widget_destroy(MemViewDlg); + MemViewDlg = NULL; +} + +void RunDebugMemoryDialog() { + GladeXML *xml; + GtkWidget *widget; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + PangoFontDescription *pfd; + int i; + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "MemViewDlg", NULL); + if (!xml) { + g_warning(_("Error: Glade interface could not be loaded!")); + return; + } + + MemViewDlg = glade_xml_get_widget(xml, "MemViewDlg"); + gtk_window_set_title(GTK_WINDOW(MemViewDlg), _("Memory Viewer")); + + widget = glade_xml_get_widget(xml, "GtkCList_MemView"); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Address"), + renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + + for (i = 0; i < 16; i++) { + const char *p = "0123456789ABCDEF"; + char buf[2]; + + buf[0] = p[i]; + buf[1] = '\0'; + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(buf, + renderer, "text", i + 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + } + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Text"), + renderer, "text", 17, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column); + + pfd = pango_font_description_from_string("Bitstream Vera Sans Mono, " + "DejaVu Sans Mono, Liberation Mono, FreeMono, Sans Mono 9"); + gtk_widget_modify_font(widget, pfd); + pango_font_description_free(pfd); + + UpdateMemViewDlg(); + + widget = glade_xml_get_widget(xml, "btn_dump"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(MemView_Dump), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_patch"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(MemView_Patch), xml, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "btn_go"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(MemView_Go), xml, NULL, G_CONNECT_AFTER); + + g_signal_connect_data(GTK_OBJECT(MemViewDlg), "response", + GTK_SIGNAL_FUNC(MemView_Close), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); +} diff --git a/gui/DebugMemory.h b/gui/DebugMemory.h new file mode 100644 index 0000000..4967373 --- /dev/null +++ b/gui/DebugMemory.h @@ -0,0 +1,24 @@ +/* Memory Viewer/Dumper for PCSX-Reloaded + * Copyright (C) 2010, Wei Mingzhi . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef DEBUGMEMORY_H +#define DEBUGMEMORY_H + +void RunDebugMemoryDialog(); + +#endif diff --git a/gui/Gtk2Gui.c b/gui/Gtk2Gui.c new file mode 100644 index 0000000..89da504 --- /dev/null +++ b/gui/Gtk2Gui.c @@ -0,0 +1,944 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Linux.h" + +#include "../libpcsxcore/plugins.h" +#include "../libpcsxcore/cheat.h" + +#include "MemcardDlg.h" +#include "ConfDlg.h" +#include "DebugMemory.h" +#include "AboutDlg.h" + +// Functions Callbacks +void OnFile_RunCd(); +void OnFile_RunBios(); +void OnFile_RunExe(); +void OnFile_RunImage(); +void OnEmu_Run(); +void OnEmu_Reset(); +void OnEmu_SwitchImage(); +void OnHelp_Help(); +void OnHelp_About(); +void OnDestroy(); +void OnFile_Exit(); + +void on_states_load(GtkWidget *widget, gpointer user_data); +void on_states_load_other(); +void on_states_save(GtkWidget *widget, gpointer user_data); +void on_states_save_other(); + +GtkWidget *Window = NULL; + +int destroy = 0; + +#define MAX_SLOTS 5 + +/* TODO - If MAX_SLOTS changes, need to find a way to automatically set all positions */ +int Slots[MAX_SLOTS] = { -1, -1, -1, -1, -1 }; + +void ResetMenuSlots(GladeXML *xml) { + GtkWidget *widget; + gchar *str; + int i; + + if (CdromId[0] == '\0') { + // disable state saving/loading if no CD is loaded + for (i = 0; i < MAX_SLOTS; i++) { + str = g_strdup_printf("GtkMenuItem_SaveSlot%d", i+1); + widget = glade_xml_get_widget(xml, str); + g_free(str); + + gtk_widget_set_sensitive(widget, FALSE); + + str = g_strdup_printf("GtkMenuItem_LoadSlot%d", i+1); + widget = glade_xml_get_widget(xml, str); + g_free(str); + + gtk_widget_set_sensitive(widget, FALSE); + } + + // also disable certain menu/toolbar items + widget = glade_xml_get_widget(xml, "other1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "other2"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "run1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "reset1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "search1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "SwitchImage"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "memorydump1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "toolbutton_run"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "toolbutton_switchimage"); + gtk_widget_set_sensitive(widget, FALSE); + + widget = glade_xml_get_widget(xml, "statusbar"); + gtk_statusbar_pop(GTK_STATUSBAR(widget), 1); + gtk_statusbar_push(GTK_STATUSBAR(widget), 1, _("Ready")); + } + else { + for (i = 0; i < MAX_SLOTS; i++) { + str = g_strdup_printf("GtkMenuItem_LoadSlot%d", i+1); + widget = glade_xml_get_widget (xml, str); + g_free (str); + + if (Slots[i] == -1) + gtk_widget_set_sensitive(widget, FALSE); + else + gtk_widget_set_sensitive(widget, TRUE); + } + + widget = glade_xml_get_widget(xml, "plugins_bios"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "graphics1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "sound1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "cdrom1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "pad1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "net1"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "SwitchImage"); + gtk_widget_set_sensitive(widget, UsingIso()); + widget = glade_xml_get_widget(xml, "toolbutton_switchimage"); + gtk_widget_set_sensitive(widget, UsingIso()); + widget = glade_xml_get_widget(xml, "toolbutton_graphics"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "toolbutton_sound"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "toolbutton_cdrom"); + gtk_widget_set_sensitive(widget, FALSE); + widget = glade_xml_get_widget(xml, "toolbutton_controllers"); + gtk_widget_set_sensitive(widget, FALSE); + + widget = glade_xml_get_widget(xml, "statusbar"); + gtk_statusbar_pop(GTK_STATUSBAR(widget), 1); + gtk_statusbar_push(GTK_STATUSBAR(widget), 1, _("Emulation Paused.")); + } +} + +int match(const char *string, char *pattern) { + int status; + regex_t re; + + if (regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB) != 0) { + return 0; + } + status = regexec(&re, string, (size_t) 0, NULL, 0); + regfree(&re); + if (status != 0) { + return 0; + } + + return 1; +} + +gchar* get_state_filename(int i) { + gchar *state_filename; + char SStateFile[64]; + char trimlabel[33]; + int j; + + strncpy(trimlabel, CdromLabel, 32); + trimlabel[32] = 0; + for (j = 31; j >= 0; j--) + if (trimlabel[j] == ' ') + trimlabel[j] = 0; + else + continue; + + sprintf(SStateFile, "%.32s-%.9s.%3.3d", trimlabel, CdromId, i); + state_filename = g_build_filename (getenv("HOME"), STATES_DIR, SStateFile, NULL); + + return state_filename; +} + +void UpdateMenuSlots() { + gchar *str; + int i; + + for (i = 0; i < MAX_SLOTS; i++) { + str = get_state_filename (i); + Slots[i] = CheckState(str); + g_free (str); + } +} + +void StartGui() { + GladeXML *xml; + GtkWidget *widget; + + /* If a plugin fails, the Window is not NULL, but is not initialised, + so the following causes a segfault + if (Window != NULL) { + gtk_window_present (GTK_WINDOW (Window)); + return; + }*/ + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "MainWindow", NULL); + + if (!xml) { + g_warning("We could not load the interface!"); + return; + } + + Window = glade_xml_get_widget(xml, "MainWindow"); + gtk_window_set_title(GTK_WINDOW(Window), "PCSX"); + gtk_window_set_icon_from_file(GTK_WINDOW(Window), PIXMAPDIR "pcsx-icon.png", NULL); + gtk_window_set_default_icon_from_file(PIXMAPDIR "pcsx-icon.png", NULL); + ResetMenuSlots(xml); + + // Set up callbacks + g_signal_connect_data(GTK_OBJECT(Window), "delete-event", + GTK_SIGNAL_FUNC(OnDestroy), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); + + // File menu + widget = glade_xml_get_widget(xml, "RunCd"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnFile_RunCd), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "RunBios"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnFile_RunBios), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "RunExe"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnFile_RunExe), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "RunImage"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnFile_RunImage), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "exit2"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnFile_Exit), NULL, NULL, G_CONNECT_AFTER); + + // States + widget = glade_xml_get_widget(xml, "GtkMenuItem_LoadSlot1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load), (gpointer) 0, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_LoadSlot2"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load), (gpointer) 1, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_LoadSlot3"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load), (gpointer) 2, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_LoadSlot4"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load), (gpointer) 3, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_LoadSlot5"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load), (gpointer) 4, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "other1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_load_other), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkMenuItem_SaveSlot1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save), (gpointer) 0, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_SaveSlot2"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save), (gpointer) 1, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_SaveSlot3"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save), (gpointer) 2, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_SaveSlot4"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save), (gpointer) 3, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "GtkMenuItem_SaveSlot5"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save), (gpointer) 4, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "other2"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(on_states_save_other), NULL, NULL, G_CONNECT_AFTER); + + // Emulation menu + widget = glade_xml_get_widget(xml, "run1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnEmu_Run), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "reset1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnEmu_Reset), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "SwitchImage"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnEmu_SwitchImage), NULL, NULL, G_CONNECT_AFTER); + + // Configuration menu + widget = glade_xml_get_widget(xml, "plugins_bios"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(ConfigurePlugins), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "graphics1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Graphics), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "sound1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Sound), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "cdrom1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_CdRom), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "pad1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Pad), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "cpu1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Cpu), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "memory_cards1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Mcds), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "net1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnConf_Net), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "memorydump1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(RunDebugMemoryDialog), NULL, NULL, G_CONNECT_AFTER); + + // Cheat menu + widget = glade_xml_get_widget(xml, "browse1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(RunCheatListDialog), NULL, NULL, G_CONNECT_AFTER); + widget = glade_xml_get_widget(xml, "search1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(RunCheatSearchDialog), NULL, NULL, G_CONNECT_AFTER); + + // Help menu + widget = glade_xml_get_widget(xml, "about_pcsx1"); + g_signal_connect_data(GTK_OBJECT(widget), "activate", + GTK_SIGNAL_FUNC(OnHelp_About), NULL, NULL, G_CONNECT_AFTER); + + // Toolbar + widget = glade_xml_get_widget(xml, "toolbutton_runcd"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnFile_RunCd), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_runimage"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnFile_RunImage), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_run"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnEmu_Run), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_switchimage"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnEmu_SwitchImage), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_memcards"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConf_Mcds), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_graphics"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConf_Graphics), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_sound"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConf_Sound), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_cdrom"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConf_CdRom), NULL, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "toolbutton_controllers"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnConf_Pad), NULL, NULL, G_CONNECT_AFTER); + + gtk_main(); +} + +void OnDestroy() { + if (!destroy) OnFile_Exit(); +} + +void destroy_main_window () { + destroy = 1; + gtk_widget_destroy(Window); + Window = NULL; + destroy = 0; + gtk_main_quit(); + while (gtk_events_pending()) gtk_main_iteration(); +} + +void OnFile_RunExe() { + GtkWidget *file_chooser; + + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + } else { + file_chooser = gtk_file_chooser_dialog_new(_("Select PSX EXE File"), + NULL, GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + + // Add file filters + GtkFileFilter *exefilter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (exefilter, "*.exe"); + gtk_file_filter_add_pattern (exefilter, "*.psx"); + gtk_file_filter_add_pattern (exefilter, "*.cpe"); + gtk_file_filter_add_pattern (exefilter, "*.EXE"); + gtk_file_filter_add_pattern (exefilter, "*.PSX"); + gtk_file_filter_add_pattern (exefilter, "*.CPE"); + gtk_file_filter_set_name (exefilter, _("PlayStation Executable Files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), exefilter); + GtkFileFilter *allfilter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (allfilter, "*"); + gtk_file_filter_set_name (allfilter, _("All Files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), allfilter); + + // Set this to the config object and retain it - maybe LastUsedDir + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), getenv("HOME")); + + if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) { + gchar *file; + + /* TODO Need to validate the file */ + + file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); + + gtk_widget_destroy (file_chooser); + destroy_main_window(); + + SetIsoFile(NULL); + LoadPlugins(); + NetOpened = FALSE; + + if (OpenPlugins() == -1) { + g_free(file); + SysRunGui(); + } else { + SysReset(); + + if (Load(file) == 0) { + g_free(file); + psxCpu->Execute(); + } else { + g_free(file); + ClosePlugins(); + SysErrorMessage(_("Not a valid PSX file"), _("The file does not appear to be a valid Playstation executable")); + SysRunGui(); + } + } + } else + gtk_widget_destroy(file_chooser); + } +} + +void OnFile_RunCd() { + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + destroy_main_window(); + + SetIsoFile(NULL); + LoadPlugins(); + NetOpened = FALSE; + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + SysReset(); + + if (CheckCdrom() == -1) { + /* Only check the CD if we are starting the console with a CD */ + ClosePlugins(); + SysErrorMessage (_("CD ROM failed"), _("The CD does not appear to be a valid Playstation CD")); + SysRunGui(); + return; + } + + // Read main executable directly from CDRom and start it + if (LoadCdrom() == -1) { + ClosePlugins(); + SysErrorMessage(_("Could not load CD-ROM!"), _("The CD-ROM could not be loaded")); + SysRunGui(); + } + + psxCpu->Execute(); +} + +void OnFile_RunBios() { + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + if (strcmp(Config.Bios, "HLE") == 0) { + SysErrorMessage (_("Could not run BIOS"), _("Running BIOS is not supported with Internal HLE BIOS.")); + return; + } + + destroy_main_window(); + + SetIsoFile(NULL); + LoadPlugins(); + NetOpened = FALSE; + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + SysReset(); + + CdromId[0] = '\0'; + CdromLabel[0] = '\0'; + + psxCpu->Execute(); +} + +static gchar *Open_Iso_Proc() { + GtkWidget *chooser; + gchar *filename; + GtkFileFilter *psxfilter, *allfilter; + static char current_folder[MAXPATHLEN] = ""; + + chooser = gtk_file_chooser_dialog_new (_("Open PSX Disc Image File"), + NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + if (current_folder[0] == '\0') { + strcpy(current_folder, getenv("HOME")); + } + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (chooser), current_folder); + + psxfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(psxfilter, "*.bin"); + gtk_file_filter_add_pattern(psxfilter, "*.img"); + gtk_file_filter_add_pattern(psxfilter, "*.mdf"); + gtk_file_filter_add_pattern(psxfilter, "*.iso"); + gtk_file_filter_add_pattern(psxfilter, "*.BIN"); + gtk_file_filter_add_pattern(psxfilter, "*.IMG"); + gtk_file_filter_add_pattern(psxfilter, "*.MDF"); + gtk_file_filter_add_pattern(psxfilter, "*.ISO"); + gtk_file_filter_set_name(psxfilter, _("PSX Image Files (*.bin, *.img, *.mdf, *.iso)")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (chooser), psxfilter); + + allfilter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(allfilter, "*"); + gtk_file_filter_set_name(allfilter, _("All Files")); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (chooser), allfilter); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { + gchar *path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(chooser)); + strcpy(current_folder, path); + g_free(path); + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser)); + gtk_widget_destroy(GTK_WIDGET(chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + return filename; + } else { + gtk_widget_destroy (GTK_WIDGET(chooser)); + while (gtk_events_pending()) gtk_main_iteration(); + return NULL; + } +} + +void OnFile_RunImage() { + gchar *filename; + + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + filename = Open_Iso_Proc(); + if (filename == NULL) { + return; + } + + destroy_main_window(); + + SetIsoFile(filename); + g_free(filename); + + LoadPlugins(); + NetOpened = FALSE; + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + SysReset(); + + if (CheckCdrom() == -1) { + // Only check the CD if we are starting the console with a CD + ClosePlugins(); + SysErrorMessage (_("CD ROM failed"), _("The CD does not appear to be a valid Playstation CD")); + SysRunGui(); + return; + } + + // Read main executable directly from CDRom and start it + if (LoadCdrom() == -1) { + ClosePlugins(); + SysErrorMessage(_("Could not load CD-ROM!"), _("The CD-ROM could not be loaded")); + SysRunGui(); + } + + psxCpu->Execute(); +} + +void OnEmu_Run() { + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + destroy_main_window(); + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + CheatSearchBackupMemory(); + psxCpu->Execute(); +} + +void OnEmu_Reset() { + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + destroy_main_window(); + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + SysReset(); + + if (CheckCdrom() != -1) { + LoadCdrom(); + } + + psxCpu->Execute(); +} + +void OnEmu_SwitchImage() { + gchar *filename; + + if (plugins_configured() == FALSE) { + ConfigurePlugins(); + return; + } + + filename = Open_Iso_Proc(); + if (filename == NULL) { + return; + } + + destroy_main_window(); + + SetIsoFile(filename); + g_free(filename); + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + + SetCdOpenCaseTime(time(NULL) + 2); + + CheatSearchBackupMemory(); + psxCpu->Execute(); +} + +void OnFile_Exit() { + DIR *dir; + struct dirent *ent; + void *Handle; + gchar *plugin = NULL; + gchar *dotdir; + + dotdir = g_build_filename(getenv("HOME"), PLUGINS_DIR, NULL); + + // with this the problem with plugins that are linked with the pthread + // library is solved + + dir = opendir(dotdir); + if (dir != NULL) { + while ((ent = readdir(dir)) != NULL) { + plugin = g_build_filename(dotdir, ent->d_name, NULL); + + if (strstr(plugin, ".so") == NULL && strstr(plugin, ".dylib") == NULL) + continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) + continue; + + g_free(plugin); + } + } + g_free(dotdir); + + bind_textdomain_codeset(PACKAGE_NAME, ""); + if (UseGui) + gtk_main_quit(); + SysClose(); + if (UseGui) + gtk_exit (0); + else + exit(0); +} + +void state_load(gchar *state_filename) { + int ret; + char Text[MAXPATHLEN + 20]; + FILE *fp; + + // check if the state file actually exists + fp = fopen(state_filename, "rb"); + if (fp == NULL) { + // file does not exist + return; + } + + fclose(fp); + + // If the window exists, then we are loading the state from within + // within the PCSX GUI. We need to initialise the plugins first + if (Window) { + destroy_main_window(); + + if (OpenPlugins() == -1) { + SysRunGui(); + return; + } + } + + ret = CheckState(state_filename); + + if (ret == 0) { + SysReset(); + ret = LoadState(state_filename); + } + + if (ret == 0) { + // Check the CD-ROM is valid + if (CheckCdrom() == -1) { + ClosePlugins(); + SysRunGui(); + return; + } + + sprintf(Text, _("Loaded state %s."), state_filename); + GPU_displayText(Text); + } else { + sprintf(Text, _("Error loading state %s!"), state_filename); + GPU_displayText(Text); + } +} + +void state_save(gchar *state_filename) { + char Text[MAXPATHLEN + 20]; + + GPU_updateLace(); + + if (SaveState(state_filename) == 0) + sprintf(Text, _("Saved state %s."), state_filename); + else + sprintf(Text, _("Error saving state %s!"), state_filename); + + GPU_displayText(Text); +} + +void on_states_load (GtkWidget *widget, gpointer user_data) { + gchar *state_filename; + gint state = (int)user_data; + + state_filename = get_state_filename(state); + + state_load(state_filename); + + g_free(state_filename); + + psxCpu->Execute(); +} + +void on_states_save (GtkWidget *widget, gpointer user_data) { + gchar *state_filename; + gint state = (int)user_data; + + state_filename = get_state_filename(state); + + state_save(state_filename); + + g_free(state_filename); +} + +void on_states_load_other() { + GtkWidget *file_chooser; + gchar *SStateFile; + + SStateFile = g_strconcat(getenv("HOME"), STATES_DIR, NULL); + + file_chooser = gtk_file_chooser_dialog_new(_("Select State File"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (file_chooser), SStateFile); + g_free(SStateFile); + + if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) { + gchar *filename; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)); + gtk_widget_destroy(file_chooser); + + state_load(filename); + + g_free(filename); + + psxCpu->Execute(); + } else + gtk_widget_destroy(file_chooser); +} + +void on_states_save_other() { + GtkWidget *file_chooser; + gchar *SStateFile; + + SStateFile = g_strconcat (getenv("HOME"), STATES_DIR, NULL); + + file_chooser = gtk_file_chooser_dialog_new(_("Select State File"), + NULL, GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_OK, + NULL); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), SStateFile); + g_free(SStateFile); + + if (gtk_dialog_run (GTK_DIALOG(file_chooser)) == GTK_RESPONSE_OK) { + gchar *filename; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); + gtk_widget_destroy(file_chooser); + + state_save(filename); + + g_free(filename); + } + else + gtk_widget_destroy(file_chooser); +} + +void OnHelp_About(GtkWidget *widget, gpointer user_data) { + RunAboutDialog(); +} + +void SysMessage(const char *fmt, ...) { + GtkWidget *Txt, *MsgDlg; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg) - 1] == '\n') + msg[strlen(msg) - 1] = 0; + + if (!UseGui) { + fprintf(stderr, "%s\n", msg); + return; + } + + MsgDlg = gtk_dialog_new_with_buttons(_("Notice"), NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL); + + gtk_window_set_position (GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + + Txt = gtk_label_new (msg); + gtk_label_set_line_wrap(GTK_LABEL(Txt), TRUE); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG(MsgDlg)->vbox), Txt); + + gtk_widget_show (Txt); + gtk_widget_show_all (MsgDlg); + gtk_dialog_run (GTK_DIALOG(MsgDlg)); + gtk_widget_destroy (MsgDlg); +} + +void SysErrorMessage(gchar *primary, gchar *secondary) { + GtkWidget *message_dialog; + if (!UseGui) + printf ("%s - %s\n", primary, secondary); + else { + message_dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + primary, + NULL); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(message_dialog), + secondary); + + gtk_dialog_run(GTK_DIALOG(message_dialog)); + gtk_widget_destroy(message_dialog); + } +} + +void SysInfoMessage(gchar *primary, gchar *secondary) { + GtkWidget *message_dialog; + if (!UseGui) + printf ("%s - %s\n", primary, secondary); + else { + message_dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + primary, + NULL); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(message_dialog), + secondary); + + gtk_dialog_run(GTK_DIALOG(message_dialog)); + gtk_widget_destroy(message_dialog); + } +} diff --git a/gui/Linux.h b/gui/Linux.h new file mode 100644 index 0000000..6f0e0c0 --- /dev/null +++ b/gui/Linux.h @@ -0,0 +1,67 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ + +#include "config.h" + +#include "../libpcsxcore/psxcommon.h" +#include + +#include "Cheat.h" + +#define DEFAULT_MEM_CARD_1 "/.pcsx/memcards/card1.mcd" +#define DEFAULT_MEM_CARD_2 "/.pcsx/memcards/card2.mcd" +#define MEMCARD_DIR "/.pcsx/memcards/" +#define PLUGINS_DIR "/.pcsx/plugins/" +#define PLUGINS_CFG_DIR "/.pcsx/plugins/cfg/" +#define PCSX_DOT_DIR "/.pcsx/" +#define BIOS_DIR "/.pcsx/bios/" +#define STATES_DIR "/.pcsx/sstates/" +#define CHEATS_DIR "/.pcsx/cheats/" +#define PATCHES_DIR "/.pcsx/patches/" + +extern gboolean UseGui; +extern int StatesC; +char cfgfile[MAXPATHLEN]; /* ADB Comment this out - make a local var, or at least use gchar funcs */ +char cfgfile_basename[MAXPATHLEN]; /* ADB Comment this out - make a local var, or at least use gchar funcs */ + +int LoadConfig(); +void SaveConfig(); + +void StartGui(); + +void PADhandleKey(int key); + +void UpdateMenuSlots(); + +gchar* get_state_filename(int i); + +void state_save(gchar *state_filename); +void state_load(gchar *state_filename); + +int match(const char* string, char* pattern); +int plugins_configured(); + +void UpdatePluginsBIOS(); + +void SysErrorMessage(gchar *primary, gchar *secondary); +void SysInfoMessage(gchar *primary, gchar *secondary); + +#endif /* __LINUX_H__ */ diff --git a/gui/LnxMain.c b/gui/LnxMain.c new file mode 100644 index 0000000..8297a91 --- /dev/null +++ b/gui/LnxMain.c @@ -0,0 +1,568 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../libpcsxcore/sio.h" + +#include "Linux.h" +#include "ConfDlg.h" + +#ifdef ENABLE_NLS +#include +#endif + +#include + +enum { + RUN = 0, + RUN_CD, +}; + +gboolean UseGui = TRUE; + +static void CreateMemcard(char *filename, char *conf_mcd) { + gchar *mcd; + struct stat buf; + + mcd = g_build_filename(getenv("HOME"), MEMCARD_DIR, filename, NULL); + + strcpy(conf_mcd, mcd); + + /* Only create a memory card if an existing one does not exist */ + if (stat(mcd, &buf) == -1) { + SysPrintf(_("Creating memory card: %s\n"), mcd); + CreateMcd(mcd); + } + + g_free (mcd); +} + +/* Create a directory under the $HOME directory, if that directory doesn't already exist */ +static void CreateHomeConfigDir(char *directory) { + struct stat buf; + + if (stat(directory, &buf) == -1) { + gchar *dir_name = g_build_filename (getenv("HOME"), directory, NULL); + mkdir(dir_name, S_IRWXU | S_IRWXG); + g_free (dir_name); + } +} + +static void CheckSubDir() { + // make sure that ~/.pcsx exists + CreateHomeConfigDir(PCSX_DOT_DIR); + + CreateHomeConfigDir(BIOS_DIR); + CreateHomeConfigDir(MEMCARD_DIR); + CreateHomeConfigDir(STATES_DIR); + CreateHomeConfigDir(PLUGINS_DIR); + CreateHomeConfigDir(PLUGINS_CFG_DIR); + CreateHomeConfigDir(CHEATS_DIR); + CreateHomeConfigDir(PATCHES_DIR); +} + +static void ScanPlugins(gchar* scandir) { + // scan for plugins and configuration tools + DIR *dir; + struct dirent *ent; + + gchar *linkname; + gchar *filename; + + /* Any plugins found will be symlinked to the following directory */ + dir = opendir(scandir); + if (dir != NULL) { + while ((ent = readdir(dir)) != NULL) { + filename = g_build_filename (scandir, ent->d_name, NULL); + + if (match(filename, ".*\\.so$") == 0 && + match(filename, ".*\\.dylib$") == 0 && + match(filename, "cfg.*") == 0) { + continue; /* Skip this file */ + } else { + /* Create a symlink from this file to the directory ~/.pcsx/plugin */ + linkname = g_build_filename (getenv("HOME"), PLUGINS_DIR, ent->d_name, NULL); + symlink(filename, linkname); + + /* If it's a config tool, make one in the cfg dir as well. + This allows plugins with retarded cfg finding to work :- ) */ + if (match(filename, "cfg.*") == 1) { + linkname = g_build_filename (getenv("HOME"), PLUGINS_CFG_DIR, ent->d_name, NULL); + symlink(filename, linkname); + } + g_free (linkname); + } + g_free (filename); + } + closedir(dir); + } +} + +static void ScanBios(gchar* scandir) { + // scan for bioses + DIR *dir; + struct dirent *ent; + + gchar *linkname; + gchar *filename; + + /* Any bioses found will be symlinked to the following directory */ + dir = opendir(scandir); + if (dir != NULL) { + while ((ent = readdir(dir)) != NULL) { + filename = g_build_filename(scandir, ent->d_name, NULL); + + if (match(filename, ".*\\.bin$") == 0 && + match(filename, ".*\\.BIN$") == 0) { + continue; /* Skip this file */ + } else { + /* Create a symlink from this file to the directory ~/.pcsx/plugin */ + linkname = g_build_filename(getenv("HOME"), BIOS_DIR, ent->d_name, NULL); + symlink(filename, linkname); + + g_free(linkname); + } + g_free(filename); + } + closedir(dir); + } +} + +static void CheckSymlinksInPath(char* dotdir) { + DIR *dir; + struct dirent *ent; + struct stat stbuf; + gchar *linkname; + + dir = opendir(dotdir); + if (dir == NULL) { + SysMessage(_("Could not open directory: '%s'\n"), dotdir); + return; + } + + /* Check for any bad links in the directory. If the remote + file no longer exists, remove the link */ + while ((ent = readdir(dir)) != NULL) { + linkname = g_strconcat (dotdir, ent->d_name, NULL); + + if (stat(linkname, &stbuf) == -1) { + /* File link is bad, remove it */ + unlink(linkname); + } + g_free (linkname); + } + closedir(dir); +} + +static void ScanAllPlugins (void) { + gchar *currentdir; + + // scan some default locations to find plugins + ScanPlugins("/usr/lib/games/psemu/"); + ScanPlugins("/usr/lib/games/psemu/lib/"); + ScanPlugins("/usr/lib/games/psemu/config/"); + ScanPlugins("/usr/local/lib/games/psemu/lib/"); + ScanPlugins("/usr/local/lib/games/psemu/config/"); + ScanPlugins("/usr/local/lib/games/psemu/"); + ScanPlugins("/usr/lib64/games/psemu/"); + ScanPlugins("/usr/lib64/games/psemu/lib/"); + ScanPlugins("/usr/lib64/games/psemu/config/"); + ScanPlugins("/usr/local/lib64/games/psemu/lib/"); + ScanPlugins("/usr/local/lib64/games/psemu/config/"); + ScanPlugins("/usr/local/lib64/games/psemu/"); + ScanPlugins("/usr/lib32/games/psemu/"); + ScanPlugins("/usr/lib32/games/psemu/lib/"); + ScanPlugins("/usr/lib32/games/psemu/config/"); + ScanPlugins("/usr/local/lib32/games/psemu/lib/"); + ScanPlugins("/usr/local/lib32/games/psemu/config/"); + ScanPlugins("/usr/local/lib32/games/psemu/"); + ScanPlugins(DEF_PLUGIN_DIR); + ScanPlugins(DEF_PLUGIN_DIR "/lib"); + ScanPlugins(DEF_PLUGIN_DIR "/lib64"); + ScanPlugins(DEF_PLUGIN_DIR "/lib32"); + ScanPlugins(DEF_PLUGIN_DIR "/config"); + + // scan some default locations to find bioses + ScanBios("/usr/lib/games/psemu"); + ScanBios("/usr/lib/games/psemu/bios"); + ScanBios("/usr/lib64/games/psemu"); + ScanBios("/usr/lib64/games/psemu/bios"); + ScanBios("/usr/lib32/games/psemu"); + ScanBios("/usr/lib32/games/psemu/bios"); + ScanBios("/usr/share/psemu"); + ScanBios("/usr/share/psemu/bios"); + ScanBios("/usr/share/pcsx"); + ScanBios("/usr/share/pcsx/bios"); + ScanBios("/usr/local/lib/games/psemu"); + ScanBios("/usr/local/lib/games/psemu/bios"); + ScanBios("/usr/local/lib64/games/psemu"); + ScanBios("/usr/local/lib64/games/psemu/bios"); + ScanBios("/usr/local/lib32/games/psemu"); + ScanBios("/usr/local/lib32/games/psemu/bios"); + ScanBios("/usr/local/share/psemu"); + ScanBios("/usr/local/share/psemu/bios"); + ScanBios("/usr/local/share/pcsx"); + ScanBios("/usr/local/share/pcsx/bios"); + ScanBios(PACKAGE_DATA_DIR); + ScanBios(PSEMU_DATA_DIR); + ScanBios(PACKAGE_DATA_DIR "/bios"); + ScanBios(PSEMU_DATA_DIR "/bios"); + + currentdir = g_strconcat(getenv("HOME"), "/.psemu-plugins/", NULL); + ScanPlugins(currentdir); + g_free(currentdir); + + currentdir = g_strconcat(getenv("HOME"), "/.psemu/", NULL); + ScanPlugins(currentdir); + g_free(currentdir); + + // Check for bad links in ~/.pcsx/plugins/ + currentdir = g_build_filename(getenv("HOME"), PLUGINS_DIR, NULL); + CheckSymlinksInPath(currentdir); + g_free(currentdir); + + // Check for bad links in ~/.pcsx/plugins/cfg + currentdir = g_build_filename(getenv("HOME"), PLUGINS_CFG_DIR, NULL); + CheckSymlinksInPath(currentdir); + g_free(currentdir); + + // Check for bad links in ~/.pcsx/bios + currentdir = g_build_filename(getenv("HOME"), BIOS_DIR, NULL); + CheckSymlinksInPath(currentdir); + g_free(currentdir); +} + +// Set the default plugin name +void set_default_plugin(char *plugin_name, char *conf_plugin_name) { + if (strlen(plugin_name) != 0) { + strcpy(conf_plugin_name, plugin_name); + printf("Picking default plugin: %s\n", plugin_name); + } else + printf("No default plugin could be found for %s\n", conf_plugin_name); +} + +int main(int argc, char *argv[]) { + char file[MAXPATHLEN] = ""; + char path[MAXPATHLEN]; + int runcd = RUN; + int loadst = 0; + int i; + +#ifdef ENABLE_NLS + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); +#endif + + // what is the name of the config file? + // it may be redefined by -cfg on the command line + strcpy(cfgfile_basename, "pcsx.cfg"); + + // read command line options + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-runcd")) runcd = RUN_CD; + else if (!strcmp(argv[i], "-nogui")) UseGui = FALSE; + else if (!strcmp(argv[i], "-psxout")) Config.PsxOut = 1; + else if (!strcmp(argv[i], "-load")) loadst = atol(argv[++i]); + else if (!strcmp(argv[i], "-cfg")) { + if (i+1 >= argc) break; + strncpy(cfgfile_basename, argv[++i], MAXPATHLEN-100); /* TODO buffer overruns */ + printf("Using config file %s.\n", cfgfile_basename); + } + else if (!strcmp(argv[i], "-cdfile")) { + char isofilename[MAXPATHLEN]; + + if (i+1 >= argc) break; + strncpy(isofilename, argv[++i], MAXPATHLEN); + if (isofilename[0] != '/') { + getcwd(path, MAXPATHLEN); + if (strlen(path) + strlen(isofilename) + 1 < MAXPATHLEN) { + strcat(path, "/"); + strcat(path, isofilename); + strcpy(isofilename, path); + } else + isofilename[0] = 0; + } + + SetIsoFile(isofilename); + runcd = RUN_CD; + } + else if (!strcmp(argv[i], "-h") || + !strcmp(argv[i], "-help") || + !strcmp(argv[i], "--help")) { + printf(PACKAGE_STRING "\n"); + printf("%s\n", _( + " pcsx [options] [file]\n" + "\toptions:\n" + "\t-runcd\t\tRuns CD-ROM\n" + "\t-cdfile FILE\tRuns a CD image file\n" + "\t-nogui\t\tDon't open the GTK GUI\n" + "\t-cfg FILE\tLoads desired configuration file (default: ~/.pcsx/pcsx.cfg)\n" + "\t-psxout\t\tEnable PSX output\n" + "\t-load STATENUM\tLoads savestate STATENUM (1-5)\n" + "\t-h -help\tDisplay this message\n" + "\tfile\t\tLoads file\n")); + return 0; + } else { + strncpy(file, argv[i], MAXPATHLEN); + if (file[0] != '/') { + getcwd(path, MAXPATHLEN); + if (strlen(path) + strlen(file) + 1 < MAXPATHLEN) { + strcat(path, "/"); + strcat(path, file); + strcpy(file, path); + } else + file[0] = 0; + } + } + } + + memset(&Config, 0, sizeof(PcsxConfig)); + strcpy(Config.Net, "Disabled"); + + if (UseGui) gtk_init(NULL, NULL); + + CheckSubDir(); + ScanAllPlugins(); + + // try to load config + // if the config file doesn't exist + if (LoadConfig() == -1) { + if (!UseGui) { + printf(_("PCSX cannot be configured without using the GUI -- you should restart without -nogui.\n")); + return 1; + } + + // Uh oh, no config file found, use some defaults + Config.PsxAuto = 1; + + gchar *str_bios_dir = g_strconcat(getenv("HOME"), BIOS_DIR, NULL); + strcpy(Config.BiosDir, str_bios_dir); + g_free(str_bios_dir); + + gchar *str_plugin_dir = g_strconcat(getenv("HOME"), PLUGINS_DIR, NULL); + strcpy(Config.PluginsDir, str_plugin_dir); + g_free(str_plugin_dir); + + gtk_init(NULL, NULL); + + // Update available plugins, but not GUI + UpdatePluginsBIOS(); + + // Pick some defaults, if they're available + set_default_plugin(GpuConfS.plist[0], Config.Gpu); + set_default_plugin(SpuConfS.plist[0], Config.Spu); + set_default_plugin(CdrConfS.plist[0], Config.Cdr); + set_default_plugin(Pad1ConfS.plist[0], Config.Pad1); + set_default_plugin(Pad2ConfS.plist[0], Config.Pad2); + set_default_plugin(BiosConfS.plist[0], Config.Bios); + + // create & load default memcards if they don't exist + CreateMemcard("card1.mcd", Config.Mcd1); + CreateMemcard("card2.mcd", Config.Mcd2); + + LoadMcds(Config.Mcd1, Config.Mcd2); + + SaveConfig(); + } + + gchar *str_patches_dir = g_strconcat(getenv("HOME"), PATCHES_DIR, NULL); + strcpy(Config.PatchesDir, str_patches_dir); + g_free(str_patches_dir); + + // switch to plugin dotdir + // this lets plugins work without modification! + gchar *plugin_default_dir = g_build_filename(getenv("HOME"), PLUGINS_DIR, NULL); + chdir(plugin_default_dir); + g_free(plugin_default_dir); + + if (UseGui) SetIsoFile(NULL); + + if (SysInit() == -1) return 1; + + if (UseGui) { + StartGui(); + } else { + // the following only occurs if the gui isn't started + if (LoadPlugins() == -1) { + SysErrorMessage(_("Error"), _("Failed loading plugins!")); + return 1; + } + + if (OpenPlugins() == -1 || plugins_configured() == FALSE) { + return 1; + } + + SysReset(); + CheckCdrom(); + + if (file[0] != '\0') { + Load(file); + } else { + if (runcd == RUN_CD) { + if (LoadCdrom() == -1) { + ClosePlugins(); + printf(_("Could not load CD-ROM!\n")); + return -1; + } + } + } + + // If a state has been specified, then load that + if (loadst) { + StatesC = loadst - 1; + gchar *state_filename = get_state_filename(StatesC); + LoadState(state_filename); + g_free(state_filename); + } + + psxCpu->Execute(); + } + + return 0; +} + +int SysInit() { +#ifdef EMU_LOG +#ifndef LOG_STDOUT + emuLog = fopen("emuLog.txt","wb"); +#else + emuLog = stdout; +#endif + setvbuf(emuLog, NULL, _IONBF, 0); +#endif + + if (EmuInit() == -1) { + printf(_("PSX emulator couldn't be initialized.\n")); + return -1; + } + + LoadMcds(Config.Mcd1, Config.Mcd2); /* TODO Do we need to have this here, or in the calling main() function?? */ + + if (Config.Debug) { + StartDebugger(); + } + + return 0; +} + +void SysReset() { + EmuReset(); +} + +void SysClose() { + EmuShutdown(); + ReleasePlugins(); + + StopDebugger(); + + if (emuLog != NULL) fclose(emuLog); +} + +void SysPrintf(const char *fmt, ...) { + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (Config.PsxOut) { + static char linestart = 1; + int l = strlen(msg); + + printf(linestart ? " * %s" : "%s", msg); + + if (l > 0 && msg[l - 1] == '\n') { + linestart = 1; + } else { + linestart = 0; + } + } + +#ifdef EMU_LOG +#ifndef LOG_STDOUT + fprintf(emuLog, "%s", msg); +#endif +#endif +} + +void *SysLoadLibrary(const char *lib) { + return dlopen(lib, RTLD_NOW); +} + +void *SysLoadSym(void *lib, const char *sym) { + return dlsym(lib, sym); +} + +const char *SysLibError() { + return dlerror(); +} + +void SysCloseLibrary(void *lib) { + dlclose(lib); +} + +static void SysDisableScreenSaver() { + static time_t fake_key_timer = 0; + static char first_time = 1, has_test_ext = 0, t = 1; + Display *display; + extern unsigned long gpuDisp; + + display = (Display *)gpuDisp; + + if (first_time) { + // check if xtest is available + int a, b, c, d; + has_test_ext = XTestQueryExtension(display, &a, &b, &c, &d); + + first_time = 0; + } + + if (has_test_ext && fake_key_timer < time(NULL)) { + XTestFakeRelativeMotionEvent(display, t *= -1, 0, 0); + fake_key_timer = time(NULL) + 55; + } +} + +void SysUpdate() { + PADhandleKey(PAD1_keypressed()); + PADhandleKey(PAD2_keypressed()); + + SysDisableScreenSaver(); +} + +/* ADB TODO Replace RunGui() with StartGui ()*/ +void SysRunGui() { + StartGui(); +} diff --git a/gui/Makefile.am b/gui/Makefile.am new file mode 100644 index 0000000..50e9e8f --- /dev/null +++ b/gui/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -DPACKAGE_DATA_DIR=\"${datadir}/pcsx/\" \ + -DPIXMAPDIR=\"${datadir}/pixmaps/\" \ + -DLOCALE_DIR=\"${datadir}/locale/\" \ + $(GTK2_CFLAGS) $(GLADE2_CFLAGS) \ + -I$(top_srcdir)/libpcsxcore -I$(top_srcdir)/include \ + -DPSEMU_DATA_DIR=\"${datadir}/psemu\" \ + -DDEF_PLUGIN_DIR=\"${libdir}/games/psemu\" + +bin_PROGRAMS = pcsx + +pcsx_SOURCES = \ + LnxMain.c \ + Plugin.c \ + Config.c \ + Gtk2Gui.c \ + MemcardDlg.c \ + ConfDlg.c \ + Cheat.c \ + DebugMemory.c \ + AboutDlg.c + +pcsx_LDADD = \ + $(GTK2_LIBS) $(GLADE2_LIBS) -lpthread -lz -lm -lXext -lXtst \ + ../libpcsxcore/libpcsxcore.a diff --git a/gui/Makefile.in b/gui/Makefile.in new file mode 100644 index 0000000..53ee8c0 --- /dev/null +++ b/gui/Makefile.in @@ -0,0 +1,538 @@ +# Makefile.in generated by automake 1.10.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = pcsx$(EXEEXT) +subdir = gui +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_pcsx_OBJECTS = LnxMain.$(OBJEXT) Plugin.$(OBJEXT) Config.$(OBJEXT) \ + Gtk2Gui.$(OBJEXT) MemcardDlg.$(OBJEXT) ConfDlg.$(OBJEXT) \ + Cheat.$(OBJEXT) DebugMemory.$(OBJEXT) AboutDlg.$(OBJEXT) +pcsx_OBJECTS = $(am_pcsx_OBJECTS) +am__DEPENDENCIES_1 = +pcsx_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + ../libpcsxcore/libpcsxcore.a +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(pcsx_SOURCES) +DIST_SOURCES = $(pcsx_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLADE2_CFLAGS = @GLADE2_CFLAGS@ +GLADE2_LIBS = @GLADE2_LIBS@ +GLIB2_CFLAGS = @GLIB2_CFLAGS@ +GLIB2_LIBS = @GLIB2_LIBS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +GTK2_CFLAGS = @GTK2_CFLAGS@ +GTK2_LIBS = @GTK2_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@ +LIBCDIO_LIBS = @LIBCDIO_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NASM = @NASM@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PEOPSXGL = @PEOPSXGL@ +PKG_CONFIG = @PKG_CONFIG@ +POSUB = @POSUB@ +PULSEAUDIO_CFLAGS = @PULSEAUDIO_CFLAGS@ +PULSEAUDIO_LIBS = @PULSEAUDIO_LIBS@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -DPACKAGE_DATA_DIR=\"${datadir}/pcsx/\" \ + -DPIXMAPDIR=\"${datadir}/pixmaps/\" \ + -DLOCALE_DIR=\"${datadir}/locale/\" \ + $(GTK2_CFLAGS) $(GLADE2_CFLAGS) \ + -I$(top_srcdir)/libpcsxcore -I$(top_srcdir)/include \ + -DPSEMU_DATA_DIR=\"${datadir}/psemu\" \ + -DDEF_PLUGIN_DIR=\"${libdir}/games/psemu\" + +pcsx_SOURCES = \ + LnxMain.c \ + Plugin.c \ + Config.c \ + Gtk2Gui.c \ + MemcardDlg.c \ + ConfDlg.c \ + Cheat.c \ + DebugMemory.c \ + AboutDlg.c + +pcsx_LDADD = \ + $(GTK2_LIBS) $(GLADE2_LIBS) -lpthread -lz -lm -lXext -lXtst \ + ../libpcsxcore/libpcsxcore.a + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gui/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu gui/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +pcsx$(EXEEXT): $(pcsx_OBJECTS) $(pcsx_DEPENDENCIES) + @rm -f pcsx$(EXEEXT) + $(LINK) $(pcsx_OBJECTS) $(pcsx_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AboutDlg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cheat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConfDlg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Config.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DebugMemory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Gtk2Gui.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LnxMain.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemcardDlg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Plugin.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gui/MemcardDlg.c b/gui/MemcardDlg.c new file mode 100644 index 0000000..31ec692 --- /dev/null +++ b/gui/MemcardDlg.c @@ -0,0 +1,755 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Linux.h" +#include "../libpcsxcore/sio.h" + +#define MAX_MEMCARD_BLOCKS 15 + +static gboolean quit; +static unsigned int currentIcon; + +McdBlock Blocks[2][MAX_MEMCARD_BLOCKS]; // Assuming 2 cards, 15 blocks? +int IconC[2][MAX_MEMCARD_BLOCKS]; +enum { + CL_ICON, + CL_TITLE, + CL_STAT, + CL_ID, + CL_NAME, + NUM_CL +}; + +GtkWidget *GtkCList_McdList1, *GtkCList_McdList2; + +static void AddColumns(GtkTreeView *treeview) { + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + // column for icon + renderer = gtk_cell_renderer_pixbuf_new (); + column = gtk_tree_view_column_new_with_attributes(_("Icon"), + renderer, "pixbuf", CL_ICON, NULL); + gtk_tree_view_append_column(treeview, column); + + // column for title + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Title"), + renderer, "text", CL_TITLE, NULL); + gtk_tree_view_append_column(treeview, column); + + // column for status + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Status"), + renderer, "text", CL_STAT, NULL); + gtk_tree_view_append_column(treeview, column); + + // column for id + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("ID"), + renderer, "text", CL_ID, NULL); + gtk_tree_view_append_column(treeview, column); + + // column for Name + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Name"), + renderer, "text", CL_NAME, NULL); + gtk_tree_view_append_column(treeview, column); +} + +static GdkPixbuf *SetIcon(GtkWidget *dialog, short *icon, int i) { + GdkPixmap *pixmap; + GdkImage *image; + GdkVisual *visual; + GdkPixbuf *pixbuf; + GdkGC *gc; + int x, y, c; + + visual = gdk_window_get_visual(dialog->window); + + if (visual->depth == 8) return NULL; + + image = gdk_image_new(GDK_IMAGE_NORMAL, visual, 32, 32); + + for (y = 0; y < 32; y++) { + for (x = 0; x < 32; x++) { + c = icon[(y>>1) * 16 + (x>>1)]; + c = ((c & 0x001f) << 10) | ((c & 0x7c00) >> 10) | (c & 0x03e0); + if (visual->depth == 16) + c = (c & 0x001f) | ((c & 0x7c00) << 1) | ((c & 0x03e0) << 1); + else if (visual->depth == 24 || visual->depth == 32) + c = ((c & 0x001f) << 3) | ((c & 0x03e0) << 6) | ((c & 0x7c00) << 9); + + gdk_image_put_pixel(image, x, y, c); + } + } + + pixmap = gdk_pixmap_new(dialog->window, 32, 32, visual->depth); + + gc = gdk_gc_new(pixmap); + gdk_draw_image(pixmap, gc, image, 0, 0, 0, 0, 32, 32); + gdk_gc_destroy(gc); + gdk_image_destroy(image); + + pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_PIXMAP (pixmap), NULL, + 0, 0, 0, 0, -1, -1); + g_object_unref(pixmap); + + return pixbuf; +} + +static void LoadListItems(int mcd, GtkWidget *widget) { + int i; + GladeXML *xml; + GtkWidget *List; + GtkWidget *dialog; + GtkListStore *store; + GtkTreeIter iter; + GdkPixbuf *pixbuf; + gchar *title; + + store = gtk_list_store_new(NUM_CL, GDK_TYPE_PIXBUF, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + xml = glade_get_widget_tree(widget); + dialog = glade_xml_get_widget(xml, "McdsDlg"); + + if (mcd == 1) List = glade_xml_get_widget(xml, "GtkCList_McdList1"); + else List = glade_xml_get_widget(xml, "GtkCList_McdList2"); + + for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) { + McdBlock *Info; + gchar *state; + + Info = &Blocks[mcd - 1][i]; + IconC[mcd - 1][i] = 0; + + if ((Info->Flags & 0xF0) == 0xA0) { + if ((Info->Flags & 0xF) >= 1 && + (Info->Flags & 0xF) <= 3) { + state = _("Deleted"); + } else + state = _("Free"); + } else if ((Info->Flags & 0xF0) == 0x50) + state = _("Used"); + else + state = _("Free"); + + pixbuf = SetIcon(dialog, Info->Icon, i + 1); + + gtk_list_store_append(store, &iter); + + title = g_convert(Info->sTitle, strlen(Info->sTitle), "UTF-8", + "Shift-JIS", NULL, NULL, NULL); + + gtk_list_store_set(store, &iter, + CL_ICON, pixbuf, + CL_TITLE, title, + CL_STAT, state, + CL_NAME, Info->Name, + CL_ID, Info->ID, + -1); + + g_free(title); + + g_object_unref(pixbuf); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(List), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(List), TRUE); + gtk_widget_show(List); +} + +static void UpdateFilenameButtons(GtkWidget *widget) { + int i; + GladeXML *xml; + GtkWidget *dialog; + const char *filename; + gchar *p; + + xml = glade_get_widget_tree(widget); + dialog = glade_xml_get_widget(xml, "McdsDlg"); + + for (i = 0; i < 2; i++) { + if (i == 0) { + widget = glade_xml_get_widget(xml, "Mcd1Label"); + filename = Config.Mcd1; + } else { + widget = glade_xml_get_widget(xml, "Mcd2Label"); + filename = Config.Mcd2; + } + + p = g_path_get_basename(filename); + gtk_label_set_text(GTK_LABEL(widget), p); + g_free(p); + } +} + +static void LoadMcdDlg(GtkWidget *widget) { + int i; + + for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) { + GetMcdBlockInfo(1, i + 1, &Blocks[0][i]); + GetMcdBlockInfo(2, i + 1, &Blocks[1][i]); + } + + LoadListItems(1, widget); + LoadListItems(2, widget); + + UpdateFilenameButtons(widget); +} + +static void OnTreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data); + +static void UpdateListItems(int mcd, GtkWidget *widget) { + GladeXML *xml; + GtkWidget *List; + GtkWidget *dialog; + GtkListStore *store; + GtkTreeIter iter; + GdkPixbuf *pixbuf; + short *pIcon; + int i; + gchar *title; + + xml = glade_get_widget_tree(widget); + dialog = glade_xml_get_widget(xml, "McdsDlg"); + + if (mcd == 1) List = glade_xml_get_widget(xml, "GtkCList_McdList1"); + else List = glade_xml_get_widget(xml, "GtkCList_McdList2"); + + store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(List))); + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter); + + for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) { + McdBlock *Info; + gchar *state; + + Info = &Blocks[mcd - 1][i]; + IconC[mcd - 1][i] = 0; + + if ((Info->Flags & 0xF0) == 0xA0) { + if ((Info->Flags & 0xF) >= 1 && + (Info->Flags & 0xF) <= 3) { + state = _("Deleted"); + } else + state = _("Free"); + } else if ((Info->Flags & 0xF0) == 0x50) + state = _("Used"); + else + state = _("Free"); + + if (Info->IconCount > 0) { + pIcon = &Info->Icon[(currentIcon % Info->IconCount) * 16 * 16]; + } else { + pIcon = Info->Icon; + } + + pixbuf = SetIcon(dialog, pIcon, i + 1); + title = g_convert(Info->sTitle, strlen(Info->sTitle), "UTF-8", + "Shift-JIS", NULL, NULL, NULL); + + gtk_list_store_set(store, &iter, + CL_ICON, pixbuf, + CL_TITLE, title, + CL_STAT, state, + CL_NAME, Info->Name, + CL_ID, Info->ID, + -1); + + g_free(title); + + g_object_unref(pixbuf); + gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter); + } + + gtk_widget_show(List); + + OnTreeSelectionChanged(gtk_tree_view_get_selection(GTK_TREE_VIEW(List)), (gpointer)mcd); +} + +static void UpdateMcdDlg(GtkWidget *widget) { + int i; + + for (i = 0; i < MAX_MEMCARD_BLOCKS; i++) { + GetMcdBlockInfo(1, i + 1, &Blocks[0][i]); + GetMcdBlockInfo(2, i + 1, &Blocks[1][i]); + } + + UpdateListItems(1, widget); + UpdateListItems(2, widget); + + UpdateFilenameButtons(widget); +} + +static void OnMcd_Close(GtkDialog *dialog, gint arg1, gpointer user_data) { + quit = TRUE; + SaveConfig(); + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +static void OnMcd_FileChange(GtkWidget *widget, gpointer user_data) { + gint memcard = (int)user_data; + gchar *filename; + GtkWidget *chooser; + + // Ask for name of memory card + chooser = gtk_file_chooser_dialog_new(_("Select A File"), + NULL, GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_OK, + NULL); + + if (memcard == 1) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), Config.Mcd1); + else + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), Config.Mcd2); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { + gtk_widget_hide(chooser); + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); + + if (filename != NULL) { + if (memcard == 1) strncpy(Config.Mcd1, filename, MAXPATHLEN); + else strncpy(Config.Mcd2, filename, MAXPATHLEN); + + LoadMcd(memcard, filename); + LoadMcdDlg(widget); + + g_free(filename); + } + } + + gtk_widget_destroy(chooser); +} + +// format a memory card +static void OnMcd_Format(GtkWidget *widget, gpointer user_data) { + GladeXML *xml; + GtkWidget *message_dialog; + gint result; + char *str; + + gint memcard = (int)user_data; + + message_dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + _("Format this Memory Card?")); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(message_dialog), + _("If you format the memory card, the card will be empty, and any existing data overwritten.")); + gtk_dialog_add_buttons(GTK_DIALOG(message_dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + _("Format card"), GTK_RESPONSE_YES, NULL); + + result = gtk_dialog_run(GTK_DIALOG(message_dialog)); + gtk_widget_destroy(message_dialog); + + if (result == GTK_RESPONSE_YES) { + xml = glade_get_widget_tree(widget); + + if (memcard == 1) str = Config.Mcd1; + else str = Config.Mcd2; + + CreateMcd(str); + LoadMcd(memcard, str); + + UpdateMcdDlg(widget); + } +} + +// create a new, formatted memory card +static void OnMcd_New(GtkWidget *widget, gpointer user_data) { + GtkWidget *chooser; + gchar *path; + + // Ask for name of new memory card + chooser = gtk_file_chooser_dialog_new(_("Create a new Memory Card"), + NULL, GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_OK, + NULL); + + // Card should be put into $HOME/.pcsx/memcards + path = g_build_filename(g_get_home_dir(), ".pcsx", "memcards", NULL); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), path); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), _("New Memory Card.mcd")); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) { + gchar *name; + + gtk_widget_hide(chooser); + name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); + + CreateMcd(name); + + if ((int)user_data == 1) strncpy(Config.Mcd1, name, MAXPATHLEN); + else strncpy(Config.Mcd2, name, MAXPATHLEN); + + LoadMcd((int)user_data, name); + LoadMcdDlg(widget); + + g_free(name); + } + + gtk_widget_destroy(chooser); + g_free(path); +} + +static int copy = 0, copymcd = 0; + +static int GetFreeMemcardSlot(int target_card) { + McdBlock *Info; + gboolean found = FALSE; + + int i = 0; + while (i < 15 && found == FALSE) { + Info = &Blocks[target_card][i]; + if (g_ascii_strcasecmp(Info->Title, "") == 0) { + found = TRUE; + } else { + i++; + } + } + + if (found == TRUE) + return i; + + // no free slots, try to find a deleted one + i = 0; + while (i < 15 && found == FALSE) { + Info = &Blocks[target_card][i]; + if ((Info->Flags & 0xF0) != 0x50) { + found = TRUE; + } else { + i++; + } + } + + if (found == TRUE) + return i; + + return -1; +} + +static void CopyMemcardData(char *from, char *to, gint *i, gchar *str) { + memcpy(to + (*i + 1) * 128, from + (copy + 1) * 128, 128); + SaveMcd((char *)str, to, (*i + 1) * 128, 128); + memcpy(to + (*i + 1) * 1024 * 8, from + (copy+1) * 1024 * 8, 1024 * 8); + SaveMcd((char *)str, to, (*i + 1) * 1024 * 8, 1024 * 8); +} + +static void OnMcd_CopyTo(GtkWidget *widget, gpointer user_data) { + gint mcd = (gint)user_data; + + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gint *i; + GladeXML *xml; + GtkTreeSelection *treesel; + gchar *str; + char *source, *destination; + + int first_free_slot; + + xml = glade_get_widget_tree(widget); + + if (mcd == 1) + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(GtkCList_McdList2)); + else + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(GtkCList_McdList1)); + + // If the item selected is not reported as a 'Free' slot + if (gtk_tree_selection_get_selected(treesel, &model, &iter)) { + path = gtk_tree_model_get_path(model, &iter); + i = gtk_tree_path_get_indices(path); + copy = *i; + copymcd = mcd; + gtk_tree_path_free(path); + } + + // Determine the first free slot in the target memory card + first_free_slot = GetFreeMemcardSlot(mcd - 1); + if (first_free_slot == -1) { + // No free slots available on the destination card + SysErrorMessage(_("No free space on memory card"), + _("There are no free slots available on the target memory card. Please delete a slot first.")); + return; + } + + xml = glade_get_widget_tree(GtkCList_McdList1); + + if (mcd == 1) { + str = Config.Mcd1; + source = Mcd2Data; + destination = Mcd1Data; + } else { + str = Config.Mcd2; + source = Mcd1Data; + destination = Mcd2Data; + } + + CopyMemcardData(source, destination, &first_free_slot, str); + UpdateMcdDlg(widget); +} + +static void OnMemcardDelete(GtkWidget *widget, gpointer user_data) { + McdBlock *Info; + int i, xor = 0, j; + char *data, *ptr; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + gchar *filename; + GladeXML *xml; + gboolean selected; + GtkWidget *tree; + GtkTreeSelection *sel; + + gint memcard = (int)user_data; + + xml = glade_get_widget_tree(widget); + + if (memcard == 1) { + tree = glade_xml_get_widget(xml, "GtkCList_McdList1"); + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree)); + selected = gtk_tree_selection_get_selected (sel, &model, &iter); + data = Mcd1Data; + filename = Config.Mcd1; + } else { + tree = glade_xml_get_widget(xml, "GtkCList_McdList2"); + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree)); + selected = gtk_tree_selection_get_selected(sel, &model, &iter); + data = Mcd2Data; + filename = Config.Mcd2; + } + + if (selected) { + path = gtk_tree_model_get_path(model, &iter); + i = *gtk_tree_path_get_indices(path); + + i++; + ptr = data + i * 128; + Info = &Blocks[memcard - 1][i - 1]; + + if ((Info->Flags & 0xF0) == 0xA0) { + if ((Info->Flags & 0xF) >= 1 && + (Info->Flags & 0xF) <= 3) { // deleted + *ptr = 0x50 | (Info->Flags & 0xF); + } else return; + } else if ((Info->Flags & 0xF0) == 0x50) { // used + *ptr = 0xA0 | (Info->Flags & 0xF); + } else { return; } + + for (j = 0; j < 127; j++) xor ^= *ptr++; + *ptr = xor; + + SaveMcd((char *)filename, data, i * 128, 128); + UpdateMcdDlg(widget); + } +} + +static void OnTreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) { + GladeXML *xml; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path; + + gboolean selected; + int i; + McdBlock b; + + gint memcard = (int)user_data; + + xml = glade_get_widget_tree(GtkCList_McdList1); + selected = gtk_tree_selection_get_selected(selection, &model, &iter); + + if (selected) { + path = gtk_tree_model_get_path(model, &iter); + i = *gtk_tree_path_get_indices(path); + gtk_tree_path_free(path); + + // If a row was selected, and the row is not blank, we can now enable + // some of the disabled widgets + if (memcard == 1) { + GetMcdBlockInfo(1, i + 1, &b); + + if ((b.Flags >= 0xA1 && b.Flags <= 0xA3) || ((b.Flags & 0xF0) == 0x50)) { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), TRUE); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), FALSE); + } + + if ((b.Flags & 0xF0) == 0x50) { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), TRUE); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), FALSE); + } + } else { + GetMcdBlockInfo(2, i + 1, &b); + + if ((b.Flags >= 0xA1 && b.Flags <= 0xA3) || ((b.Flags & 0xF0) == 0x50)) { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), TRUE); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), FALSE); + } + + if ((b.Flags & 0xF0) == 0x50) { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), TRUE); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), FALSE); + } + } + } else { + if (memcard == 1) { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo2"), FALSE); + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete1"), FALSE); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_CopyTo1"), FALSE); + gtk_widget_set_sensitive(glade_xml_get_widget(xml, "GtkButton_Delete2"), FALSE); + } + } +} + +gboolean updateFunc(gpointer data) { + if (quit) return FALSE; + currentIcon++; + UpdateListItems(1, GtkCList_McdList1); + UpdateListItems(2, GtkCList_McdList2); + g_timeout_add(333, updateFunc, 0); + return FALSE; +} + +void OnConf_Mcds() { + GladeXML *xml; + GtkWidget *dialog; + GtkWidget *widget; + GtkTreeSelection *treesel1, *treesel2; + gchar *str; + + xml = glade_xml_new(PACKAGE_DATA_DIR "pcsx.glade2", "McdsDlg", NULL); + + if (!xml) { + g_warning("We could not load the interface!"); + return; + } + + dialog = glade_xml_get_widget(xml, "McdsDlg"); + + gtk_window_set_title(GTK_WINDOW(dialog), _("Memory Card Manager")); + + // Assign default memory cards + if (!strlen(Config.Mcd1)) { + str = g_strconcat(getenv("HOME"), DEFAULT_MEM_CARD_1, NULL); + strcpy(Config.Mcd1, str); + g_free(str); + } + + if (!strlen(Config.Mcd2)) { + str = g_strconcat(getenv("HOME"), DEFAULT_MEM_CARD_2, NULL); + strcpy(Config.Mcd2, str); + g_free(str); + } + + GtkCList_McdList1 = glade_xml_get_widget(xml, "GtkCList_McdList1"); + AddColumns(GTK_TREE_VIEW(GtkCList_McdList1)); + GtkCList_McdList2 = glade_xml_get_widget(xml, "GtkCList_McdList2"); + AddColumns(GTK_TREE_VIEW(GtkCList_McdList2)); + + treesel1 = gtk_tree_view_get_selection(GTK_TREE_VIEW (GtkCList_McdList1)); + gtk_tree_selection_set_mode(treesel1, GTK_SELECTION_SINGLE); + g_signal_connect_data(G_OBJECT(treesel1), "changed", + G_CALLBACK(OnTreeSelectionChanged), + (gpointer)1, NULL, G_CONNECT_AFTER); + + treesel2 = gtk_tree_view_get_selection(GTK_TREE_VIEW (GtkCList_McdList2)); + gtk_tree_selection_set_mode(treesel2, GTK_SELECTION_SINGLE); + g_signal_connect_data(G_OBJECT(treesel2), "changed", + G_CALLBACK(OnTreeSelectionChanged), + (gpointer)2, NULL, G_CONNECT_AFTER); + + LoadMcdDlg(dialog); + + // Setup a handler for when Close or Cancel is clicked + g_signal_connect_data(GTK_OBJECT(dialog), "response", + GTK_SIGNAL_FUNC(OnMcd_Close), xml, (GClosureNotify)g_object_unref, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkButton_Format1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_Format), (gpointer)1, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkButton_Format2"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_Format), (gpointer)2, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "Mcd1Button"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_FileChange), (gpointer)1, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "Mcd2Button"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_FileChange), (gpointer)2, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkButton_New1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_New), (gpointer)1, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkButton_New2"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_New), (gpointer)2, NULL, G_CONNECT_AFTER); + + widget = glade_xml_get_widget(xml, "GtkButton_CopyTo1"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_CopyTo), (gpointer)1, NULL, G_CONNECT_AFTER); + gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + + widget = glade_xml_get_widget(xml, "GtkButton_CopyTo2"); + g_signal_connect_data(GTK_OBJECT(widget), "clicked", + GTK_SIGNAL_FUNC(OnMcd_CopyTo), (gpointer)2, NULL, G_CONNECT_AFTER); + gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + + widget = glade_xml_get_widget(xml, "GtkButton_Delete1"); + g_signal_connect_data (GTK_OBJECT (widget), "clicked", + GTK_SIGNAL_FUNC(OnMemcardDelete), (gpointer)1, NULL, G_CONNECT_AFTER); + gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + + widget = glade_xml_get_widget(xml, "GtkButton_Delete2"); + g_signal_connect_data (GTK_OBJECT (widget), "clicked", + GTK_SIGNAL_FUNC(OnMemcardDelete), (gpointer)2, NULL, G_CONNECT_AFTER); + gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE); + + quit = FALSE; + currentIcon = 0; + + g_timeout_add(1, updateFunc, 0); + + while (gtk_events_pending()) { gtk_main_iteration(); } +} diff --git a/gui/MemcardDlg.h b/gui/MemcardDlg.h new file mode 100644 index 0000000..519283a --- /dev/null +++ b/gui/MemcardDlg.h @@ -0,0 +1,24 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef MEMCARDDLG_H +#define MEMCARDDLG_H + +void OnConf_Mcds(); + +#endif diff --git a/gui/Plugin.c b/gui/Plugin.c new file mode 100644 index 0000000..867fce0 --- /dev/null +++ b/gui/Plugin.c @@ -0,0 +1,390 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "Linux.h" + +#include "../libpcsxcore/plugins.h" +#include "../libpcsxcore/spu.h" +#include "../libpcsxcore/cdriso.h" + +#include "nopic.h" + +#define MAX_SLOTS 5 /* ADB TODO Same as Gtk2Gui.c */ + +void OnFile_Exit(); + +unsigned long gpuDisp; + +int StatesC = 0; +extern int UseGui; +int ShowPic = 0; + +void gpuShowPic() { + gchar *state_filename; + gzFile f; + + if (!ShowPic) { + unsigned char *pMem; + + pMem = (unsigned char *) malloc(128*96*3); + if (pMem == NULL) return; + + state_filename = get_state_filename (StatesC); + + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + + f = gzopen(state_filename, "rb"); + if (f != NULL) { + gzseek(f, 32, SEEK_SET); // skip header + gzread(f, pMem, 128*96*3); + gzclose(f); + } else { + memcpy(pMem, NoPic_Image.pixel_data, 128*96*3); + DrawNumBorPic(pMem, StatesC+1); + } + GPU_showScreenPic(pMem); + + free(pMem); + ShowPic = 1; + g_free (state_filename); + } else { + GPU_showScreenPic(NULL); + ShowPic = 0; + } +} + +void KeyStateSave(int i) { + gchar *state_filename; + + state_filename = get_state_filename (i); + state_save (state_filename); + + g_free (state_filename); +} + +void KeyStateLoad(int i) { + gchar *state_filename; + + state_filename = get_state_filename (i); + state_load (state_filename); + + g_free (state_filename); + + // HACKHACK: prevent crash when using recompiler due to execution not + // returned from compiled code. This WILL cause memory leak, however a + // large amount of refactor is needed for a proper fix. + if (Config.Cpu == CPU_DYNAREC) psxCpu->Execute(); +} + +static short modctrl = 0, modalt = 0; + +/* Handle keyboard keystrokes */ +void PADhandleKey(int key) { + char Text[MAXPATHLEN]; + gchar *state_filename; + + short rel = 0; //released key flag + + if (key == 0) + return; + + if ((key >> 30) & 1) //specific to dfinput (padJoy) + rel = 1; + + if (rel) { + switch (key & ~0x40000000) { + case XK_Alt_L: + case XK_Alt_R: + modalt=0; + break; + case XK_Control_L: + case XK_Control_R: + modctrl=0; + break; + } + return; + } + + switch (key) { + case XK_Alt_L: + case XK_Alt_R: + modalt=1; + break; + case XK_Control_L: + case XK_Control_R: + modctrl=1; + break; + + case XK_0: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(10); + break; + + case XK_1: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(0); + if (modctrl) KeyStateSave(0); + break; + case XK_2: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(1); + if (modctrl) KeyStateSave(1); + break; + case XK_3: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(2); + if (modctrl) KeyStateSave(2); + break; + case XK_4: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(3); + if (modctrl) KeyStateSave(3); + break; + case XK_5: + if (modalt && modctrl) + return; + if (modalt) KeyStateLoad(4); + if (modctrl) KeyStateSave(4); + break; + + case XK_F1: + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + state_filename = get_state_filename (StatesC); + state_save (state_filename); + + g_free (state_filename); + + if (ShowPic) { ShowPic = 0; gpuShowPic(); } + + break; + case XK_F2: + if (StatesC < (MAX_SLOTS - 1)) StatesC++; + else StatesC = 0; + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + if (ShowPic) { ShowPic = 0; gpuShowPic(); } + break; + case XK_F3: + state_filename = get_state_filename (StatesC); + state_load (state_filename); + + g_free (state_filename); + + // HACKHACK: prevent crash when using recompiler due to execution not + // returned from compiled code. This WILL cause memory leak, however a + // large amount of refactor is needed for a proper fix. + if (Config.Cpu == CPU_DYNAREC) psxCpu->Execute(); + + break; + case XK_F4: + gpuShowPic(); + break; + case XK_F5: + Config.Sio ^= 0x1; + if (Config.Sio) + sprintf(Text, _("SIO IRQ Always Enabled")); + else sprintf(Text, _("SIO IRQ Not Always Enabled")); + GPU_displayText(Text); + break; + case XK_F6: + Config.Mdec ^= 0x1; + if (Config.Mdec) + sprintf(Text, _("Black & White Mdecs Only Enabled")); + else sprintf(Text, _("Black & White Mdecs Only Disabled")); + GPU_displayText(Text); + break; + case XK_F7: + Config.Xa ^= 0x1; + if (Config.Xa == 0) + sprintf (Text, _("XA Enabled")); + else sprintf (Text, _("XA Disabled")); + GPU_displayText(Text); + break; + case XK_F8: + GPU_makeSnapshot(); + break; + case XK_F9: + SetCdOpenCaseTime(-1); + break; + case XK_F10: + SetCdOpenCaseTime(0); + break; + case XK_Escape: + // TODO + // the architecture is too broken to actually restart the GUI + // because SysUpdate is called from deep within the actual + // execution of the emulation code + // Fixing this would probably require a complete reworking of + // all functions, so that they return 0 or 1 for success + // that way, execution wouldn't continue + if (CdromId[0] != '\0') + KeyStateSave(10); + ClosePlugins(); + UpdateMenuSlots(); + if (!UseGui) OnFile_Exit(); + StartGui(); + break; + case XK_Return: //0xff0d + if (modalt) //alt-return + //I just made this up: a special sym for fullscreen because the current interface can't handle key mods + //though it can be used in the future as a convention...eg bit 29 for alt, bit 28 for cntl, etc. + GPU_keypressed( (1<<29) | 0xFF0D ); + break; + default: + GPU_keypressed(key); + if (Config.UseNet) NET_keypressed(key); + } +} + +void OnFile_Exit(); + +void SignalExit(int sig) { + ClosePlugins(); + OnFile_Exit(); +} + +#define PARSEPATH(dst, src) \ + ptr = src + strlen(src); \ + while (*ptr != '\\' && ptr != src) ptr--; \ + if (ptr != src) { \ + strcpy(dst, ptr+1); \ + } + +int _OpenPlugins() { + int ret; + + signal(SIGINT, SignalExit); + signal(SIGPIPE, SignalExit); + + GPU_clearDynarec(clearDynarec); + + ret = CDR_open(); + if (ret < 0) { SysMessage(_("Error opening CD-ROM plugin!")); return -1; } + ret = SPU_open(); + if (ret < 0) { SysMessage(_("Error opening SPU plugin!")); return -1; } + SPU_registerCallback(SPUirq); + ret = GPU_open(&gpuDisp, "PCSX", NULL); + if (ret < 0) { SysMessage(_("Error opening GPU plugin!")); return -1; } + ret = PAD1_open(&gpuDisp); + if (ret < 0) { SysMessage(_("Error opening Controller 1 plugin!")); return -1; } + ret = PAD2_open(&gpuDisp); + if (ret < 0) { SysMessage(_("Error opening Controller 2 plugin!")); return -1; } + + if (Config.UseNet && !NetOpened) { + netInfo info; + char path[MAXPATHLEN]; + char dotdir[MAXPATHLEN]; + + strncpy(dotdir, getenv("HOME"), MAXPATHLEN-100); + strcat(dotdir, "/.pcsx/plugins/"); + + strcpy(info.EmuName, "PCSX " PACKAGE_VERSION); + strncpy(info.CdromID, CdromId, 9); + strncpy(info.CdromLabel, CdromLabel, 9); + info.psxMem = psxM; + info.GPU_showScreenPic = GPU_showScreenPic; + info.GPU_displayText = GPU_displayText; + info.GPU_showScreenPic = GPU_showScreenPic; + info.PAD_setSensitive = PAD1_setSensitive; + sprintf(path, "%s%s", Config.BiosDir, Config.Bios); + strcpy(info.BIOSpath, path); + strcpy(info.MCD1path, Config.Mcd1); + strcpy(info.MCD2path, Config.Mcd2); + sprintf(path, "%s%s", dotdir, Config.Gpu); + strcpy(info.GPUpath, path); + sprintf(path, "%s%s", dotdir, Config.Spu); + strcpy(info.SPUpath, path); + sprintf(path, "%s%s", dotdir, Config.Cdr); + strcpy(info.CDRpath, path); + NET_setInfo(&info); + + ret = NET_open(&gpuDisp); + if (ret < 0) { + if (ret == -2) { + // -2 is returned when something in the info + // changed and needs to be synced + char *ptr; + + PARSEPATH(Config.Bios, info.BIOSpath); + PARSEPATH(Config.Gpu, info.GPUpath); + PARSEPATH(Config.Spu, info.SPUpath); + PARSEPATH(Config.Cdr, info.CDRpath); + + strcpy(Config.Mcd1, info.MCD1path); + strcpy(Config.Mcd2, info.MCD2path); + return -2; + } else { + Config.UseNet = FALSE; + } + } else { + if (NET_queryPlayer() == 1) { + if (SendPcsxInfo() == -1) Config.UseNet = FALSE; + } else { + if (RecvPcsxInfo() == -1) Config.UseNet = FALSE; + } + } + NetOpened = TRUE; + } else if (Config.UseNet) { + NET_resume(); + } + + return 0; +} + +int OpenPlugins() { + int ret; + + while ((ret = _OpenPlugins()) == -2) { + ReleasePlugins(); + LoadMcds(Config.Mcd1, Config.Mcd2); + if (LoadPlugins() == -1) return -1; + } + return ret; +} + +void ClosePlugins() { + int ret; + + signal(SIGINT, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + ret = CDR_close(); + if (ret < 0) { SysMessage(_("Error closing CD-ROM plugin!")); return; } + ret = SPU_close(); + if (ret < 0) { SysMessage(_("Error closing SPU plugin!")); return; } + ret = PAD1_close(); + if (ret < 0) { SysMessage(_("Error closing Controller 1 Plugin!")); return; } + ret = PAD2_close(); + if (ret < 0) { SysMessage(_("Error closing Controller 2 plugin!")); return; } + ret = GPU_close(); + if (ret < 0) { SysMessage(_("Error closing GPU plugin!")); return; } + + if (Config.UseNet) { + NET_pause(); + } +} diff --git a/gui/nopic.h b/gui/nopic.h new file mode 100644 index 0000000..553cede --- /dev/null +++ b/gui/nopic.h @@ -0,0 +1,1345 @@ +//////////////////////////////////////////////////////////////////////// +// following code taken from the gpuPeopsSoft +//////////////////////////////////////////////////////////////////////// + +// font 0-9, 24x20 pixels, 1 byte = 4 dots +// 00 = black +// 01 = white +// 10 = red +// 11 = transparent + +unsigned char cFont[10][120]= +{ +// 0 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 1 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 2 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 3 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 4 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x14,0x00,0x00, + 0x80,0x00,0x14,0x14,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 5 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 6 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x15,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 7 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 8 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 9 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x15,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +} +}; + +//////////////////////////////////////////////////////////////////////// + +void PaintPicDot(unsigned char * p,unsigned char c) +{ + + if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black + if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white + if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red + // transparent +} + + ///////////////////////////////////////////////////////////////////// + // generic number/border painter + +void DrawNumBorPic(unsigned char *pMem, int lSelectedSlot) +{ + unsigned char *pf; + int x,y; + int c,v; + + pf=pMem+(103*3); // offset to number rect + + for(y=0;y<20;y++) // loop the number rect pixel + { + for(x=0;x<6;x++) + { + c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot) + v=(c&0xc0)>>6; + PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect + v=(c&0x30)>>4; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=(c&0x0c)>>2; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=c&0x03; + PaintPicDot(pf,(unsigned char)v);pf+=3; + } + pf+=104*3; // next rect y line + } + + pf=pMem; // ptr to first pos in 128x96 pic + for(x=0;x<128;x++) // loop top/bottom line + { + *(pf+(95*128*3))=0x00;*pf++=0x00; + *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red + *(pf+(95*128*3))=0xff;*pf++=0xff; + } + pf=pMem; // ptr to first pos + for(y=0;y<96;y++) // loop left/right line + { + *(pf+(127*3))=0x00;*pf++=0x00; + *(pf+(127*3))=0x00;*pf++=0x00; // paint it red + *(pf+(127*3))=0xff;*pf++=0xff; + pf+=127*3; // offset to next line + } +} + +//////////////////////////////////////////////////////////////////////// + + +/* GIMP RGB C-Source image dump (NoPic.h) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 96 * 3 + 1]; +} NoPic_Image = { + 128, 96, 3, + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0U\0\0" + "U\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8" + "\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251" + "\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0" + "\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\305" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0\214\0\0\34\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\305\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0""8\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\305\0\0q\0\0U\0\0U\0" + "\0U\0\0\214\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\251\0\0\251\0\0\251\0\0\251\0\0\251" + "\0\0\251\0\0\251\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\251\0\0U\0\0U\0\0" + "U\0\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0" + "\0\376\0\0\376\0\0\341\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\341\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\341\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\305" + "\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214" + "\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34" + "\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\0\0\0\251\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0" + "\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376" + "\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\214\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0" + "\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0""8\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0" + "\0\0\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\214\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0" + "\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\214\0\0\341\0\0\376" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0" + "\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0" + "\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376" + "\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\305\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\341\0\0\34\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\305" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\214\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\305\0\0\251\0\0\251\0\0\251\0\0\341\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0" + "U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\251\0\0\251\0\0\251\0\0\251\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0" + "\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0q\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\214\0\0\305\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\214\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0", +}; + -- cgit v1.2.3