Coder Social home page Coder Social logo

Comments (11)

drieseng avatar drieseng commented on August 26, 2024

Please share the code that you used for this test, and include the following information:

  • SSH server software (name and version)
  • encryption algorithm used
  • MAC algorithm used
  • .NET Framework version

The only big area's of improvement I can think of are:

  • encryption algorithms
  • PipeStream (used in SshCommand and ScpClient)
  • ShellStream

SSH.NET uses its proper encryption implementations (in order to support a broad set of target frameworks), while SharpSSH uses the BCL implementations (System.Security.Cryptography.*) which are surely highly tuned.

from ssh.net.

kpali avatar kpali commented on August 26, 2024
  • SSH server software: SSH-2.0-OpenSSH_4.3
  • encryption algorithm used: aes256-ctr
  • MAC algorithm used: hmac-md5
  • .NET Framework version: 4.0

Code:

IsshStream.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace SshTest
{
    public interface ISshStream
    {
        void Connect(string host, string userName, string password);

        void Close();

        void Write(string data);

        StreamReader GetStreamReader();

        StreamWriter GetStreamWriter();
    }
}

SshNetStream.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SshTest
{
    internal class SshNetStream : ISshStream
    {
        Renci.SshNet.ShellStream _shellStream;
        Renci.SshNet.SshClient _sshClinet;

        public void Connect(string host, string userName, string password)
        {
            _sshClinet = new Renci.SshNet.SshClient(host, userName, password);
            _sshClinet.Connect();
            _shellStream = _sshClinet.CreateShellStream("ShellStream", 512, 24, 512, 512, 1024);
        }

        public void Close()
        {
            if (_sshClinet != null)
                _sshClinet.Disconnect();
        }

        public void Write(string data)
        {
            StreamWriter streamWriter = GetStreamWriter();
            streamWriter.Write(data + "\r");
            streamWriter.Flush();
        }

        StreamReader _streamReader = null;
        public StreamReader GetStreamReader()
        {
            if (_streamReader != null)
            {
                return _streamReader;
            }
            else
            {
                if (_shellStream == null)
                {
                    return null;
                }
                _streamReader = new StreamReader(_shellStream);
                return _streamReader;
            }
        }

        StreamWriter _streamWriter = null;
        public StreamWriter GetStreamWriter()
        {
            if (_streamWriter != null)
            {
                return _streamWriter;
            }
            else
            {
                if (_shellStream == null)
                {
                    return null;
                }
                _streamWriter = new StreamWriter(_shellStream);
                return _streamWriter;
            }
        }
    }
}

SharpSshStream.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SshTest
{
    internal class SharpSshStream : ISshStream
    {
        Tamir.SharpSsh.SshStream _sshStream;

        public void Connect(string host, string userName, string password)
        {
            _sshStream = new Tamir.SharpSsh.SshStream(host, userName, password);
        }

        public void Close()
        {
            if (_sshStream != null)
                _sshStream.Close();
        }

        public void Write(string data)
        {
            StreamWriter streamWriter = GetStreamWriter();
            streamWriter.Write(data + "\r");
            streamWriter.Flush();
        }

        StreamReader _streamReader = null;
        public StreamReader GetStreamReader()
        {
            if (_streamReader != null)
            {
                return _streamReader;
            }
            else
            {
                if (_sshStream == null)
                {
                    return null;
                }
                _streamReader = new StreamReader(_sshStream.GetInputStream());
                return _streamReader;
            }
        }

        StreamWriter _streamWriter = null;
        public StreamWriter GetStreamWriter()
        {
            if (_streamWriter != null)
            {
                return _streamWriter;
            }
            else
            {
                if (_sshStream == null)
                {
                    return null;
                }
                _streamWriter = new StreamWriter(_sshStream.GetOutputStream());
                return _streamWriter;
            }
        }
    }
}

SshStreamFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SshTest
{
    internal static class SshStreamFactory
    {
        public static ISshStream CreateSshStream(string sshStreamType)
        {
            switch (sshStreamType)
            {
                case "sharpssh":
                    return new SharpSshStream();
                case "sshnet":
                    return new SshNetStream();
                default:
                    throw new Exception("Invalid SshStream type:" + sshStreamType);
            }
        }
    }
}

UnblockStreamReader.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace SshTest
{
    class UnblockStreamReaderLockObject
    {
        public char[] buffer;
        public int len;
        public int pos;
    };

    public class UnblockStreamReader
    {
        const int BUFFER_SIZE = 65536;
        Thread readThread;
        UnblockStreamReaderLockObject lockObject;
        public int GetUnreadBufferLength()
        {
            return lockObject.len;
        }
        public int GetUnreadBufferPosition()
        {
            return lockObject.pos;
        }
        StreamReader streamReader;

        public UnblockStreamReader(StreamReader streamReader)
        {
            lockObject = new UnblockStreamReaderLockObject();

            lockObject.buffer = new char[BUFFER_SIZE + 1];
            lockObject.len = 0;
            lockObject.pos = 0;

            this.streamReader = streamReader;
            readThread = new Thread(this.ReadThreadProc);
            readThread.Name = "UnblockStreamReader thread";
            readThread.Start();
        }

        public void Close()
        {
            readThread.Abort();
            lock (lockObject)
            {
                lockObject.len = 0;
                lockObject.pos = 0;
            }
        }

        private void ReadThreadProc(object param)
        {
            char[] buf = new char[1];
            int readLen = 0;
            bool isSleep = false;
            try
            {
                while (true)
                {
                    lock (lockObject)
                    {
                        if (lockObject.len >= BUFFER_SIZE)
                        {
                            isSleep = true;
                        }
                    }
                    if (isSleep == true)
                    {
                        isSleep = false;
                        Thread.Sleep(10);
                        continue;
                    }
                    readLen = this.streamReader.Read(buf, 0, 1);
                    if (readLen > 0)
                    {
                        lock (lockObject)
                        {
                            if ((lockObject.pos + lockObject.len) >= BUFFER_SIZE)
                            {
                                for (int i = 0; i < lockObject.len; i++)
                                {
                                    lockObject.buffer[i] = lockObject.buffer[lockObject.pos + i];
                                }
                                lockObject.pos = 0;
                            }

                            lockObject.buffer[lockObject.pos + lockObject.len] = buf[0];

                            lockObject.len++;
                        }
                    }
                    else
                        Thread.Sleep(10);
                }
            }
            catch (Exception e)
            {
                e.ToString();
                return;
            }
        }

        public int ReadChar(ref char buf)
        {
            lock (lockObject)
            {
                if (lockObject.len == 0)
                {
                    return 0;
                }
                buf = lockObject.buffer[lockObject.pos];
                lockObject.pos++;
                lockObject.len--;
            }
            return 1;
        }

        public String ReadToEnd(bool isRemove = true)
        {
            String resultString;
            lock (lockObject)
            {
                if (lockObject.len == 0)
                {
                    return null;
                }
                resultString = new String(lockObject.buffer, lockObject.pos, lockObject.len);
                if (isRemove)
                {
                    lockObject.pos = 0;
                    lockObject.len = 0;
                }
                return resultString;
            }
        }

        public String ReadLine(char lineEndFlag = '\n')
        {
            String resultString;
            while (true)
            {
                lock (lockObject)
                {
                    if (lockObject.len == 0)
                    {
                        Thread.Sleep(10);
                        continue;
                    }

                    for (int i = 0; i < lockObject.len; i++)
                    {
                        if (lockObject.buffer[lockObject.pos + i] == lineEndFlag)
                        {
                            resultString = new String(lockObject.buffer, lockObject.pos, i + 1);
                            lockObject.pos = lockObject.pos + i + 1;
                            lockObject.len = lockObject.len - i - 1;
                            return resultString;
                        }
                    }
                }
                Thread.Sleep(10);
            }
        }
    }
}

UnblockStreamUtility.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

namespace SshTest
{
    public class UnblockStreamUtility
    {
        internal static String[] ReadUntil(UnblockStreamReader reader, List<UntilInfo> untilInfoList, int noResponseTimeoutSeconds)
        {
            List<String> resultList = new List<String>();
            char[] buffer = new char[65536];
            int curBufferLen = 0;
            int noResponseTimeoutMilliseconds = noResponseTimeoutSeconds * 1000;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            while (true)
            {
                char readChar = new char();
                int readCharLen = reader.ReadChar(ref readChar);
                if (readCharLen == 0)
                {
                    Thread.Sleep(10);
                    if (stopwatch.ElapsedMilliseconds >= noResponseTimeoutMilliseconds)
                    {
                        stopwatch.Stop();
                        throw new Exception("No Response Timeout!");
                    }
                    continue;
                }
                else { stopwatch.Restart(); }
                buffer[curBufferLen] = readChar;

                foreach (UntilInfo untilInfo in untilInfoList)
                {
                    if (readChar == untilInfo.UntilCharArray[untilInfo.CompareLen])
                    {
                        untilInfo.CompareLen++;
                        if (untilInfo.CompareLen == untilInfo.UntilCharArray.Length)
                        {
                            untilInfo.CompareLen = 0;
                            String lineStr = new String(buffer, 0, curBufferLen + 1);
                            if (lineStr.EndsWith("\r\r\n"))
                            {
                                lineStr = lineStr.Substring(0, lineStr.Length - 3);
                            }
                            else if (lineStr.EndsWith("\r\n"))
                            {
                                lineStr = lineStr.Substring(0, lineStr.Length - 2);
                            }
                            else if (lineStr.EndsWith("\n"))
                            {
                                lineStr = lineStr.Substring(0, lineStr.Length - 1);
                            }

                            resultList.Add(lineStr);
                            curBufferLen = 0;

                            if (untilInfo.ExceptionMessage != null)
                                throw new Exception(untilInfo.ExceptionMessage);
                            else
                                return resultList.ToArray();
                        }
                    }
                    else
                    {
                        untilInfo.CompareLen = 0;
                    }
                }

                if (readChar == '\n')
                {
                    String lineStr = new String(buffer, 0, curBufferLen + 1);

                    if (lineStr.EndsWith("\r\r\n"))
                    {
                        lineStr = lineStr.Substring(0, lineStr.Length - 3);
                    }
                    else if (lineStr.EndsWith("\r\n"))
                    {
                        lineStr = lineStr.Substring(0, lineStr.Length - 2);
                    }
                    else if (lineStr.EndsWith("\n"))
                    {
                        lineStr = lineStr.Substring(0, lineStr.Length - 1);
                    }

                    resultList.Add(lineStr);

                    curBufferLen = 0;
                    foreach (UntilInfo untilInfo in untilInfoList)
                    {
                        untilInfo.CompareLen = 0;
                    }
                    continue;
                }
                curBufferLen++;
            }
        }
    }
}

UntilInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SshTest
{
    public class UntilInfo
    {
        public UntilInfo(string untilString, string exceptionMessage = null)
        {
            this.UntilString = untilString;
            this.ExceptionMessage = exceptionMessage;
            this.UntilCharArray = untilString.ToCharArray();
            this.CompareLen = 0;
        }

        public string UntilString
        {
            get;
            private set;
        }

        public string ExceptionMessage
        {
            get;
            private set;
        }

        public char[] UntilCharArray
        {
            get;
            private set;
        }

        public int CompareLen
        {
            get;
            set;
        }
    }
}

MySshClient.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace SshTest
{
    public class MySshClient : IDisposable
    {
        public MySshClient(string host, string userName, string password, string sshStreamType)
        {
            _host = host;
            _userName = userName;
            _password  = password;
            _sshStreamType = sshStreamType;
        }

        private string _host;
        private string _userName;
        private string _password;
        private string _sshStreamType;
        private int _noResponseTimeoutSeconds = 60;

        private Component component = new Component();
        private bool disposed = false;

        ~MySshClient()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    component.Dispose();
                }

                this.Close();

                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private ISshStream SshStream
        {
            get;
            set;
        }

        public void Connect()
        {
            SshStream = SshStreamFactory.CreateSshStream(_sshStreamType);
            SshStream.Connect(_host, _userName, _password);

            try
            {
                UnblockStreamReader = new UnblockStreamReader(SshStream.GetStreamReader());
                InitEnv();
            }
            catch (Exception ex)
            {
                this.Close();
                throw ex;
            }
        }

        protected virtual void InitEnv()
        {
            string[] response = null;
            this.SshStream.Write("set +o vi");
            this.SshStream.Write("set +o viraw");
            this.SshStream.Write("export PROMPT_COMMAND=");
            this.SshStream.Write("export PS1=" + Prompt);
            response = this.ReadResponse("export PS1=" + Prompt + "\r\n", _noResponseTimeoutSeconds);
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            string helloMessage = "Hello this is test message!";
            this.SshStream.Write("echo '" + helloMessage + "'");
            response = this.ReadResponse(helloMessage + "\r\n", _noResponseTimeoutSeconds);
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            this.SshStream.Write("stty columns 512");
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            this.SshStream.Write("stty rows 24");
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            this.SshStream.Write("export LANG=en_US.UTF-8");
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            this.SshStream.Write("export NLS_LANG=American_America.ZHS16GBK");
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);

            this.SshStream.Write("unalias grep");
            response = this.ReadResponse(Prompt, _noResponseTimeoutSeconds);
        }

        protected virtual void Close()
        {
            if (UnblockStreamReader != null)
            {
                UnblockStreamReader.Close();
                UnblockStreamReader = null;
            }
            if (SshStream != null)
            {
                SshStream.Close();
                SshStream = null;
            }
        }

        protected UnblockStreamReader UnblockStreamReader
        {
            get;
            private set;
        }

        public String Prompt
        {
            get
            {
                return "[SHINE_COMMAND_PROMPT]";
            }
        }

        public void Write(string data)
        {
            if (SshStream == null)
            {
                this.Connect();
            }
            if (UnblockStreamReader.GetUnreadBufferLength() > 0)
            {
                UnblockStreamReader.ReadToEnd();
            }
            this.SshStream.Write(data);
        }

        public string[] ReadResponse(string prompt, int noResponseTimeoutSeconds)
        {
            List<UntilInfo> untilInfoList = new List<UntilInfo>() { new UntilInfo(prompt) };
            string[] response = UnblockStreamUtility.ReadUntil(UnblockStreamReader, untilInfoList, noResponseTimeoutSeconds);
            return response;
        }

        public string[] ReadResponse(List<UntilInfo> untilInfoList, int noResponseTimeoutSeconds)
        {
            string[] response = UnblockStreamUtility.ReadUntil(UnblockStreamReader, untilInfoList, noResponseTimeoutSeconds);
            return response;
        }

        public string[] RunCommand(string command)
        {
            SshStream.Write("command");
            return ReadResponse(Prompt, _noResponseTimeoutSeconds);
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace SshTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();

            Renci.SshNet.SshClient sshNet = new Renci.SshNet.SshClient("10.168.3.51", "oracle", "oracle");
            stopwatch.Restart();
            sshNet.Connect();
            stopwatch.Stop();
            Console.Write("sshNet.Connect()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");
            stopwatch.Restart();
            Renci.SshNet.SshCommand sshCommand = sshNet.RunCommand("free -m");
            stopwatch.Stop();
            Console.Write("sshNet.RunCommand()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");

            Tamir.SharpSsh.SshExec sharpSsh = new Tamir.SharpSsh.SshExec("10.168.3.51", "oracle", "oracle");
            stopwatch.Restart();
            sharpSsh.Connect();
            stopwatch.Stop();
            Console.Write("sharpSsh.Connect()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");
            stopwatch.Restart();
            string result = sharpSsh.RunCommand("free -m");
            stopwatch.Stop();
            Console.Write("sharpSsh.RunCommand()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");

            MySshClient mySshClient_SshNet = new MySshClient("10.168.3.51", "oracle", "oracle", "sshnet");
            stopwatch.Restart();
            mySshClient_SshNet.Connect();
            stopwatch.Stop();
            Console.Write("mySshClient_SshNet.Connect()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");
            stopwatch.Restart();
            string[] results1 = mySshClient_SshNet.RunCommand("free -m");
            stopwatch.Stop();
            Console.Write("mySshClient_SshNet.RunCommand()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");

            MySshClient mySshClient_SharpSsh = new MySshClient("10.168.3.51", "oracle", "oracle", "sharpssh");
            stopwatch.Restart();
            mySshClient_SharpSsh.Connect();
            stopwatch.Stop();
            Console.Write("mySshClient_SharpSsh.Connect()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");
            stopwatch.Restart();
            string[] results2 = mySshClient_SharpSsh.RunCommand("free -m");
            stopwatch.Stop();
            Console.Write("mySshClient_SharpSsh.RunCommand()   ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + "milliseconds");

            Console.ReadLine();
        }
    }
}

Code execution results:

sshNet.Connect() 531milliseconds

sshNet.RunCommand() 320milliseconds

sharpSsh.Connect() 305milliseconds

sharpSsh.RunCommand() 268milliseconds

mySshClient_SshNet.Connect() 1369milliseconds

mySshClient_SshNet.RunCommand() 52milliseconds

mySshClient_SharpSsh.Connect() 454milliseconds

mySshClient_SharpSsh.RunCommand() 9milliseconds

from ssh.net.

drieseng avatar drieseng commented on August 26, 2024

Thanks for taking time to provide all the info.
I'll look into it this evening or this weekend.

from ssh.net.

Compufreak345 avatar Compufreak345 commented on August 26, 2024

I'm also having some performance issues using a ShellStream - did you find time to look into this @drieseng ?

from ssh.net.

drieseng avatar drieseng commented on August 26, 2024

What version of SharpSSH did you use? I tried version 1.1.1.13, but that version does not have GetInputStream() and GetOutputStream() methods on SshStream.

from ssh.net.

kpali avatar kpali commented on August 26, 2024

These two methods are my extension methods in SshSteam:

public Stream GetInputStream()
{
    return m_in;
}

public Stream GetOutputStream()
{
    return m_out;
}

I hope it can help you :-)

from ssh.net.

drieseng avatar drieseng commented on August 26, 2024

These are the results I get when run against the develop branch (which is almost the same as 2016.1.0-beta1):

sshNet.Connect()   113 milliseconds
sshNet.RunCommand()   101 milliseconds
sharpSsh.Connect()   155 milliseconds
sharpSsh.RunCommand()   114 milliseconds
mySshClient_SshNet.Connect()   203 milliseconds
mySshClient_SshNet.RunCommand()   10 milliseconds
mySshClient_SharpSsh.Connect()   344 milliseconds
mySshClient_SharpSsh.RunCommand()   10 milliseconds

What type of system did you run your test on?
Both SSH.NET and SharpSSH are substantially faster in my test.

What version of SSH.NET did you test against, and - if you built from source - did you build the release configuration?

Please re-run your test against a recent officially packaged version of SSH.NET.

from ssh.net.

drieseng avatar drieseng commented on August 26, 2024

There's also some weird stuff in the code you provided.
For example:
In MySshClient.RunCommand(string command), you're actually wrting the literal "command" to the underlying stream.

from ssh.net.

Compufreak345 avatar Compufreak345 commented on August 26, 2024

In my case, I am using 2016.0.0 and I am using the CreateShellStream-method. The weird thing is that I am configuring a router, and when I am using NetConfClient (that also uses an SSHStream if I am not misunderstanding something) my commands get finished in 300-1000ms, while using SSH CLI for the same commands it takes either ~7s or ~15s - strangely nothing inbetween, it's always either 7 or 15s.

This is my code :

 this.client = new SshClient(connectionInfo);
            this.client.Connect();
            // http://stackoverflow.com/questions/30883237/how-to-run-commands-in-cmd-process
            stream = client.CreateShellStream("", 0, 0, 0, 0, 1048);

            reader = new StreamReader(stream);
            writer = new StreamWriter(stream);
public string sendCommand(string customCmd)
        {
            _writeStream($"show clock\r\n{customCmd}\r\nshow clock\r\nexec echo \"MMS_END_COMMAND\"");
            return ReadStream(reader);
        }

        private void _writeStream(string cmd)
        {
            writer.WriteLine(cmd);
            writer.Flush();
        }
private string ReadStream(StreamReader reader)
       {
           var result = new StringBuilder();
           var lineBuilder = new StringBuilder();
           while (true)
           {
               var i = reader.Read();
               if (i >= 0)
               {
                   var c = (char) i;
                   
                       lineBuilder.Append(c);
                   
                   if (c != '\n') continue;
                   
                   var line = lineBuilder.ToString();
                   lineBuilder = new StringBuilder();
                   if (line.EndsWith("echo \"MMS_END_COMMAND\"\r\n")) continue;
                   if (line == "MMS_END_COMMAND\r\n") break;
                   result.Append(line);
               }
               else
               {
                   // It doesn't matter if I sleep here or if I don't.
                   Thread.Sleep(10);
               }
           }
           return result.ToString();
       }

I am sending 200 commands seperated by \r\n - it doesn't make a difference if I write them one by one or all together. It seems like it has to do with the Writer, as reading the list I set gets finished in 500ms.

I will try with the 2016.1.0-beta1 now.

/edit: Same behavior with 2016.1.0-beta1

from ssh.net.

Compufreak345 avatar Compufreak345 commented on August 26, 2024

Hmm ok, forget what I wrote (sorry) - if I replace my commands with echo-commands it finishes in 1138ms - it seems like the internal behavior for the operations I perform (setting ACL-entries) of the router is causing my issues :/

P.S.: Letting my code stay there for a while, maybe the Op could try to use some of it and see if his problems persist.

from ssh.net.

drieseng avatar drieseng commented on August 26, 2024

Do you still get the same results with the code you originally provided?
In which case we need to dig deeper as the issue is probably not in ShellStream itself.
If not, I propose we close this issue.

from ssh.net.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.