Projects STRLCPY jadx Commits 5ed5ec5f
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/JadxGUI.java
    1 1  package jadx.gui;
    2 2   
    3 3  import jadx.cli.JadxCLIArgs;
     4 +import jadx.gui.ui.MainWindow;
    4 5   
    5 6  import javax.swing.SwingUtilities;
    6 7  import javax.swing.UIManager;
    skipped 12 lines
    19 20   SwingUtilities.invokeLater(new Runnable() {
    20 21   public void run() {
    21 22   JadxWrapper wrapper = new JadxWrapper(jadxArgs);
    22  - MainWindow mainWindow = new MainWindow(wrapper);
    23  - mainWindow.pack();
    24  - mainWindow.setLocationAndPosition();
    25  - mainWindow.setVisible(true);
    26  - mainWindow.setLocationRelativeTo(null);
    27  - mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
     23 + MainWindow window = new MainWindow(wrapper);
     24 + window.pack();
     25 + window.setLocationAndPosition();
     26 + window.setVisible(true);
     27 + window.setLocationRelativeTo(null);
     28 + window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    28 29   
    29 30   if (jadxArgs.getInput().isEmpty()) {
    30  - mainWindow.openFile();
     31 + window.openFile();
    31 32   } else {
    32  - mainWindow.openFile(jadxArgs.getInput().get(0));
     33 + window.openFile(jadxArgs.getInput().get(0));
    33 34   }
    34 35   }
    35 36   });
    skipped 8 lines
  • ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/JadxTextArea.java jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java
    1  -package jadx.gui;
     1 +package jadx.gui.ui;
    2 2   
    3 3  import jadx.api.CodePosition;
    4 4  import jadx.gui.treemodel.JClass;
    5 5   
     6 +import javax.swing.JViewport;
     7 +import javax.swing.SwingUtilities;
    6 8  import javax.swing.event.HyperlinkEvent;
    7 9  import javax.swing.event.HyperlinkListener;
    8 10  import javax.swing.text.BadLocationException;
     11 +import javax.swing.text.Caret;
     12 +import javax.swing.text.DefaultCaret;
    9 13  import java.awt.Color;
     14 +import java.awt.Point;
     15 +import java.awt.Rectangle;
    10 16   
    11 17  import org.fife.ui.rsyntaxtextarea.LinkGenerator;
    12 18  import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
    skipped 5 lines
    18 24  import org.slf4j.Logger;
    19 25  import org.slf4j.LoggerFactory;
    20 26   
    21  -public class JadxTextArea extends RSyntaxTextArea {
    22  - private static final Logger LOG = LoggerFactory.getLogger(JadxTextArea.class);
     27 +class CodeArea extends RSyntaxTextArea {
     28 + private static final Logger LOG = LoggerFactory.getLogger(CodeArea.class);
    23 29   
    24 30   private static final long serialVersionUID = 6312736869579635796L;
    25 31   
    skipped 1 lines
    27 33   private static final Color JUMP_FOREGROUND = new Color(0x785523);
    28 34   private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF);
    29 35   
     36 + private final CodePanel codePanel;
    30 37   private final JClass cls;
    31  - private final MainWindow rootWindow;
    32 38   
    33  - 
    34  - public JadxTextArea(MainWindow mainWindow, JClass cls) {
    35  - this.rootWindow = mainWindow;
    36  - this.cls = cls;
     39 + CodeArea(CodePanel panel) {
     40 + this.codePanel = panel;
     41 + this.cls = panel.getCls();
    37 42   
    38 43   setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
    39 44   SyntaxScheme scheme = getSyntaxScheme();
    skipped 3 lines
    43 48   setBackground(BACKGROUND);
    44 49   setAntiAliasingEnabled(true);
    45 50   setEditable(false);
    46  - getCaret().setVisible(true);
     51 + Caret caret = getCaret();
     52 + if (caret instanceof DefaultCaret) {
     53 + ((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
     54 + }
     55 + caret.setVisible(true);
    47 56   
    48 57   setHyperlinksEnabled(true);
    49 58   CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(cls);
    skipped 32 lines
    82 91   }
    83 92   }
    84 93   
     94 + void scrollToLine(int line) {
     95 + line--;
     96 + if (line < 0) {
     97 + line = 0;
     98 + }
     99 + setCaretAtLine(line);
     100 + centerCurrentLine();
     101 + forceCurrentLineHighlightRepaint();
     102 + }
     103 + 
     104 + public void centerCurrentLine() {
     105 + JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, this);
     106 + if (viewport == null) {
     107 + return;
     108 + }
     109 + try {
     110 + Rectangle r = modelToView(getCaretPosition());
     111 + if (r == null) {
     112 + return;
     113 + }
     114 + int extentHeight = viewport.getExtentSize().height;
     115 + int viewHeight = viewport.getViewSize().height;
     116 + 
     117 + int y = Math.max(0, r.y - (extentHeight / 2));
     118 + y = Math.min(y, viewHeight - extentHeight);
     119 + 
     120 + viewport.setViewPosition(new Point(0, y));
     121 + } catch (BadLocationException e) {
     122 + LOG.debug("Can't center current line", e);
     123 + }
     124 + }
     125 + 
     126 + private void setCaretAtLine(int line) {
     127 + try {
     128 + setCaretPosition(getLineStartOffset(line));
     129 + } catch (BadLocationException e) {
     130 + LOG.debug("Can't scroll to " + line, e);
     131 + }
     132 + }
     133 + 
    85 134   private class CodeLinkGenerator implements LinkGenerator, HyperlinkListener {
    86 135   private final JClass jCls;
    87 136   
    skipped 36 lines
    124 173   if (obj instanceof CodePosition) {
    125 174   CodePosition pos = (CodePosition) obj;
    126 175   JClass cls = new JClass(pos.getJavaClass());
    127  - rootWindow.showCode(cls, pos.getLine());
     176 + codePanel.getCodePanel().showCode(cls, pos.getLine());
    128 177   LOG.debug("Code jump to: {}", pos);
    129 178   }
    130 179   }
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java
     1 +package jadx.gui.ui;
     2 + 
     3 +import jadx.gui.treemodel.JClass;
     4 +import jadx.gui.utils.Utils;
     5 + 
     6 +import javax.swing.AbstractAction;
     7 +import javax.swing.JPanel;
     8 +import javax.swing.KeyStroke;
     9 +import java.awt.BorderLayout;
     10 +import java.awt.event.ActionEvent;
     11 +import java.awt.event.InputEvent;
     12 +import java.awt.event.KeyEvent;
     13 + 
     14 +import org.fife.ui.rtextarea.RTextScrollPane;
     15 + 
     16 +class CodePanel extends JPanel {
     17 + 
     18 + private final TabbedPane codePanel;
     19 + private final JClass jClass;
     20 + private final SearchBar searchBar;
     21 + private final CodeArea codeArea;
     22 + private final RTextScrollPane scrollPane;
     23 + 
     24 + CodePanel(TabbedPane panel, JClass cls) {
     25 + codePanel = panel;
     26 + jClass = cls;
     27 + codeArea = new CodeArea(this);
     28 + searchBar = new SearchBar(codeArea);
     29 + 
     30 + scrollPane = new RTextScrollPane(codeArea);
     31 + scrollPane.setFoldIndicatorEnabled(true);
     32 + 
     33 + setLayout(new BorderLayout());
     34 + add(searchBar, BorderLayout.NORTH);
     35 + add(scrollPane);
     36 + 
     37 + KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
     38 + Utils.addKeyBinding(codeArea, key, "SearchAction", new AbstractAction() {
     39 + @Override
     40 + public void actionPerformed(ActionEvent e) {
     41 + searchBar.toggle();
     42 + }
     43 + });
     44 + }
     45 + 
     46 + TabbedPane getCodePanel() {
     47 + return codePanel;
     48 + }
     49 + 
     50 + JClass getCls() {
     51 + return jClass;
     52 + }
     53 + 
     54 + SearchBar getSearchBar() {
     55 + return searchBar;
     56 + }
     57 + 
     58 + CodeArea getCodeArea() {
     59 + return codeArea;
     60 + }
     61 + 
     62 + RTextScrollPane getScrollPane() {
     63 + return scrollPane;
     64 + }
     65 +}
     66 + 
  • ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/MainWindow.java jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
    1  -package jadx.gui;
     1 +package jadx.gui.ui;
    2 2   
     3 +import jadx.gui.JadxWrapper;
    3 4  import jadx.gui.treemodel.JClass;
    4 5  import jadx.gui.treemodel.JNode;
    5 6  import jadx.gui.treemodel.JRoot;
    6 7  import jadx.gui.utils.NLS;
    7 8  import jadx.gui.utils.Utils;
    8 9   
    9  -import javax.swing.AbstractAction;
    10  -import javax.swing.BorderFactory;
    11 10  import javax.swing.ImageIcon;
    12 11  import javax.swing.JButton;
    13 12  import javax.swing.JFileChooser;
    14 13  import javax.swing.JFrame;
    15  -import javax.swing.JLabel;
    16 14  import javax.swing.JMenu;
    17 15  import javax.swing.JMenuBar;
    18 16  import javax.swing.JMenuItem;
    19 17  import javax.swing.JPanel;
    20 18  import javax.swing.JScrollPane;
    21 19  import javax.swing.JSplitPane;
    22  -import javax.swing.JTabbedPane;
    23  -import javax.swing.JTextArea;
    24 20  import javax.swing.JToggleButton;
    25 21  import javax.swing.JToolBar;
    26 22  import javax.swing.JTree;
    27  -import javax.swing.KeyStroke;
    28 23  import javax.swing.ProgressMonitor;
    29 24  import javax.swing.event.TreeExpansionEvent;
    30 25  import javax.swing.event.TreeWillExpandListener;
    31 26  import javax.swing.filechooser.FileNameExtensionFilter;
    32  -import javax.swing.plaf.basic.BasicButtonUI;
    33  -import javax.swing.text.BadLocationException;
    34 27  import javax.swing.tree.DefaultMutableTreeNode;
    35 28  import javax.swing.tree.DefaultTreeCellRenderer;
    36 29  import javax.swing.tree.DefaultTreeModel;
    skipped 3 lines
    40 33  import java.awt.BorderLayout;
    41 34  import java.awt.Component;
    42 35  import java.awt.DisplayMode;
    43  -import java.awt.FlowLayout;
    44 36  import java.awt.GraphicsDevice;
    45 37  import java.awt.GraphicsEnvironment;
    46 38  import java.awt.event.ActionEvent;
    47 39  import java.awt.event.ActionListener;
    48  -import java.awt.event.InputEvent;
    49 40  import java.awt.event.KeyAdapter;
    50 41  import java.awt.event.KeyEvent;
    51 42  import java.awt.event.MouseAdapter;
    52 43  import java.awt.event.MouseEvent;
    53 44  import java.io.File;
    54  -import java.util.HashMap;
    55  -import java.util.Map;
    56 45   
    57  -import org.fife.ui.rtextarea.RTextScrollPane;
    58 46  import org.slf4j.Logger;
    59 47  import org.slf4j.LoggerFactory;
    60 48   
    skipped 9 lines
    70 58   private static final ImageIcon ICON_OPEN = Utils.openIcon("folder");
    71 59   private static final ImageIcon ICON_SAVE_ALL = Utils.openIcon("disk_multiple");
    72 60   private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross");
    73  - private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed");
    74 61   private static final ImageIcon ICON_FLAT_PKG = Utils.openIcon("empty_logical_package_obj");
    75 62   private static final ImageIcon ICON_SEARCH = Utils.openIcon("magnifier");
    76 63   
    skipped 3 lines
    80 67   
    81 68   private JTree tree;
    82 69   private DefaultTreeModel treeModel;
    83  - 
    84  - private final JTabbedPane tabbedPane = new JTabbedPane();
    85  - private final Map<JClass, Component> openTabs = new HashMap<JClass, Component>();
     70 + private TabbedPane tabbedPane;
    86 71   
    87 72   public MainWindow(JadxWrapper wrapper) {
    88 73   this.wrapper = wrapper;
    skipped 49 lines
    138 123   }
    139 124   }
    140 125   
    141  - private void toggleSearch() {
    142  - SearchBar searchBar = getSearchBar((JPanel) tabbedPane.getSelectedComponent());
    143  - searchBar.toggle();
    144  - }
    145  - 
    146 126   private void treeClickAction() {
    147 127   Object obj = tree.getLastSelectedPathComponent();
    148 128   if (obj instanceof JNode) {
    149 129   JNode node = (JNode) obj;
    150 130   JClass cls = node.getRootClass();
    151 131   if (cls != null) {
    152  - showCode(cls, node.getLine());
     132 + tabbedPane.showCode(cls, node.getLine());
    153 133   }
    154 134   }
    155 135   }
    156 136   
    157  - private JPanel newCodePane(final JClass cls) {
    158  - JadxTextArea textArea = new JadxTextArea(this, cls);
    159  - RTextScrollPane scrollPane = new RTextScrollPane(textArea);
    160  - scrollPane.setFoldIndicatorEnabled(true);
    161  - 
    162  - JPanel textPanel = new JPanel(new BorderLayout());
    163  - SearchBar searchBar = new SearchBar(textArea);
    164  - textPanel.add(searchBar, BorderLayout.NORTH);
    165  - textPanel.add(scrollPane);
    166  - 
    167  - KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
    168  - Utils.addKeyBinding(textArea, key, "SearchAction", new AbstractAction() {
    169  - @Override
    170  - public void actionPerformed(ActionEvent e) {
    171  - toggleSearch();
    172  - }
    173  - });
    174  - return textPanel;
    175  - }
    176  - 
    177  - private SearchBar getSearchBar(JPanel panel) {
    178  - return (SearchBar) panel.getComponent(0);
    179  - }
    180  - 
    181  - private JadxTextArea getTextArea(JPanel panel) {
    182  - RTextScrollPane scrollPane = (RTextScrollPane) panel.getComponent(1);
    183  - return (JadxTextArea) scrollPane.getTextArea();
    184  - }
    185  - 
    186  - void showCode(JClass cls, int line) {
    187  - JPanel panel = (JPanel) openTabs.get(cls);
    188  - if (panel != null) {
    189  - panel = (JPanel) openTabs.get(cls);
    190  - tabbedPane.setSelectedComponent(panel);
    191  - } else {
    192  - panel = newCodePane(cls);
    193  - tabbedPane.add(panel);
    194  - openTabs.put(cls, panel);
    195  - int id = tabbedPane.indexOfComponent(panel);
    196  - tabbedPane.setTabComponentAt(id, makeTabComponent(cls, panel));
    197  - tabbedPane.setSelectedIndex(id);
    198  - }
    199  - JadxTextArea textArea = getTextArea(panel);
    200  - scrollToLine(textArea, line);
    201  - }
    202  - 
    203  - private Component makeTabComponent(final JClass cls, final Component comp) {
    204  - String name = cls.getCls().getFullName();
    205  - JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
    206  - panel.setOpaque(false);
    207  - 
    208  - final JLabel label = new JLabel(name);
    209  - label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
    210  - label.setIcon(cls.getIcon());
    211  - 
    212  - final JButton button = new JButton();
    213  - button.setIcon(ICON_CLOSE_INACTIVE);
    214  - button.setRolloverIcon(ICON_CLOSE);
    215  - button.setRolloverEnabled(true);
    216  - button.setOpaque(false);
    217  - button.setUI(new BasicButtonUI());
    218  - button.setContentAreaFilled(false);
    219  - button.setFocusable(false);
    220  - button.setBorder(null);
    221  - button.setBorderPainted(false);
    222  - button.addActionListener(new ActionListener() {
    223  - @Override
    224  - public void actionPerformed(ActionEvent e) {
    225  - closeCodeTab(cls, comp);
    226  - }
    227  - });
    228  - 
    229  - panel.addMouseListener(new MouseAdapter() {
    230  - @Override
    231  - public void mouseClicked(MouseEvent e) {
    232  - if (e.getButton() == MouseEvent.BUTTON2) {
    233  - closeCodeTab(cls, comp);
    234  - } else {
    235  - // TODO: make correct event delegation to tabbed pane
    236  - tabbedPane.setSelectedComponent(comp);
    237  - }
    238  - }
    239  - });
    240  - 
    241  - panel.add(label);
    242  - panel.add(button);
    243  - panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
    244  - return panel;
    245  - }
    246  - 
    247  - private void closeCodeTab(JClass cls, Component comp) {
    248  - tabbedPane.remove(comp);
    249  - openTabs.remove(cls);
    250  - }
    251  - 
    252  - private void scrollToLine(JTextArea textArea, int line) {
    253  - if (line == 0) {
    254  - line = 1;
    255  - }
    256  - try {
    257  - textArea.setCaretPosition(textArea.getLineStartOffset(line - 1));
    258  - } catch (BadLocationException e) {
    259  - LOG.error("Can't scroll to " + line, e);
    260  - }
     137 + private void toggleSearch() {
     138 + tabbedPane.getSelectedCodePanel().getSearchBar().toggle();
    261 139   }
    262 140   
    263 141   private void initMenuAndToolbar() {
    skipped 132 lines
    396 274   JScrollPane treeScrollPane = new JScrollPane(tree);
    397 275   splitPane.setLeftComponent(treeScrollPane);
    398 276   
    399  - tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
     277 + tabbedPane = new TabbedPane(this);
    400 278   splitPane.setRightComponent(tabbedPane);
    401 279   
    402 280   setContentPane(mainPanel);
    skipped 19 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/SearchBar.java jadx-gui/src/main/java/jadx/gui/ui/SearchBar.java
    1  -package jadx.gui;
     1 +package jadx.gui.ui;
    2 2   
    3 3  import jadx.gui.utils.NLS;
    4 4  import jadx.gui.utils.Utils;
    skipped 15 lines
    20 20  import org.fife.ui.rtextarea.SearchContext;
    21 21  import org.fife.ui.rtextarea.SearchEngine;
    22 22   
    23  -public class SearchBar extends JToolBar {
     23 +class SearchBar extends JToolBar {
    24 24   private static final long serialVersionUID = 1836871286618633003L;
    25 25   
    26 26   private static final Color COLOR_BG_ERROR = new Color(0xFFDFDE);
    skipped 180 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java
     1 +package jadx.gui.ui;
     2 + 
     3 +import jadx.gui.treemodel.JClass;
     4 +import jadx.gui.utils.Utils;
     5 + 
     6 +import javax.swing.BorderFactory;
     7 +import javax.swing.ImageIcon;
     8 +import javax.swing.JButton;
     9 +import javax.swing.JLabel;
     10 +import javax.swing.JPanel;
     11 +import javax.swing.JTabbedPane;
     12 +import javax.swing.plaf.basic.BasicButtonUI;
     13 +import java.awt.Component;
     14 +import java.awt.FlowLayout;
     15 +import java.awt.event.ActionEvent;
     16 +import java.awt.event.ActionListener;
     17 +import java.awt.event.MouseAdapter;
     18 +import java.awt.event.MouseEvent;
     19 +import java.util.HashMap;
     20 +import java.util.Map;
     21 + 
     22 +class TabbedPane extends JTabbedPane {
     23 + 
     24 + private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross");
     25 + private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed");
     26 + 
     27 + private final MainWindow mainWindow;
     28 + private final Map<JClass, CodePanel> openTabs = new HashMap<JClass, CodePanel>();
     29 + 
     30 + TabbedPane(MainWindow window) {
     31 + mainWindow = window;
     32 + 
     33 + setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
     34 + }
     35 + 
     36 + private void addCodePanel(CodePanel codePanel) {
     37 + add(codePanel);
     38 + openTabs.put(codePanel.getCls(), codePanel);
     39 + }
     40 + 
     41 + private void closeCodePanel(CodePanel codePanel) {
     42 + remove(codePanel);
     43 + openTabs.remove(codePanel.getCls());
     44 + }
     45 + 
     46 + void showCode(JClass cls, int line) {
     47 + CodePanel panel = openTabs.get(cls);
     48 + if (panel == null) {
     49 + panel = new CodePanel(this, cls);
     50 + addCodePanel(panel);
     51 + setTabComponentAt(indexOfComponent(panel), makeTabComponent(panel));
     52 + }
     53 + 
     54 + setSelectedComponent(panel);
     55 + CodeArea codeArea = panel.getCodeArea();
     56 + codeArea.scrollToLine(line);
     57 + codeArea.requestFocus();
     58 + }
     59 + 
     60 + private Component makeTabComponent(final CodePanel codePanel) {
     61 + JClass cls = codePanel.getCls();
     62 + String name = cls.getCls().getFullName();
     63 + JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
     64 + panel.setOpaque(false);
     65 + 
     66 + final JLabel label = new JLabel(name);
     67 + label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
     68 + label.setIcon(cls.getIcon());
     69 + 
     70 + final JButton button = new JButton();
     71 + button.setIcon(ICON_CLOSE_INACTIVE);
     72 + button.setRolloverIcon(ICON_CLOSE);
     73 + button.setRolloverEnabled(true);
     74 + button.setOpaque(false);
     75 + button.setUI(new BasicButtonUI());
     76 + button.setContentAreaFilled(false);
     77 + button.setFocusable(false);
     78 + button.setBorder(null);
     79 + button.setBorderPainted(false);
     80 + button.addActionListener(new ActionListener() {
     81 + @Override
     82 + public void actionPerformed(ActionEvent e) {
     83 + closeCodePanel(codePanel);
     84 + }
     85 + });
     86 + 
     87 + panel.addMouseListener(new MouseAdapter() {
     88 + @Override
     89 + public void mouseClicked(MouseEvent e) {
     90 + if (e.getButton() == MouseEvent.BUTTON2) {
     91 + closeCodePanel(codePanel);
     92 + } else {
     93 + // TODO: make correct event delegation to tabbed pane
     94 + setSelectedComponent(codePanel);
     95 + }
     96 + }
     97 + });
     98 + 
     99 + panel.add(label);
     100 + panel.add(button);
     101 + panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
     102 + return panel;
     103 + }
     104 + 
     105 + CodePanel getSelectedCodePanel() {
     106 + return (CodePanel) getSelectedComponent();
     107 + }
     108 + 
     109 + MainWindow getMainWindow() {
     110 + return mainWindow;
     111 + }
     112 +}
     113 + 
Please wait...
Page is in error, reload to recover