Giter VIP home page Giter VIP logo

sharpen's Introduction

Sharpen - Automated Java->C# coversion

imazen/sharpen masterimazen master - AppVeyor develop imazen develop - AppVeyor

mono/sharpen mastermono master - AppVeyor (permissions issue) develop mono develop - AppVeyor (permissions issue)

Sharpen is a library and command-line tool for automating Java to C# code conversion. You can provide configuration classes to control a wide range of class and functionality mapping.

Sharpen doesn’t provide a compatibility runtime (i.e, an implementation of all java functionality on top of .NET), but it does provide some utility classes to meet the most common needs.

It’s likely that you will need to create a configuration class to customize and perfect your conversion, and you may need to apply patches to the result as well.

Sharpen was originally created by db40 svn source here in the format of an Eclipse plugin, but it has since been refactored to work from the command line and on build servers.

Building and testing sharpen itself

  1. Clone this repository
  2. Install Java 7 and maven. Java 6 and 8 and later aren’t supported.
  3. Run ‘mvn clean test’ to test
  4. Run ‘mvn install ’ to generate .jar files in /sharpen.core/target

Running sharpen

  1. mvn install should have created a file named sharpencore-0.0.1-SNAPSHOT-jar-with-dependencies.jar. This is a self-contained copy of sharpen that can be run anywhere.
  2. Run java -jar sharpencore-0.0.1-SNAPSHOT-jar-with-dependencies.jar SOURCEPATH -cp JAR_DEPENDENCY_A JAR_DEPENDENCY_B
    Each dependecy needed by the java source should be specified as a full path to the jar file. SOURCEPATH should also be a full path.
  3. Run -help for syntax

Sharpen allows for configuration through code

Sharpen’s command-line options don’t let you fully override all conversion options and behaviour. For example if you need to change mapping of primitive types or allow/deny mapping between iterators and enumerators, ...

Creating external config class

Your external configuration class must:

  • inherit Configuration class;
  • must be publicly visible;
  • must have a public constructor;

An example configuration project can be found here https://github.com/ydanila/sharpen_imazen_config.

Using your custom config class

Name your jar file <configuration class name>.sharpenconfig.jar in the sharpen directory. Then specify the full configuration name via the command line parameter -configurationClass (or via the options file).

For example, for the XMP core port with this prebuilt Sharpen configuration could be used as follows.

java -jar sharpen-jar-with-dependencies.jar C:/java_src/ -configurationClass sharpen.config.MEConfiguration @sharpen-all-options-without-configuration

Configuration also could be specified in an options file. In this case, for the XMP core port with this prebuilt Sharpen configuration it could be used like this:

java -jar sharpen-jar-with-dependencies.jar C:/java_src/ @sharpen-all-options

sharpen's People

Contributors

asimarslan avatar ecerta avatar hazzik avatar lilith avatar sharwell avatar slluis avatar terrajobst avatar therzok avatar ydanila avatar zaoqi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sharpen's Issues

Automatic convert setters and getters to properties

Sharpen should have a feature which is able to automatic identify setters and getters and convert them to properties.

Following rules apply:

  • If a method name is starting with "get" or "is"; and it returns something; and it does not have any arguments then it is a getter
  • If a method name starts with "set" or "is"; and it does not return anything; and it accepts one argument then it is a setter
  • The property name will be a method name without leading "is", "get" or "set"

incorrect parsing of for loop with multiple initializations

Maybe there's an option I'm missing, so apologies if that's the case. When there are comma separated variables initialized in the for loop they are not preserved by sharpen.
Java:

for (int i = 0, n = 40; i < n; i++) {

Resulting C#:

for (int i = 0; i < n; i++)

I was looking into the source code and maybe there is a problem with the following CSharpBuilder.java class method:

    public boolean visit(VariableDeclarationExpression node) {
        pushExpression(new CSDeclarationExpression(createVariableDeclaration((VariableDeclarationFragment) node
                .fragments().get(0))));
        return false;
    }

It seems like get(0) ensures that you'll only ever get one item instead of multiple items. It's hard for me to debug whatever exactly is going on. Below is a test case you can run and the current results I'm getting:

public class testCase {
    public static void main (String args[]) {
        System.out.println ("Hello World!");
        for (int i = 0, n = 40; i < n; i++) {
            n *= 2;
            System.out.println("Hello " + i);
        }
    }
}

becomes:

using Sharpen;

public class testCase
{
    public static void Main(string[] args)
    {
        System.Console.Out.WriteLine("Hello World!");
        for (int i = 0; i < n; i++)
        {
            n *= 2;
            System.Console.Out.WriteLine("Hello " + i);
        }
    }
}

Fails on String.format

Exception::136: failed to map: 'System.out.println(String.format("%d) price: %.2f; attack +%.2f",stair,creaturePrice,creatureEffect))'

failed to map: 'memory=new byte[pages][bytesPerPage]'

C:/Users/user/Desktop/nfctools/nfctools-core/src/main/java/org/nfctools/mf/ul/MemoryMap.java
Conversion finished in 4781ms.
ERROR: <unknown>:26: failed to map: 'memory=new byte[pages][bytesPerPage]'
java.lang.IllegalArgumentException: <unknown>:26: failed to map: 'memory=new byte[pages][bytesPerPage]'

https://github.com/grundid/nfctools/blob/master/nfctools-core/src/main/java/org/nfctools/mf/ul/MemoryMap.java

solved this by adding a compiled version of the source as a jar as a dependency with -cp with the path to the jar
and renaming the file to have an extension other than java
also making a copy of the file with single dimension array, then fixing it manually

maybe it is still a bug. so I leave this open

Identify using statment patterns.

It would be nice to have a feature which is able to detect using patterns For example, if we have a try-finally statement and call of close method of AutoCloseable or Closeable interfaces then we can convert this try-finally statement to a C# using statement.

Mapping of string arrays within an interface

In Java, we can have something like this ::

public interface MyInterface {
   public const string[] MY_ARR = new string[] { "one", "two", "three};
}

Sharpen maps this to:

public abstract class MyInterface {
   public const string[] MY_ARR = new string[] { "one", "two", "three};
}

The generated code is not valid. I think this should be mapped to (which is valid) :

public abstract class MyInterface {
   public readonly string[] MY_ARR = { "one", "two", "three};
}

Is there a way around this issue without modifying the codebase? If not, perhaps I can help?

Add support for Java 8 lambdas

I think that here might be a problem. Because Java's lambdas are interfaces and C#'s lambdas are delegates we can have some problems converting them.

Invalid code generated for loops

The following function:

void errorExample() {
    if (true) {
        for (int i = 0; i < 3; i++) {
        }
    }

    for (int i = 0; i < 3; i++) {
    }

    if (true) {
        for (int i = 0; i < 3; i++) {
        }
    }
}

currently produces the following invalid result:

internal virtual void ErrorExample()
{
    if (true)
    {
        for (int i = 0; i < 3; i++)
        {
        }
    }
    for (int i_1 = 0; i_1 < 3; i_1++)
    {
    }
    if (true)
    {
        for (int i = 0; i_1 < 3; i_1++)
        {
        }
    }
}

Licensing terms

Not strictly an issue but perhaps you could add an FAQ with the answers to the following questions ....

I understand that Sharpen is license under GPL, but my question is what is the license status of generated C# code, and is there an LGPL (or other permissive license) version of wrapper classes for referenced JRE classes? Or perhaps each user has to create the wrapper classes themselves?

Conversion Failing for sample helloworld java program

I am trying to convert a sample program(helloworld) jar to c#. I tried below command but it is ended with error. I am trying to convert with out any configuration file(will that works?)

C:\Users\User1.m2\repository\sharpen\sharpencore\0.0.1-SNAPSHOT>java -jar sha
rpencore-0.0.1-SNAPSHOT-jar-with-dependencies.jar D:\Sharpenconvert -cp D:\Sharp
enconvert\tools2.jar
Configuration Class: null
Configuration Class: Sharpen.Runtime
project: D:
Pascal case mode: None
Conversion finished in 126ms.
ERROR: sourceFiles
java.lang.IllegalArgumentException: sourceFiles
at sharpen.core.framework.ConversionBatch.setsourceFiles(ConversionBatch
.java:57)
at sharpen.core.SharpenApplication.convertTo(SharpenApplication.java:142
)
at sharpen.core.SharpenApplication.convert(SharpenApplication.java:127)
at sharpen.core.SharpenApplication.safeRun(SharpenApplication.java:118)
at sharpen.core.SharpenApplication.start(SharpenApplication.java:57)
at sharpen.core.SharpenCmd.main(SharpenCmd.java:13)
Faied to run. Exception:sourceFiles

I know I did mistake but I don't know what it is exactly( I am not able to figure out even syntax also)
I googled for documentation/ sample code but I didn't find any, that is why I am asking here for immediate help.

Test failure

I followed the instructions, plus some tips I found in another issue, but my tests are failing. Windows 7, JDK 1.7.0_79 and JRE 7 (u80 I think) - don't know which one it's using. pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>sharpen</groupId>
  <artifactId>sharpencore</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>sharpencore</name>
  <url>https://github.com/imazen/sharpen</url>
    <organization>
        <name>Imazen</name>
        <url>http://www.imazen.io</url>
    </organization>
    <licenses>
        <license>
            <name>GPL 2 </name>
            <url>http://www.gnu.org/licenses/gpl-2.0.html</url>
            <distribution>repo</distribution>
            <comments>GPL 2 License</comments>
        </license>
    </licenses>
    <developers>
        <developer>
            <id>1</id>
            <name>Nathanael Jones</name>
            <email>[email protected]</email>
            <organization>Imazen</organization>
            <organizationUrl>http://www.imazen.io</organizationUrl>
            <roles>
                <role>Architect</role>
                <role>Developer</role>
            </roles>
            <timezone>-5</timezone>
        </developer>
        <developer>
            <id>2</id>
            <name>Yakov Danilov</name>
            <email>[email protected]</email>
            <organization>imazen.io</organization>
            <organizationUrl>http://www.imazen.io</organizationUrl>
            <roles>
                <role>Developer</role>
            </roles>
            <timezone>+3</timezone>
        </developer>
    </developers>
    <issueManagement>
        <system>github</system>
        <url>https://github.com/imazen/sharpen/issues</url>
    </issueManagement>
    <ciManagement>
        <system>travis</system>
        <url>https://travis-ci.org/imazen/sharpen</url>
    </ciManagement>
    <scm>
        <connection>scm:git:github.com:imazen/sharpen.git</connection>
        <developerConnection>scm:git:github.com:imazen/sharpen.git</developerConnection>
        <url>https://github.com/imazen/sharpen</url>
    </scm>
    <!--<distributionManagement>-->
        <!--<downloadUrl>https://oss.sonatype.org/content/groups/public</downloadUrl>-->
        <!--<repository>-->
            <!--<id>oss.sonatype.org</id>-->
            <!--<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>-->
        <!--</repository>-->
        <!--<snapshotRepository>-->
            <!--<id>oss.sonatype.org</id>-->
            <!--<url>https://oss.sonatype.org/content/repositories/snapshots</url>-->
        <!--</snapshotRepository>-->
        <!--<site>-->
            <!--<id>parent.jcabi.com</id>-->
            <!--<url>http://parent.jcabi.com/</url>-->
        <!--</site>-->
    <!--</distributionManagement>-->

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <finalName>${project.artifactId}-${project.version}</finalName>
  </properties>

  <dependencies>
    
    <dependency>
      <groupId>org.eclipse.jdt</groupId>
      <artifactId>org.eclipse.jdt.core</artifactId>
      <version>3.7.1</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.core</groupId>
      <artifactId>runtime</artifactId>
      <version>3.10.0-v20140318-2214</version>
    </dependency>
     <dependency>
      <groupId>org.eclipse.equinox</groupId>
      <artifactId>common</artifactId>
      <version>3.6.200-v20130402-1505</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.osgi</groupId>
      <artifactId>org.eclipse.osgi</artifactId>
      <version>3.6.0.v20100517</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.4</version>
      <scope>test</scope>
    </dependency>
    
  </dependencies>
  
  <build>
    <directory>src/target</directory>
    <outputDirectory>src/target/classes</outputDirectory>
    <finalName>${finalName}</finalName>
    <testOutputDirectory>src/target/testcases</testOutputDirectory>
    <sourceDirectory>src/main</sourceDirectory>
    <scriptSourceDirectory>src/main/resources</scriptSourceDirectory>
    <testSourceDirectory>src/test</testSourceDirectory>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>
    
    <plugins>
      
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>sharpen.core.SharpenCmd</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
            <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

	  <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>

    </plugins>
   
  </build>

  <profiles>
    <profile>
        <!--
        Static quality analysis with Qulice and other tools.
        This profile is supposed to be activated in continuous
        integration environment, right before the final approval
        of the build. It runs a number of static code analysis
        tools to validate and approve the quality of source
        code and the SCM repository.
        @see http://www.jcabi.com/jcabi-parent/profile-qulice.html
        -->
        <id>qulice</id>
        <build>
            <plugins>
                <plugin>
                    <!--
                    Qulice-maven-plugin is a compound static analysis
                    tool that aggregates Checkstyle, PMD, FindBugs,
                    CodeNarc (for Groovy code) and a few other analyzers.
                    Qulice also configures them correctly to enable the
                    most important rules.
                    @see http://www.qulice.com/qulice-maven-plugin/
                    -->
                    <groupId>com.qulice</groupId>
                    <artifactId>qulice-maven-plugin</artifactId>
                    <version>0.12</version>
                    <executions>
                        <execution>
                            <id>sharpen-check</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>check</goal>
                            </goals>
                            <configuration>
                                <license>file:${basedir}/LICENSE.txt</license>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
  </profiles>
</project>

There are a ton of test failures so I put the results in a zip file:

sharpen.ui.tests.zip

Maven plugin based on Sharpen

Hi Luis
as you can see on my github page (https://github.com/ggerla/java2csharp), I wrote a maven plugin to convert java classes in c#. Now I'm using Xml annotations and XSD schema transition.
I'd like to use the sharpen.core code to avoid to use xml and xsd. I already implemented an example and I think that for me it would a great solution.
Can I use your code (of course, I will change my license from Apache License to GPL)?

Suboptimal fallthrough analysis

The following switch statement produces an unreachable goto case statement in the translated code.

switch (x) {
case 0:
  if (something) {
    break;
  } else {
    break;
  }

case 1:
  break;
}

Configuration Loading is bad

The code in ConfigurationFactory to load the config jar uses the path of the sharpen jar INCLUDING the sharpen jar filename, so you would have to create a folder with the same name as the sharpen jar and drop your config files in there.

Suboptimal <see> and <seealso> tags

The C# code is generated with XML documentation tags that resemble the following:

<see cref="Item">Item</see>
<seealso cref="Item">Item</seealso>

When the text for the link is not explicitly specified, these should actually produce the following instead:

<see cref="Item"/>
<seealso cref="Item"/>

Create example

We should create a full, non-trivial conversion example, using a custom configuration class.

Incorrect mapping of Iterator.next()

The following code is mapped incorrectly :

Source Java

Collection<SomeClass> myCollection = getCollection();
SomeClass firstItem = myCollection.iterator().next(); // Assuming we know there is at least one item
doSomething(firstItem);

Generated C#

Collection<SomeClass> myCollection = getCollection();
SomeClass firstItem = myCollection .GetEnumerator().Next(); // ERROR Because there is no Next() method on the enumerator.
doSomething(firstItem);

Indexer usage missing parentheses

The following Java code:

if (visited.put(current.getParent(i), current.getParent(i)) == null) {
  workList.push(current.getParent(i));
}

Is currently producing the following C# code:

if (visited[current.GetParent(i)] = current.GetParent(i) == null)
{
  workList.Push(current.GetParent(i));
}

This is incorrect for two reasons:

  1. Parentheses are needed around the indexer usage.
  2. The return value of the put method is the old value stored in the map. The result of the assignment expression is the new value stored in the map. The semantics change results in a major logic error in code like is posted above.

Can't install wit Java 7 and maven 3

Hi,
on my system i've:

  • java version "1.7.0_80"
  • Apache Maven 3.6.2
    but when i run "mvn install" i get this error:
    [ERROR] Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.6: Could not transfer artifact org.apache.maven.plugins:maven-resources-plugin:pom:2.6 from/to central (https://repo.maven.apache.org/maven2): Received fatal alert: protocol_version

How can i fix it?

Thanks.
installing error

Incorrect conversion of classes declared inside of methods.

public class ContextFactory
{
    private static ContextFactory global = new ContextFactory();

    public interface GlobalSetter {
        public void setContextFactoryGlobal(ContextFactory factory);
        public ContextFactory getContextFactoryGlobal();
    }

    public synchronized static GlobalSetter getGlobalSetter() {
        if (hasCustomGlobal) {
            throw new IllegalStateException();
        }
        hasCustomGlobal = true;
        class GlobalSetterImpl implements GlobalSetter {
            public void setContextFactoryGlobal(ContextFactory factory) {
                global = factory == null ? new ContextFactory() : factory;
            }
            public ContextFactory getContextFactoryGlobal() {
                return global;
            }
        }
        return new GlobalSetterImpl();
    }
}

Is converted to

public class ContextFactory
{
        private static ContextFactory global = new ContextFactory();

    public interface GlobalSetter
    {
        void SetContextFactoryGlobal(ContextFactory factory);

        ContextFactory GetContextFactoryGlobal();
    }

    public static ContextFactory.GlobalSetter GetGlobalSetter()
    {
        lock (typeof(ContextFactory))
        {
            if (hasCustomGlobal)
            {
                throw new InvalidOperationException();
            }
            hasCustomGlobal = true;
            return new _T1664473621(this); // we are in the static method
        }
    }

    internal class _T1664473621 : ContextFactory.GlobalSetter // the name of a class is incorrect
    {
        public virtual void SetContextFactoryGlobal(ContextFactory factory)
        {
            ContextFactory.global = factory == null ? new ContextFactory() : factory;
        }

        public virtual ContextFactory GetContextFactoryGlobal()
        {
            return ContextFactory.global;
        }

        internal _T1664473621(ContextFactory _enclosing)
        {
            this._enclosing = _enclosing;
        }

        private readonly ContextFactory _enclosing;
    }
}

Invalid automatic interface implementation in abstract class

Sharpen generates incorrect code for the following input:

interface Foo {
    /** @sharpen.indexer */
    int get(int index);
}

abstract class AbstractFoo implements Foo {
}

Here is the current output.

internal interface IFoo
{
    int this[int index]
    {
        get;
    }
}

internal abstract class AbstractFoo : IFoo
{
    public abstract int Get(int arg1);
}

Dictionary get indexer used incorrectly

In Java, Map.get returns null when an element does not exist. In C#, the get indexer for IDictionary<TKey, TValue> throws an exception in the same scenario. Currently calls to get are getting translated into indexer usage, but this breaks the semantics for this operation. The correct code for this case would be the following:

Java:

T value = map.get(key);

C#:

T value;
map.TryGetValue(key, out value);

Incorrect treatment of java.lang.Boolean

If I have code

boolean myMethod() {
   Boolean myBool = null;
   myBool = something();
   return myBool;
}

It is converted to:

bool myMethod() {
   bool myBool = null; // INVALID AS BOOL IS PRIMITIVE IN C#
   myBool = something();
   return myBool;
}

Problem is that it converts Boolean and boolean as primitives, when the java code might depend upon a boolean being able to hold a null value.

A trivial but incorrect fix :

bool myMethod() {
   bool? myBool = null; // NOW VALID BECAUSE NULL IS NOW AN ACCEPTED VALUE
   myBool = something();
   return myBool; // NOW THIS IS AN INVALID BECAUSE C# does not unbox
}

Obviously, this logic is complex so perhaps the answer is to require (and check) that the java code does not use the unbox feature and simply translate boolean to bool?, and within the java code and translate the booleanValue() method on Boolean to the Value property on the bool? instance.

Possible complete solution (depends upon autounboxing detection)::

boolean myMethod() {
   Boolean myBool = null;
   myBool = something(); // Assuming something() is trusted not to return null
   return myBool.booleanValue(); // Manual UNBOXING
}
bool myMethod() {
   bool? myBool = null; // NOW VALID BECAUSE NULL IS NOW AN ACCEPTED VALUE
   myBool = something();
   return myBool.Value; // NOW VALID BECAUSE THIS IS A MANUAL UNBOXING TRANSLATED FROM JAVA
}

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.