summaryrefslogtreecommitdiff
path: root/IvyDaemon
diff options
context:
space:
mode:
authorfcolin2007-02-01 12:05:09 +0000
committerfcolin2007-02-01 12:05:09 +0000
commit12c926b30ac4c97773d93afbd9adadd3bc5251b4 (patch)
treeeb24ef3f5e519f0d05c6ecec2736feb47cb664af /IvyDaemon
parent91afb5f2ead250cd371feb9882a5b31f8acc4ea4 (diff)
downloadivy-csharp-12c926b30ac4c97773d93afbd9adadd3bc5251b4.zip
ivy-csharp-12c926b30ac4c97773d93afbd9adadd3bc5251b4.tar.gz
ivy-csharp-12c926b30ac4c97773d93afbd9adadd3bc5251b4.tar.bz2
ivy-csharp-12c926b30ac4c97773d93afbd9adadd3bc5251b4.tar.xz
modification structure svn
Diffstat (limited to 'IvyDaemon')
-rw-r--r--IvyDaemon/App.icobin0 -> 1078 bytes
-rw-r--r--IvyDaemon/IvyDaemon.cs169
-rw-r--r--IvyDaemon/IvyDaemon.csproj154
-rw-r--r--IvyDaemon/IvyDaemon.csproj.vspscc10
-rw-r--r--IvyDaemon/IvyDaemon_TemporaryKey.pfxbin0 -> 1676 bytes
-rw-r--r--IvyDaemon/Properties/AssemblyInfo.cs58
-rw-r--r--IvyDaemon/Properties/Settings.Designer.cs35
-rw-r--r--IvyDaemon/Properties/Settings.settings9
-rw-r--r--IvyDaemon/Settings.cs28
-rw-r--r--IvyDaemon/app.config15
10 files changed, 478 insertions, 0 deletions
diff --git a/IvyDaemon/App.ico b/IvyDaemon/App.ico
new file mode 100644
index 0000000..3a5525f
--- /dev/null
+++ b/IvyDaemon/App.ico
Binary files differ
diff --git a/IvyDaemon/IvyDaemon.cs b/IvyDaemon/IvyDaemon.cs
new file mode 100644
index 0000000..8c0b069
--- /dev/null
+++ b/IvyDaemon/IvyDaemon.cs
@@ -0,0 +1,169 @@
+/// François-Régis Colin
+/// http://www.tls.cena.fr/products/ivy/
+/// *
+/// (C) CENA
+/// *
+namespace IvyDaemon
+{
+ using System;
+ using System.IO;
+ using System.Threading;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Configuration;
+ using System.Diagnostics;
+ using IvyBus;
+ /// <summary> IvyDaemon: simple TCP to Ivy relay.
+ /// </summary>
+ /// <remarks>
+ /// This is a sample implementation of an Ivy Daemon, like ivyd
+ /// sends anonymous messages to an Ivy bus through a simple tcp socket,
+ /// line by line. The default port is 3456.
+ /// </remarks>
+ public class IvyDaemon
+ {
+
+
+ private TcpListener serviceSocket;
+ private static bool debug = Properties.Settings.Default.IvyDebug;
+ private volatile Thread clientThread; // volatile to ensure the quick communication
+ private Ivy bus;
+
+ public static int DEFAULT_SERVICE_PORT = 3456;
+ public const System.String DEFAULTNAME = "IvyDaemon";
+ public static System.String helpmsg = "usage: IvyDaemon [options]\n\t-b BUS\tspecifies the Ivy bus domain\n\t-p\tport number, default " + DEFAULT_SERVICE_PORT + "\n\t-n ivyname (default " + DEFAULTNAME + ")\n\t-q\tquiet, no tty output\n\t-d\tdebug\n\t-h\thelp\nListens on the TCP port, and sends each line read on the Ivy bus. It is useful to launch one Ivy Daemon and let scripts send their message on the bus.\n";
+ [STAThread]
+ public static void Main(System.String[] args)
+ {
+ Ivy bus;
+ int servicePort = DEFAULT_SERVICE_PORT;
+ System.String name = DEFAULTNAME;
+ bool quiet = false;
+ System.String domain = Ivy.GetDomain(null);
+/* Getopt opt = new Getopt("IvyDaemon", args, "n:b:dqp:h");
+ int c;
+ while ((c = opt.getopt()) != - 1)
+ {
+ switch (c)
+ {
+ case 'n':
+ name = opt.Optarg;
+ break;
+
+ case 'b':
+ domain = opt.Optarg;
+ break;
+
+ case 'q':
+ quiet = true;
+ break;
+
+ case 'd':
+ //UPGRADE_ISSUE: Method 'java.lang.System.getProperties' was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1000_javalangSystemgetProperties"'
+ //System.Configuration.AppSettingsReader sysProp = System.getProperties();
+ //SupportClass.PutElement(sysProp, "IVY_DEBUG", "yes");
+ break;
+
+ case 'p':
+ System.String s = "";
+ try
+ {
+ servicePort = System.Int32.Parse(s = opt.Optarg);
+ }
+ catch (System.FormatException nfe)
+ {
+ System.Console.Out.WriteLine("Invalid port number: " + s);
+ System.Environment.Exit(0);
+ }
+ break;
+
+ case 'h': default:
+ System.Console.Out.WriteLine(helpmsg);
+ System.Environment.Exit(0);
+ break;
+
+ }
+ }
+*/
+ bus = new Ivy(name, name + " ready");
+ if (!quiet)
+ System.Console.Out.WriteLine("broadcasting on " + Ivy.Domains(domain));
+ bus.Start(domain);
+ if (!quiet)
+ System.Console.Out.WriteLine("listening on " + servicePort);
+ IvyDaemon d = new IvyDaemon(bus, servicePort);
+ }
+
+ public IvyDaemon(Ivy bus, int servicePort)
+ {
+ this.bus = bus;
+ IPAddress localAddr = IPAddress.Any;
+ serviceSocket = new TcpListener(localAddr, servicePort);
+ clientThread = new Thread(new ThreadStart(this.Run));
+ clientThread.Start();
+ }
+
+ /*
+ * the service socket reader.
+ * it could be a thread, but as long as we've got one ....
+ */
+ public void Run()
+ {
+ Thread thisThread = Thread.CurrentThread;
+ traceDebug("Thread started");
+ while (clientThread == thisThread)
+ {
+ try
+ {
+ SubReader generatedAux2 = new SubReader(serviceSocket.AcceptTcpClient(),bus);
+ }
+ catch (IOException e)
+ {
+ traceDebug("TCP socket reader caught an exception " + e.Message);
+ }
+ }
+ traceDebug("Thread stopped");
+ }
+
+ internal class SubReader
+ {
+ internal StreamReader in_Renamed;
+ internal Thread looperThread;
+ internal Ivy bus;
+ internal SubReader(TcpClient socket, Ivy bus)
+ {
+ this.bus = bus;
+ in_Renamed = new StreamReader(socket.GetStream());
+ looperThread = new Thread(new ThreadStart(this.Run));
+ looperThread.Start();
+ }
+ public void Run()
+ {
+ traceDebug("Subreader Thread started");
+ String msg = null;
+ try
+ {
+ while (true)
+ {
+ msg = in_Renamed.ReadLine();
+ if (msg == null)
+ break;
+ bus.SendMsg(msg);
+ }
+ }
+ catch (IOException ioe)
+ {
+ traceDebug("Subreader exception:" + ioe.Message);
+ System.Environment.Exit(0);
+ }
+ traceDebug("Subreader Thread stopped");
+ }
+
+ }
+ [Conditional("DEBUG")]
+ private static void traceDebug(string s)
+ {
+ Trace.WriteLineIf(debug, "-->IvyDaemon<-- " + s);
+ }
+ }
+} \ No newline at end of file
diff --git a/IvyDaemon/IvyDaemon.csproj b/IvyDaemon/IvyDaemon.csproj
new file mode 100644
index 0000000..1dc6409
--- /dev/null
+++ b/IvyDaemon/IvyDaemon.csproj
@@ -0,0 +1,154 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectType>Local</ProjectType>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B10AB29F-D678-4472-9BA3-D627262E14E1}</ProjectGuid>
+ <SccProjectName>SAK</SccProjectName>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccProvider>SAK</SccProvider>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ApplicationIcon>App.ico</ApplicationIcon>
+ <AssemblyKeyContainerName>
+ </AssemblyKeyContainerName>
+ <AssemblyName>IvyDaemon</AssemblyName>
+ <AssemblyOriginatorKeyFile>
+ </AssemblyOriginatorKeyFile>
+ <DefaultClientScript>JScript</DefaultClientScript>
+ <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+ <DefaultTargetSchema>IE50</DefaultTargetSchema>
+ <DelaySign>false</DelaySign>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>IvyDaemon</RootNamespace>
+ <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+ <StartupObject>
+ </StartupObject>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <ManifestCertificateThumbprint>A4751EEE69A15B9F42D2EF22930B195D367E5103</ManifestCertificateThumbprint>
+ <ManifestKeyFile>IvyDaemon_TemporaryKey.pfx</ManifestKeyFile>
+ <GenerateManifests>true</GenerateManifests>
+ <SignManifests>true</SignManifests>
+ <IsWebBootstrapper>true</IsWebBootstrapper>
+ <PublishUrl>\\samba\fcolin\public_html\ClickOnce\IvyDaemon\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Web</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <InstallUrl>http://www.tls.cena.fr/~fcolin/ClickOnce/IvyDaemon/</InstallUrl>
+ <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
+ <WebPage>publish.htm</WebPage>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <OutputPath>bin\Debug\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>true</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>false</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>full</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <OutputPath>bin\Release\</OutputPath>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+ <BaseAddress>285212672</BaseAddress>
+ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+ <ConfigurationOverrideFile>
+ </ConfigurationOverrideFile>
+ <DefineConstants>TRACE</DefineConstants>
+ <DocumentationFile>
+ </DocumentationFile>
+ <DebugSymbols>false</DebugSymbols>
+ <FileAlignment>4096</FileAlignment>
+ <NoStdLib>false</NoStdLib>
+ <NoWarn>
+ </NoWarn>
+ <Optimize>true</Optimize>
+ <RegisterForComInterop>false</RegisterForComInterop>
+ <RemoveIntegerChecks>false</RemoveIntegerChecks>
+ <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+ <WarningLevel>4</WarningLevel>
+ <DebugType>none</DebugType>
+ <ErrorReport>prompt</ErrorReport>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <Name>System</Name>
+ </Reference>
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Data">
+ <Name>System.Data</Name>
+ </Reference>
+ <Reference Include="System.Xml">
+ <Name>System.XML</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="App.ico" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="IvyDaemon.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <Compile Include="Settings.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="IvyDaemon_TemporaryKey.pfx" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 2.0</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Ivy\Ivy.csproj">
+ <Project>{F2F03CF7-0087-4EDB-AD15-80C9E8DA2617}</Project>
+ <Name>Ivy</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/IvyDaemon/IvyDaemon.csproj.vspscc b/IvyDaemon/IvyDaemon.csproj.vspscc
new file mode 100644
index 0000000..a2a1a1c
--- /dev/null
+++ b/IvyDaemon/IvyDaemon.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:IvyDaemon"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/IvyDaemon/IvyDaemon_TemporaryKey.pfx b/IvyDaemon/IvyDaemon_TemporaryKey.pfx
new file mode 100644
index 0000000..b280243
--- /dev/null
+++ b/IvyDaemon/IvyDaemon_TemporaryKey.pfx
Binary files differ
diff --git a/IvyDaemon/Properties/AssemblyInfo.cs b/IvyDaemon/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..65a2ee8
--- /dev/null
+++ b/IvyDaemon/Properties/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Pour modifier les informations
+// associées à un assembly, changez les valeurs de ces attributs.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer des numéros de révision et de build par défaut
+// en utilisant '*', comme ci-dessous :
+
+[assembly: AssemblyVersion("2.0.*")]
+
+//
+// Pour signer votre assembly, vous devez spécifier la clé à utiliser. Consultez
+// la documentation Microsoft .NET Framework pour plus d'informations sur la signature d'un assembly.
+//
+// Utilisez les attributs ci-dessous pour contrôler la clé utilisée lors de la signature.
+//
+// Remarques :
+// (*) Si aucune clé n'est spécifiée, l'assembly n'est pas signé.
+// (*) KeyName fait référence à une clé installée dans le fournisseur de
+// services cryptographiques (CSP) de votre ordinateur. KeyFile fait référence à un fichier qui contient
+// une clé.
+// (*) Si les valeurs de KeyFile et de KeyName sont spécifiées, le
+// traitement suivant se produit :
+// (1) Si KeyName se trouve dans le CSP, la clé est utilisée.
+// (2) Si KeyName n'existe pas mais que KeyFile existe, la clé
+// de KeyFile est installée dans le CSP et utilisée.
+// (*) Pour créer KeyFile, vous pouvez utiliser l'utilitaire sn.exe (Strong Name, Nom fort).
+// Lors de la spécification de KeyFile, son emplacement doit être
+// relatif au répertoire de sortie du projet qui est
+// %Project Directory%\obj\<configuration>. Par exemple, si votre KeyFile se trouve
+// dans le répertoire du projet, vous devez spécifier l'attribut
+// AssemblyKeyFile sous la forme [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) DelaySign (signature différée) est une option avancée. Pour plus d'informations, consultez la
+// documentation Microsoft .NET Framework.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/IvyDaemon/Properties/Settings.Designer.cs b/IvyDaemon/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..7555e19
--- /dev/null
+++ b/IvyDaemon/Properties/Settings.Designer.cs
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.42
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace IvyDaemon.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool IvyDebug {
+ get {
+ return ((bool)(this["IvyDebug"]));
+ }
+ }
+ }
+}
diff --git a/IvyDaemon/Properties/Settings.settings b/IvyDaemon/Properties/Settings.settings
new file mode 100644
index 0000000..046036c
--- /dev/null
+++ b/IvyDaemon/Properties/Settings.settings
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="IvyDaemon.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="IvyDebug" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">False</Value>
+ </Setting>
+ </Settings>
+</SettingsFile> \ No newline at end of file
diff --git a/IvyDaemon/Settings.cs b/IvyDaemon/Settings.cs
new file mode 100644
index 0000000..6ac518c
--- /dev/null
+++ b/IvyDaemon/Settings.cs
@@ -0,0 +1,28 @@
+namespace IvyDaemon.Properties {
+
+
+ // This class allows you to handle specific events on the settings class:
+ // The SettingChanging event is raised before a setting's value is changed.
+ // The PropertyChanged event is raised after a setting's value is changed.
+ // The SettingsLoaded event is raised after the setting values are loaded.
+ // The SettingsSaving event is raised before the setting values are saved.
+ internal sealed partial class Settings {
+
+ public Settings() {
+ // // To add event handlers for saving and changing settings, uncomment the lines below:
+ //
+ // this.SettingChanging += this.SettingChangingEventHandler;
+ //
+ // this.SettingsSaving += this.SettingsSavingEventHandler;
+ //
+ }
+
+ private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
+ // Add code to handle the SettingChangingEvent event here.
+ }
+
+ private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
+ // Add code to handle the SettingsSaving event here.
+ }
+ }
+}
diff --git a/IvyDaemon/app.config b/IvyDaemon/app.config
new file mode 100644
index 0000000..df27cc0
--- /dev/null
+++ b/IvyDaemon/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+ <section name="IvyDaemon.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <IvyDaemon.Properties.Settings>
+ <setting name="IvyDebug" serializeAs="String">
+ <value>False</value>
+ </setting>
+ </IvyDaemon.Properties.Settings>
+ </applicationSettings>
+</configuration> \ No newline at end of file