mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-02 06:05:32 +00:00
AS3 direct editation
This commit is contained in:
@@ -46,7 +46,7 @@ public abstract class AVM2Item extends GraphTargetItem {
|
||||
}
|
||||
|
||||
protected GraphTextWriter formatProperty(GraphTextWriter writer, GraphTargetItem object, GraphTargetItem propertyName, LocalData localData) throws InterruptedException {
|
||||
boolean empty = false;
|
||||
boolean empty = object instanceof FindPropertyAVM2Item;
|
||||
if (object instanceof LocalRegAVM2Item) {
|
||||
if (((LocalRegAVM2Item) object).computedValue != null) {
|
||||
if (((LocalRegAVM2Item) object).computedValue.getThroughNotCompilable() instanceof FindPropertyAVM2Item) {
|
||||
@@ -55,6 +55,13 @@ public abstract class AVM2Item extends GraphTargetItem {
|
||||
}
|
||||
}
|
||||
|
||||
if(object instanceof FindPropertyAVM2Item){
|
||||
FindPropertyAVM2Item fp=(FindPropertyAVM2Item)object;
|
||||
if(fp.propertyName instanceof FullMultinameAVM2Item){
|
||||
propertyName = fp.propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty) {
|
||||
if (object.getPrecedence() > PRECEDENCE_PRIMARY) {
|
||||
writer.append("(");
|
||||
@@ -70,7 +77,7 @@ public abstract class AVM2Item extends GraphTargetItem {
|
||||
}
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
if (empty) {
|
||||
return propertyName.toString(writer, localData);
|
||||
}
|
||||
if (propertyName instanceof FullMultinameAVM2Item) {
|
||||
|
||||
@@ -2017,6 +2017,7 @@ public class ActionScriptParser {
|
||||
if (s.type != SymbolType.CURLY_OPEN) {
|
||||
expected(s, lexer.yyline(), SymbolType.IDENTIFIER);
|
||||
name = s.value.toString();
|
||||
s = lex();
|
||||
}
|
||||
while (s.type != SymbolType.CURLY_OPEN) {
|
||||
expected(s, lexer.yyline(), SymbolType.DOT);
|
||||
@@ -2097,7 +2098,6 @@ public class ActionScriptParser {
|
||||
}
|
||||
|
||||
public PackageAVM2Item packageFromString(String str, String fileName) throws ParseException, IOException, CompilationException {
|
||||
this.constantPool = constantPool;
|
||||
lexer = new ActionScriptLexer(new StringReader(str));
|
||||
|
||||
PackageAVM2Item ret = parsePackage(fileName);
|
||||
@@ -2132,6 +2132,20 @@ public class ActionScriptParser {
|
||||
this.otherABCs = otherABCs;
|
||||
}
|
||||
|
||||
|
||||
public static void compile(String src, ABC abc, boolean documentClass,String fileName) throws ParseException, IOException, InterruptedException, CompilationException {
|
||||
SWC swc = new SWC(new FileInputStream(Configuration.getPlayerSWC()));
|
||||
SWF swf = new SWF(swc.getSWF("library.swf"), true);
|
||||
List<ABC> playerABCs = new ArrayList<>();
|
||||
for (Tag t : swf.tags) {
|
||||
if (t instanceof ABCContainerTag) {
|
||||
playerABCs.add(((ABCContainerTag) t).getABC());
|
||||
}
|
||||
}
|
||||
ActionScriptParser parser = new ActionScriptParser(abc, playerABCs);
|
||||
parser.addScript(src, documentClass, fileName);
|
||||
}
|
||||
|
||||
public static void compile(String src, String dst) {
|
||||
System.err.println("WARNING: AS3 compiler is not finished yet. This is only used for debuggging!");
|
||||
try {
|
||||
|
||||
@@ -96,7 +96,11 @@ public abstract class Trait implements Serializable {
|
||||
}
|
||||
}
|
||||
if (isStatic) {
|
||||
ret += " static";
|
||||
if((this instanceof TraitSlotConst)&&((TraitSlotConst)this).isNamespace()){
|
||||
//static is automatic
|
||||
}else{
|
||||
ret += " static";
|
||||
}
|
||||
}
|
||||
if ((kindFlags & ATTR_Final) > 0) {
|
||||
if (!isStatic) {
|
||||
|
||||
@@ -74,11 +74,11 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
name = "*";
|
||||
}
|
||||
String newimport = ns.getName(abc.constants);
|
||||
if ((ns.kind != Namespace.KIND_PACKAGE)
|
||||
/*if ((ns.kind != Namespace.KIND_PACKAGE)
|
||||
&& (ns.kind != Namespace.KIND_NAMESPACE)
|
||||
&& (ns.kind != Namespace.KIND_STATIC_PROTECTED)) {
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
/*if (ns.kind == Namespace.KIND_NAMESPACE)*/ {
|
||||
String oldimport = newimport;
|
||||
newimport = null;
|
||||
@@ -118,7 +118,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
}
|
||||
if (ns.kind == Namespace.KIND_PACKAGE) {
|
||||
if (!pkg.equals(ignorePackage)) {
|
||||
imports.add(newimport);
|
||||
if(!pkg.equals("__AS3__.vec")){ //Automatic import
|
||||
imports.add(newimport);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ns.kind == Namespace.KIND_NAMESPACE) {
|
||||
@@ -159,6 +161,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
}
|
||||
if (!imports.contains(newimport)) {
|
||||
String pkg = newimport.substring(0, newimport.lastIndexOf('.'));
|
||||
if(pkg.equals("__AS3__.vec")){ //special case - is imported always
|
||||
return;
|
||||
}
|
||||
if (!pkg.equals(ignorePackage)) {
|
||||
imports.add(newimport);
|
||||
}
|
||||
|
||||
@@ -595,32 +595,42 @@ public class Configuration {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static File getPlayerSWC() {
|
||||
public static File getFlashLibPath() {
|
||||
try {
|
||||
String home = getFFDecHome();
|
||||
File libsdir = new File(home + "flashlib");
|
||||
if (libsdir.exists()) {
|
||||
File libs[] = libsdir.listFiles(new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().startsWith("playerglobal");
|
||||
}
|
||||
});
|
||||
List<String> libnames = new ArrayList<>();
|
||||
for (File f : libs) {
|
||||
libnames.add(f.getName());
|
||||
}
|
||||
Collections.sort(libnames);
|
||||
if (!libnames.isEmpty()) {
|
||||
return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (!libsdir.exists()) {
|
||||
libsdir.mkdirs();
|
||||
}
|
||||
return libsdir;
|
||||
} catch (IOException ex) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static File getPlayerSWC() {
|
||||
File libsdir = getFlashLibPath();
|
||||
if (libsdir!=null && libsdir.exists()) {
|
||||
File libs[] = libsdir.listFiles(new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().startsWith("playerglobal");
|
||||
}
|
||||
});
|
||||
List<String> libnames = new ArrayList<>();
|
||||
for (File f : libs) {
|
||||
libnames.add(f.getName());
|
||||
}
|
||||
Collections.sort(libnames);
|
||||
if (!libnames.isEmpty()) {
|
||||
return new File(libsdir.getAbsolutePath() + File.separator + libnames.get(libnames.size() - 1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocal0Ins;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScriptParser;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
|
||||
@@ -55,7 +57,10 @@ import com.jpexs.decompiler.flash.gui.abc.tablemodels.UIntTableModel;
|
||||
import com.jpexs.decompiler.flash.helpers.Freed;
|
||||
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.SymbolClassTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.treenodes.TreeNode;
|
||||
import com.jpexs.decompiler.graph.CompilationException;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.awt.BorderLayout;
|
||||
@@ -71,6 +76,9 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -90,6 +98,7 @@ import javax.swing.JTable;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.BevelBorder;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.DefaultTableColumnModel;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
@@ -123,6 +132,15 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
|
||||
private NewTraitDialog newTraitDialog;
|
||||
public JLabel scriptNameLabel;
|
||||
|
||||
static final String ACTION_SAVE_DECOMPILED = "SAVEDECOMPILED";
|
||||
static final String ACTION_EDIT_DECOMPILED = "EDITDECOMPILED";
|
||||
static final String ACTION_CANCEL_DECOMPILED = "CANCELDECOMPILED";
|
||||
|
||||
public JLabel experimentalLabel = new JLabel(AppStrings.translate("action.edit.experimental"));
|
||||
public JButton editDecompiledButton = new JButton(AppStrings.translate("button.edit"), View.getIcon("edit16"));
|
||||
public JButton saveDecompiledButton = new JButton(AppStrings.translate("button.save"), View.getIcon("save16"));
|
||||
public JButton cancelDecompiledButton = new JButton(AppStrings.translate("button.cancel"), View.getIcon("cancel16"));
|
||||
|
||||
static final String ACTION_ADD_TRAIT = "ADDTRAIT";
|
||||
|
||||
public boolean search(String txt, boolean ignoreCase, boolean regexp) {
|
||||
@@ -361,10 +379,34 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
|
||||
iconDecPanel.add(scriptNameLabel);
|
||||
iconDecPanel.add(iconsPanel);
|
||||
iconDecPanel.add(decompiledScrollPane);
|
||||
|
||||
JPanel decButtonsPan = new JPanel(new FlowLayout());
|
||||
decButtonsPan.setBorder(new BevelBorder(BevelBorder.RAISED));
|
||||
decButtonsPan.add(editDecompiledButton);
|
||||
decButtonsPan.add(experimentalLabel);
|
||||
decButtonsPan.add(saveDecompiledButton);
|
||||
decButtonsPan.add(cancelDecompiledButton);
|
||||
|
||||
editDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
|
||||
saveDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
|
||||
cancelDecompiledButton.setMargin(new Insets(3, 3, 3, 10));
|
||||
|
||||
saveDecompiledButton.addActionListener(this);
|
||||
saveDecompiledButton.setActionCommand(ACTION_SAVE_DECOMPILED);
|
||||
editDecompiledButton.addActionListener(this);
|
||||
editDecompiledButton.setActionCommand(ACTION_EDIT_DECOMPILED);
|
||||
|
||||
cancelDecompiledButton.addActionListener(this);
|
||||
cancelDecompiledButton.setActionCommand(ACTION_CANCEL_DECOMPILED);
|
||||
saveDecompiledButton.setVisible(false);
|
||||
cancelDecompiledButton.setVisible(false);
|
||||
decButtonsPan.setAlignmentX(0);
|
||||
|
||||
|
||||
JPanel decPanel = new JPanel(new BorderLayout());
|
||||
decPanel.add(searchPanel, BorderLayout.NORTH);
|
||||
decPanel.add(iconDecPanel, BorderLayout.CENTER);
|
||||
decPanel.add(decButtonsPan, BorderLayout.SOUTH);
|
||||
detailPanel = new DetailPanel(this);
|
||||
JPanel panB = new JPanel();
|
||||
panB.setLayout(new BorderLayout());
|
||||
@@ -380,7 +422,9 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
|
||||
splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent pce) {
|
||||
Configuration.guiAvm2SplitPaneDividerLocation.set((int) pce.getNewValue());
|
||||
if(!directEditing){
|
||||
Configuration.guiAvm2SplitPaneDividerLocation.set((int) pce.getNewValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
decompiledTextArea.setContentType("text/actionscript");
|
||||
@@ -543,9 +587,124 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
|
||||
searchPanel.showQuickFindDialog(decompiledTextArea);
|
||||
}
|
||||
|
||||
|
||||
public String lastDecompiled = null;
|
||||
public boolean directEditing = false;
|
||||
private int detWidth = 0;
|
||||
private int detsp = 0;
|
||||
|
||||
public void setDecompiledEditMode(boolean val) {
|
||||
if (val) {
|
||||
lastDecompiled = decompiledTextArea.getText();
|
||||
decompiledTextArea.setEditable(true);
|
||||
saveDecompiledButton.setVisible(true);
|
||||
editDecompiledButton.setVisible(false);
|
||||
experimentalLabel.setVisible(false);
|
||||
cancelDecompiledButton.setVisible(true);
|
||||
decompiledTextArea.getCaret().setVisible(true);
|
||||
decLabel.setIcon(View.getIcon("editing16"));
|
||||
directEditing = true;
|
||||
detWidth = detailPanel.getWidth();
|
||||
detsp = splitPane.getDividerLocation();
|
||||
detailPanel.setVisible(false);
|
||||
} else {
|
||||
decompiledTextArea.setText(lastDecompiled);
|
||||
decompiledTextArea.setEditable(false);
|
||||
saveDecompiledButton.setVisible(false);
|
||||
editDecompiledButton.setVisible(true);
|
||||
experimentalLabel.setVisible(true);
|
||||
cancelDecompiledButton.setVisible(false);
|
||||
decompiledTextArea.getCaret().setVisible(true);
|
||||
decLabel.setIcon(null);
|
||||
directEditing = false;
|
||||
detailPanel.setVisible(true);
|
||||
detailPanel.setSize(detailPanel.getHeight(), detWidth);
|
||||
splitPane.setDividerLocation(detsp);
|
||||
}
|
||||
decompiledTextArea.ignoreCarret = directEditing;
|
||||
|
||||
decompiledTextArea.requestFocusInWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
switch (e.getActionCommand()) {
|
||||
case ACTION_EDIT_DECOMPILED:
|
||||
File swc = Configuration.getPlayerSWC();
|
||||
final String adobePage = "http://www.adobe.com/support/flashplayer/downloads.html";
|
||||
if(swc == null){
|
||||
if(View.showConfirmDialog(this, AppStrings.translate("message.action.playerglobal.needed").replace("%adobehomepage%",adobePage),AppStrings.translate("message.action.playerglobal.title"),JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE)==JOptionPane.OK_OPTION){
|
||||
|
||||
java.awt.Desktop desktop = null;
|
||||
if (java.awt.Desktop.isDesktopSupported()) {
|
||||
desktop = java.awt.Desktop.getDesktop();
|
||||
if (desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
|
||||
try {
|
||||
java.net.URI uri = new java.net.URI(adobePage);
|
||||
desktop.browse(uri);
|
||||
} catch (URISyntaxException | IOException ex) {
|
||||
}
|
||||
} else {
|
||||
desktop = null;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
do{
|
||||
ret = View.showConfirmDialog(this, AppStrings.translate("message.action.playerglobal.place").replace("%libpath%", Configuration.getFlashLibPath().getAbsolutePath()),AppStrings.translate("message.action.playerglobal.title"),JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
|
||||
swc = Configuration.getPlayerSWC();
|
||||
}while(ret == JOptionPane.OK_OPTION && swc == null);
|
||||
if(ret == JOptionPane.OK_OPTION){
|
||||
setDecompiledEditMode(true);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
setDecompiledEditMode(true);
|
||||
}
|
||||
break;
|
||||
case ACTION_CANCEL_DECOMPILED:
|
||||
setDecompiledEditMode(false);
|
||||
break;
|
||||
case ACTION_SAVE_DECOMPILED:
|
||||
ScriptPack pack = decompiledTextArea.getScriptLeaf();
|
||||
String scriptName = pack.getPathScriptName()+".as";
|
||||
int oldIndex = pack.scriptIndex;
|
||||
int newIndex = abc.script_info.size();
|
||||
String documentClass = "";
|
||||
loopt:for (Tag t : swf.tags) {
|
||||
if (t instanceof SymbolClassTag) {
|
||||
SymbolClassTag sc = (SymbolClassTag) t;
|
||||
for (int i = 0; i < sc.tags.length; i++) {
|
||||
if (sc.tags[i] == 0) {
|
||||
documentClass = sc.names[i];
|
||||
break loopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean isDocumentClass = documentClass.equals(pack.getPath().toString());
|
||||
|
||||
try {
|
||||
ActionScriptParser.compile(decompiledTextArea.getText(), abc,isDocumentClass, scriptName);
|
||||
//Move newly added script to its position
|
||||
abc.script_info.set(oldIndex, abc.script_info.get(newIndex));
|
||||
abc.script_info.remove(newIndex);
|
||||
((Tag)abc.parentTag).setModified(true);
|
||||
lastDecompiled = decompiledTextArea.getText();
|
||||
decompiledTextArea.setClassIndex(-1);
|
||||
View.showMessageDialog(this, AppStrings.translate("message.action.saved"));
|
||||
setDecompiledEditMode(false);
|
||||
reload();
|
||||
} catch (ParseException ex) {
|
||||
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
decompiledTextArea.gotoLine((int)ex.line);
|
||||
} catch (CompilationException ex) {
|
||||
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
decompiledTextArea.gotoLine((int)ex.line);
|
||||
} catch (IOException|InterruptedException ex) {
|
||||
//ignore
|
||||
}
|
||||
break;
|
||||
case ACTION_ADD_TRAIT:
|
||||
int class_index = decompiledTextArea.getClassIndex();
|
||||
if (class_index < 0) {
|
||||
|
||||
@@ -54,7 +54,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL
|
||||
private ABC abc;
|
||||
private ScriptPack script;
|
||||
public int lastTraitIndex = 0;
|
||||
private boolean ignoreCarret = false;
|
||||
public boolean ignoreCarret = false;
|
||||
private boolean reset = false;
|
||||
private final ABCPanel abcPanel;
|
||||
private int classIndex = -1;
|
||||
|
||||
@@ -739,6 +739,7 @@ public class ActionPanel extends JPanel implements ActionListener, SearchListene
|
||||
} catch (IOException ex) {
|
||||
} catch (ParseException ex) {
|
||||
View.showMessageDialog(this, AppStrings.translate("error.action.save").replace("%error%", ex.text).replace("%line%", "" + ex.line), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
editor.gotoLine((int)ex.line);
|
||||
}
|
||||
break;
|
||||
case ACTION_EDIT_DECOMPILED:
|
||||
|
||||
@@ -464,3 +464,7 @@ error.sound.invalid = Invalid sound.
|
||||
|
||||
button.prev = Previous
|
||||
button.next = Next
|
||||
|
||||
message.action.playerglobal.title = PlayerGlobal library needed
|
||||
message.action.playerglobal.needed = For ActionScript 3 direct editation, a library called "PlayerGlobal.swc" needs to be downloaded from Adobe homepage.\r\n%adobehomepage%\r\nPress OK to go to the download page.
|
||||
message.action.playerglobal.place = Download the library called PlayerGlobal(.swc), and place it to directory\r\n%libpath%\r\n Press OK to continue.
|
||||
@@ -459,4 +459,8 @@ filter.sounds = Podporovan\u00e9 zvukov\u00e9 form\u00e1ty (*.wav, *.mp3)
|
||||
filter.sounds.wav = Wave form\u00e1t (*.wav)
|
||||
filter.sounds.mp3 = MP3 komprimovan\u00fd form\u00e1t (*.mp3)
|
||||
|
||||
error.sound.invalid = Neplatn\u00fd zvuk.
|
||||
error.sound.invalid = Neplatn\u00fd zvuk.
|
||||
|
||||
message.action.playerglobal.title = Vy\u017eadov\u00e1na knihovna PlayerGlobal
|
||||
message.action.playerglobal.needed = Pro p\u0159\u00edmou editaci ActionScriptu 3 je pot\u0159eba knihovna "PlayerGlobal.swc", kterou lze stahnout ze str\u00e1nek Adobe\r\n%adobehomepage%\r\nStiskn\u011bte OK pro p\u0159echod na stahovac\u00ed str\u00e1nku.
|
||||
message.action.playerglobal.place = St\u00e1hn\u011bte knihovnu nazvanou PlayerGlobal(.swc), a um\u00edst\u011bte j\u00ed do adres\u00e1\u0159e\r\n%libpath%\r\n Stiskn\u011bte OK pro pokra\u010dov\u00e1n\u00ed.
|
||||
Reference in New Issue
Block a user