execute/open execute a program in c# - c#

Hello so i created a kind of launcher application, but i have a but of a problem when i try to use the launch button it just doesn't do anything here's my code. What i need is a way to select the Arma folder trough the program that you have enterd but when i use the code it doesn't work?
private void iniSetup()
{
//Directory Read
tb_arma3dir.Text = ini.IniReadValue("Directory", "ARMA3");
tb_addondir.Text = ini.IniReadValue("Directory", "ADDON");
}
private void arma2OACheck()
{
string arma3Path = tb_arma3dir.Text;
if (arma3Path.EndsWith(#"\"))
arma3Path = arma3Path.TrimEnd('\'');
if(!File.Exists(arma3Path + "\\ArmA2OA.exe"))
{
a3dir_pic.Source = new BitmapImage(new Uri("./Resources/redX.png", UriKind.Relative));
a2Good = false;
}
else
{
a3dir_pic.Source = new BitmapImage(new Uri("./Resources/greenCheck.png", UriKind.Relative));
a2Good = true;
}
}
private void addonDirCheck()
{
string addonPath = tb_addondir.Text;
if (addonPath.EndsWith(#"\"))
addonPath = addonPath.TrimEnd('\'');
if (!Directory.Exists(addonPath))
{
addondir_pic.Source = new BitmapImage(new Uri("./Resources/redX.png", UriKind.Relative));
addonGood = false;
}
else
{
addondir_pic.Source = new BitmapImage(new Uri("./Resources/greenCheck.png", UriKind.Relative));
addonGood = true;
}
}
private void CompileLaunchParams()
{
string launchStr = "";
// Lauch parameters
launchStr += #"-mod=#TCG" + #" -ip=31.186.251.207" + #" -port=2302" + " -nosplash" + "-world=empty" + "-nosplash";
// Parse game path
string filename = "iniSetup";
// Start game process as administrator
ProcessStartInfo info = new ProcessStartInfo(filename); // what do i use to select the program so it can execute?
info.UseShellExecute = true;
info.Verb = "runas";
info.Arguments = launchStr;
Process.Start(info);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if(a2Good & addonGood ) // if the addon and arma is good it launches
{
CompileLaunchParams();
}
else
{
MessageBox.Show("Not all settings are configured, Please click the gear in the top right to define options!");
}
}

You can try save selected path to field in class like:
private string Arma3Path;
private void arma2OACheck()
{
string path = tb_arma3dir.Text;
if (path.EndsWith(#"\"))
Arma3Path = path.TrimEnd('\'') + "\\ArmA2OA.exe";
if(!File.Exists(Arma3Path))
{
a3dir_pic.Source = new BitmapImage(new Uri("./Resources/redX.png", UriKind.Relative));
a2Good = false;
}
else
{
a3dir_pic.Source = new BitmapImage(new Uri("./Resources/greenCheck.png", UriKind.Relative));
a2Good = true;
}
}
and then use it like
private void CompileLaunchParams()
{
string launchStr = "";
// Lauch parameters
launchStr += #"-mod=#TCG" + #" -ip=31.186.251.207" + #" -port=2302" + " -nosplash" + "-world=empty" + "-nosplash";
// Parse game path
string filename = Arma3Path;
// Start game process as administrator
ProcessStartInfo info = new ProcessStartInfo(filename); // what do i use to select the program so it can execute?
info.UseShellExecute = true;
info.Verb = "runas";
info.Arguments = launchStr;
Process.Start(info);
}

Related

Connect to VPN xamarin android

Hello I am using this code to connect vpn with c# my code can connect and disconnect and create vpn and it working fine but i want use it in xamarin android i do search google but No result
private static string FolderPath => string.Concat(Directory.GetCurrentDirectory(),
"\\VPN");
private void btnConnect_Click(object sender, EventArgs e)
{
if (!Directory.Exists(FolderPath))
Directory.CreateDirectory(FolderPath);
var sb = new StringBuilder();
sb.AppendLine("[VPN]");
sb.AppendLine("MEDIA=rastapi");
sb.AppendLine("Port=VPN2-0");
sb.AppendLine("Device=WAN Miniport (IKEv2)");
sb.AppendLine("DEVICE=vpn");
sb.AppendLine("PhoneNumber=" + txtHost.Text);
File.WriteAllText(FolderPath + "\\VpnConnection.pbk", sb.ToString());
sb = new StringBuilder();
sb.AppendLine("rasdial \"VPN\" " + txtUsrname.Text + " " + txtPassword.Text + " /phonebook:\"" + FolderPath +
"\\VpnConnection.pbk\"");
File.WriteAllText(FolderPath + "\\VpnConnection.bat", sb.ToString());
var newProcess = new Process
{
StartInfo =
{
FileName = FolderPath + "\\VpnConnection.bat",
WindowStyle = ProcessWindowStyle.Normal
}
};
newProcess.Start();
newProcess.WaitForExit();
btnConnect.Enabled = false;
btnDisconnect.Enabled = true;
}
private void btnDisconnect_Click(object sender, EventArgs e)
{
File.WriteAllText(FolderPath + "\\VpnDisconnect.bat", "rasdial /d");
var newProcess = new Process
{
StartInfo =
{
FileName = FolderPath + "\\VpnDisconnect.bat",
WindowStyle = ProcessWindowStyle.Normal
}
};
newProcess.Start();
newProcess.WaitForExit();
btnConnect.Enabled = true;
btnDisconnect.Enabled = false;
}
or I want convert it to xamarin android and
connect or disconnect sorry for my english

C# WPF application capture python script console output

I have been trying for hours to figure out how to do this but I have a python script that was made into an exe so it acts a console application I'm trying to write a GUI wrapper for it using WPF I have it set up to where it does execute the exe with the command arguments but I want to capture the output from the console and display it in a text box and i can not figure it out. I have tried multiple code snippets but it either does nothing, Outputs after the python exe has finished, or locks up the GUI until the python exe finishes then dumps the completed output to the textbox.
Would someone be able to take a look and see if they can help me with this?
public partial class MainWindow : Window
{
//string output = string.Empty;
private static StringBuilder output = new StringBuilder();
private object syncGate = new object();
private Process process;
private bool outputChanged;
public MainWindow()
{
InitializeComponent();
}
private void RB_Mii_Checked(object sender, RoutedEventArgs e)
{
}
//If we click the button we copy the bin file to the work directory
private void btn_SelMiiQR_Click(object sender, RoutedEventArgs e)
{
//Copy the encrypted.bin file to the working directory
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Input.bin (*.bin)|*.bin|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (openFileDialog.ShowDialog() == true)
{
var fileName = openFileDialog.FileName;
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
//If the file exists delete the existing file and copy the newone.
if (System.IO.File.Exists(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName)))
{
System.IO.File.Delete(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
System.IO.File.Copy(fileName, System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
}
//If the button was clicked use the input.bin file and attempt to brute force the movable_sedpart1.bin
private void BTN_MIIBF_Click(object sender, RoutedEventArgs e)
{
//If the mfg has input year or no input use it
if (TB_MFGYR.Text.Length == 0 || TB_MFGYR.Text.Length == 4)
{
string DStype = null;
string MFGYR = null;
//Grab the Year if it has value
if (TB_MFGYR.Text.Length == 4)
{
MFGYR = TB_MFGYR.Text;
}
else
{
MFGYR = null;
}
if (RB_N3ds.IsChecked == true)
{
DStype = "new";
}
else if (RB_O3DS.IsChecked == true)
{
DStype = "old";
}
//Execute Command with Arguments
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
string dir = System.IO.Path.GetDirectoryName(exePath)+"\\App\\";
//Start the process and export thr console output to the textbox
CreateProcess(dir + "seedminer_launcher.exe", "Mii " + DStype + " " + MFGYR, dir);
}
//Else display Error Message WIP
else
{
tb_outputtext.Text = null;
tb_outputtext.Text = "MFG Year must have 4 characters or none";
}
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
private void ReadData()
{
var input = process.StandardOutput;
int nextChar;
while ((nextChar = input.Read()) >= 0)
{
lock (syncGate)
{
output.Append((char)nextChar);
if (!outputChanged)
{
outputChanged = true;
var dispatcher = Application.Current.MainWindow.Dispatcher;
Dispatcher.BeginInvoke(new Action(OnOutputChanged));
}
}
}
lock (syncGate)
{
process.Dispose();
process = null;
}
}
private void OnOutputChanged()
{
lock (syncGate)
{
tb_outputtext.AppendText(output.ToString());
outputChanged = false;
}
}
}
If I understand you correctly then you want your WPF app to continously update the content ot the TextBox while your python executable is running?
I have stripped down your code and used the Windows command ping -t 127.0.0.1 -w 10000 which generates a new line every second to test your code. On my machine your code works as expected: the output in the WPF textbox is updated every second.
What happens if you replace the ping command with your python executable in the code below? Does your python script output a newline character after each line (as mentioned in Process.OutputDataReceived Event)?
MainWindow.xaml.cs
using System;
using System.Diagnostics;
using System.Windows;
namespace SO_Continous_Process_Output
{
public partial class MainWindow : Window
{
private Process process;
public MainWindow()
{
InitializeComponent();
CreateProcess("ping", "-t 127.0.0.1 -w 1000", "");
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
}
}
MainWindow.xaml
<Window x:Class="SO_Continous_Process_Output.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="tb_outputtext" Text="{Binding ProcessOutput}"></TextBox>
</Grid>
</Window>
Update
Python script
I wrote a python script to test if the output works and I had to set flush=True in order to make it work.
import time
while True:
print('hi!', flush=True)
time.sleep(1)

command prompt commands executing in windows application

i am trying in windows application i need to run another one application that's tetpdflib. that tetpdflib runs in command prompt only. when i drag and drop exe to the command prompt it will execute. for that i followed some coding
Process tetmlProcess = new Process();
tetmlProcess.StartInfo.CreateNoWindow = true;
tetmlProcess.StartInfo.RedirectStandardOutput = true;
tetmlProcess.StartInfo.UseShellExecute = false;
tetmlProcess.StartInfo.FileName = #"cmd.exe";
tetmlProcess.StartInfo.Arguments = "cd C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
tetmlProcess.Start();
but i cant get output.. and also i need to run following command prompt lines also
cd tet.exe
and tet -m filename
how to execute those commands in that process.
thats the full coding
public static string inputfile = string.Empty;
public static string outputfolder = string.Empty;
private void btninputbrowse_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog inputFileBrowser = new OpenFileDialog();
DialogResult result = inputFileBrowser.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
inputfile = inputFileBrowser.FileName;
txtinput.Text = inputFileBrowser.FileName;
}
}
private void btnoutputbrowse_Click(object sender, RoutedEventArgs e)
{
FolderBrowserDialog folderbrowsing = new FolderBrowserDialog();
DialogResult result = folderbrowsing.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
outputfolder = folderbrowsing.SelectedPath;
txtoutput.Text = folderbrowsing.SelectedPath;
}
}
private void btnok_Click(object sender, RoutedEventArgs e)
{
MoveInputFileToOutPutFolder();
}
private void MoveInputFileToOutPutFolder()
{
try
{
string[] splitinput = inputfile.Split('\\');
outputfolder = System.IO.Path.Combine(outputfolder,splitinput.LastOrDefault());
if (File.Exists(outputfolder))
{
File.Delete(outputfolder);
}
File.Copy(inputfile,outputfolder);
TetmlApplicationRunning();
}
catch (Exception)
{
throw;
}
}
private void TetmlApplicationRunning()
{
try
{
Process tetmlProcess = new Process();
//tetmlProcess.StartInfo.CreateNoWindow = true;
//tetmlProcess.StartInfo.RedirectStandardOutput = true;
//tetmlProcess.StartInfo.UseShellExecute = false;
tetmlProcess.StartInfo.FileName = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
tetmlProcess.StartInfo.WorkingDirectory = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin";
tetmlProcess.StartInfo.Arguments = "tetml -m wordplus" + inputfile;
tetmlProcess.Start();
}
catch (Exception)
{
throw;
}
}
}
}
You can do it like below. you won't need to run cmd.exe you can directly run tet.ext. Added comments in code.
Process tetmlProcess = new Process();
tetmlProcess.StartInfo.CreateNoWindow = true;
tetmlProcess.StartInfo.RedirectStandardOutput = true;
tetmlProcess.StartInfo.UseShellExecute = false;
// Instead of cmd.exe you run the tet.exe
tetmlProcess.StartInfo.FileName = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
//Set The working directory to C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin\ if needed
tetmlProcess.StartInfo.WorkingDirectory = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin";
//Use the arguments required for tet.exe
tetmlProcess.StartInfo.Arguments = "-m filename";
tetmlProcess.Start();
Note: This code is directly typed in here (have no access to visual studio now) so may contain syntax errors. Treat this only as guideline.
try the following snippet:
var proc = new ProcessStartInfo();
string yourCommand;
yourCommand = "calc.exe";
proc.UseShellExecute = true;
proc.WorkingDirectory = #"C:\Windows\System32";
proc.FileName = #"C:\Windows\System32\cmd.exe";
proc.Arguments = "/c " + yourCommand;
proc.WindowStyle = ProcessWindowStyle.Normal;
Process.Start(proc);
I run calculator; you can run your program as tet.exe and you must set the other parameters such as WorkingDirectory and FileName based on your .exe file.
This line of code
proc.WindowStyle = ProcessWindowStyle.Normal;
displays the cmd.exe window. If you are gonna not to display that, change the mentioned line of code to proc.WindowStyle = ProcessWindowStyle.Hidden;
I hope that work out!
I owuld not try to simulate the command prompt, but execute the application directly. I assume that for this application output is sent to the console. You can redirect this output, but it is not possible to combine this with shell execute. I use the full path name to the application, which I set in the "Options" class and is stored in the registry. An example:
static public String CompileScript(String InputFile, String OutputFile)
{
Process Compiler = new Process();
String Result = String.Empty;
try
{
Compiler.StartInfo.FileName = CLuaCreatorOptions.TrainSimulatorDirectory + "\\luac.exe";
Compiler.StartInfo.Arguments = "-v -o " + OutputFile + " " + InputFile;
Compiler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Compiler.StartInfo.CreateNoWindow = true;
Compiler.StartInfo.UseShellExecute = false;
Compiler.StartInfo.RedirectStandardOutput = true;
Compiler.StartInfo.RedirectStandardError = true;
Compiler.Start();
Result = Compiler.StandardOutput.ReadToEnd() + "\n" + Compiler.StandardError.ReadToEnd();
Compiler.WaitForExit();
}
catch (Exception e)
{
return "Error compiling script " + e.Message + "\r\n" + Result;
}
return Result;
}
This example runs the LUA compiler and returns all error messages (async) to a string "Result". I show this sting in a multiline textbox in the forms application tha calls this compiler.
These three lines do the trick for you to redirect the output.
Compiler.StartInfo.UseShellExecute = false;
Compiler.StartInfo.RedirectStandardOutput = true;
Compiler.StartInfo.RedirectStandardError = true;
To actually obtain the information, you need to run the application and pick up the output. You need to wait till the application exits to get complete results, the last three lines do that for you:
Compiler.Start();
Result = Compiler.StandardOutput.ReadToEnd() + "\n" + Compiler.StandardError.ReadToEnd();
Compiler.WaitForExit();
Finally, you probably want to suppress the command window to be visible. This code will do that for you:
Compiler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Compiler.StartInfo.CreateNoWindow = true;

Expected behaviour with white space in the command line

I wrote a program that compiles my .cs files using csc.exe:
namespace myCompiler
{
public partial class Form1 : Form
{
string compilerFolder;
string outputFolder;
string projectFile;
string output = #" /out:";
public Form1()
{
InitializeComponent();
}
private void startCompile_Click(object sender, EventArgs e)
{
Compile();
}
public void findCompile_Click(object sender, EventArgs e)
{
DialogResult result1 = folderBrowserDialog1.ShowDialog();
compilerFolder = folderBrowserDialog1.SelectedPath;
MessageBox.Show(compilerFolder);
cscLabel.Text = compilerFolder;
}
private void outputCompile_Click(object sender, EventArgs e)
{
DialogResult result2 = folderBrowserDialog2.ShowDialog();
outputFolder = folderBrowserDialog2.SelectedPath;
outputLabel.Text = (outputFolder);
MessageBox.Show(outputFolder);
}
private void findProject_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
projectFile = openFileDialog1.FileName;
projectLabel.Text = (projectFile);
MessageBox.Show(projectFile);
}
}
public void Compile()
{
try
{
Process compile = new Process();
string outputExe = fileName.Text;
string compiler = compilerFolder + #"\csc.exe";
string arGs = output + outputFolder + #"\" + outputExe + " " + projectFile;
compile.StartInfo.FileName = (compiler);
compile.StartInfo.Arguments = (arGs);
compile.StartInfo.RedirectStandardOutput = true;
compile.StartInfo.UseShellExecute = false;
compile.Start();
string stdOutput = "";
while (!compile.HasExited)
{
stdOutput += compile.StandardOutput.ReadToEnd();
MessageBox.Show(stdOutput);
}
}
catch (Exception errorMsg)
{
MessageBox.Show(errorMsg.Message);
}
}
private void testButton_Click(object sender, EventArgs e)
{
MessageBox.Show(projectFile);
MessageBox.Show(compilerFolder);
}
}
}
The compile instruction runs but produces no results, just a quick flash of a black console screen.
Basically what seems to be happening, is when all the strings are parsed in the commandline as arguments for the process, the .cs project source directory is broken up by each white space ie c:\users\%username%\Documents\Visual Studio 2010\ is broken up as c:\users\%username%\Documents\Visual then Studio then 2010\Projects\Myproject\myproj.cs
and subsequently the compilation fails.
You need double quotes around a filepath with spaces in it.
See my edit to your code below.
public void Compile()
{
try
{
Process compile = new Process();
string outputExe = fileName.Text;
string compiler = compilerFolder + "\csc.exe";
// add double quotes around path with spaces in it.
string arGs = output + "\"" + outputFolder + "\"" + #"\" + outputExe + " " + projectFile;
compile.StartInfo.FileName = compiler;
compile.StartInfo.Arguments = arGs;
compile.StartInfo.RedirectStandardOutput = true;
compile.StartInfo.UseShellExecute = false;
compile.Start();
string stdOutput = "";
while (!compile.HasExited)
{
stdOutput += compile.StandardOutput.ReadToEnd();
MessageBox.Show(stdOutput);
}
}
catch (Exception errorMsg)
{
MessageBox.Show(errorMsg.Message);
}
}

If image open with... else open with?

I was just wondering if there is anyone out here that knows how to write a code how to check if item is an image then open with Windows image preview else open With Build in Media player.
Code is like this :
private bool listbox3job()
{
AxWMPLib.AxWindowsMediaPlayer axWmp = wfh.Child as AxWMPLib.AxWindowsMediaPlayer;
WMPLib.IWMPPlaylist playlist = axWmp.newPlaylist("myPlaylist", string.Empty);
DateTime? start = starttid2.Value;
DateTime? end = sluttid2.Value;
DateTime now = DateTime.Now;
if (start == null || end == null)
{
return false;
}
else if (now >= start.Value && now <= end.Value)
{
foreach (var selected in listBox3.Items)
{
string s = selected.ToString();
if (listBox3Dict.ContainsKey(s))
{
if (extentions.Contains(System.IO.Path.GetExtension(s).ToUpperInvariant()))
{
Process process = new Process();
process.StartInfo.FileName = "rundll32.exe";
process.StartInfo.Arguments = #"C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen " + listBox3Dict[s];
process.Start();
Thread.Sleep(7000);
{
exit();
}
}
else
{
WMPLib.IWMPMedia temp = axWmp.newMedia(listBox3Dict[s]);
playlist.appendItem(temp);
axWmp.settings.setMode("loop", true);
axWmp.settings.autoStart = true;
axWmp.currentPlaylist = playlist;
}
}
}
return true;
}
return false;
}
Here you are
public static List<string> extentions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
private void Open()
{
foreach (var selected in listBox4.Items)
{
string s = selected.ToString();
if (listBox4Dict.ContainsKey(s))
{
if (extentions.Contains(Path.GetExtension(s).ToUpperInvariant()))
{
Process process = new Process();
process.StartInfo.FileName = "rundll32.exe";
process.StartInfo.Arguments = #"C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen " +listBox4Dict[s];
process.Start();
process.WaitForExit();
while (!process.HasExited)
Thread.Sleep(500);
}
else
{
Mediaplayer.URL = (listBox4Dict[s]);
}
}
}
}

Categories

Resources