Tool to convert javascript to Haxe Extern class files

2,884 views
Skip to first unread message

Huck

unread,
May 15, 2012, 9:18:49 PM5/15/12
to haxe...@googlegroups.com
Hello Haxers,

Im here to propose a solution to one of the biggest shortcommings of haxe on the javascript front. Haxe is really cool, but the fact that it is not compatible with javascript is a major issue to its success. Sure, we can create extern classes, but its a REAL pain to create and worst, they fall back behind in versions behind the javascript ones becuase they requuier so muhc maintenance. For any javascript developer, this is a major turnoff, and seriously, most people dont want to make their own externs for HUGE javascript libraries, they just want it to work.

so, i am here to offer a solution to this problem. I need to develop a website in haxe but needed to use jquery, jquery-ui and three.js. the haxe libraries for these files if they exist are ususally poorly maintained and out of date. so, i thought it would be cool to create a tool to convert javascript into a "best shot" version of haxe extern files. With a tool like this, it would become almost trivial to generate plenty of extern files for any javascript out there. The tool i created here is a demo, a hack i made to test the concept. It takes in a javascript file and generates a haxe extern file for all classes in the file. sure javascript doesnt have type info, but the tool can try to guess the types from the code and provides a best guess. the rest is set as Dynamic. So the tool greatly simplifies the operation of creating the externs, and then all is required is a quick sweep by a human to do the last touches. with a tool like this, if it is properly developped can greatly help haxe become the standard on the web.

so about the tool, it is written in c# (runs in mono perfectly too so on all plateforms) it uses JInt library to parse the javascript files (which uses ANTLR3). this library is highly efficient and parses successfully the most difficult javascript files. i tested against three.js and jquery.js. so this library parses the JS and returns a DOM of the code, which we can analyse and use to generate haxe code.

now, the project i made here is a demo and im ashamed to say the code is seriously crappy. it mostly works, but is far from perfect in current state. thats mostly because i dont have time to dedicate to this, so it was a hackfest for me in a single day to put this together to prove the concept. If i was to take put more time into it, i would rebuild it but with a proper structure and it could be very good. javascriopt is fairly simple, but has its quirks. So now, i suggest a haxe developper put just a few days into this tool to recreate it proper and it can become extremely powerful, and really give a big push to haxe on the web with javascript. As i said, if you look at the code you will see it is very easy to parse the javascript and recreate the structure for haxe.

So, again i hop someone will take this code and build it as it should, because if this tool works, it wll be a HUGE bonus for haxe, one that google dart doesnt even have yet... im here if you have questions,

regards,

note: i provide this code as is, with no warranty. i also dont have any time to put into this, so its a donation (hacky code anyways ;)).

note 2: im having troubles uploading the code, so i posted the code on this URL until i can get it to work on google groups.
 

Huck

unread,
May 15, 2012, 9:19:30 PM5/15/12
to haxe...@googlegroups.com
there we go, worked this time :)
JS2Haxe.7z

Marcelo de Moraes Serpa

unread,
May 15, 2012, 9:34:35 PM5/15/12
to haxe...@googlegroups.com
I also think Haxe for js dev can be the best thing since sliced bread. This sounds interesting, why not pushing to github? :)

I totally agree that the maintenance of externs is a pain.

As a side note though, I think the best thing would be to somehow include that into the Haxe compiler itself, as part of the js-gen stuff? Or, create a build tool and compile to Neko.

My two cents,

- Marcelo


Message has been deleted

Huck

unread,
May 15, 2012, 10:03:38 PM5/15/12
to haxe...@googlegroups.com

And here is a sample haxe file generated by the tool for Three.js version r49. Sure its not perfect, but its pretty good considering it was created by a single day hackathon and that the tool generated this file in a single second.

Again if another dev gives it a few days of proper love, REALLY good stuff can come out of this idea for haxe.

regards,


three.test.hx

Philippe Elsass

unread,
May 16, 2012, 3:45:35 AM5/16/12
to haxe...@googlegroups.com
Looks like a good direction, three.js is a particularly complex source...

Another option, with JS, is to load the library in a browser and to explore it "live" - but the parser solution gives you a chance to get the comments.




--
Philippe

Tony Polinelli

unread,
May 16, 2012, 5:52:39 AM5/16/12
to haxe...@googlegroups.com
nice idea- it seems to produce a lot of Dynamic's tho - wouldnt this
make the usefullness of haxe a little limited ?
Tony Polinelli
http://touchmypixel.com

Nicolas Cannasse

unread,
May 16, 2012, 6:52:46 AM5/16/12
to haxe...@googlegroups.com
Le 16/05/2012 03:18, Huck a �crit :
> Hello Haxers,
>
> Im here to propose a solution to one of the biggest shortcommings of
> haxe on the javascript front. Haxe is really cool, but the fact that it
> is not compatible with javascript is a major issue to its success. Sure,
> we can create extern classes, but its a REAL pain to create and worst,
> they fall back behind in versions behind the javascript ones becuase
> they requuier so muhc maintenance. For any javascript developer, this is
> a major turnoff, and seriously, most people dont want to make their own
> externs for HUGE javascript libraries, they just want it to work.
[...]

Hi,

While I completely agree with the issue itself, I'm not sure an
automated tool is the best solution.

Haxe developers should expect that quality externs are available, and by
"quality" I mean that people took time to read the library documentation
and strictly type the extern API, add the overloads, etc.

I think there's several approachs for that :

- using an automatic tool to allow to extract the first "untyped"
version, then work on make it typed

- extract directly the typed version from the HTML documentation of the
library, but there is no real documentation standard and it can break
easily if they change the output/engine

For instance, I'm using an automated extracting tool for Flash API -
which is a lot more easy since it's strictly typed - but I still have to
do some extra manual work to add a bit more strict typing (using enums
instead of String where it makes sense) and other things such as
@:require version annotations.

In the end, I think what we need is people who have enough time to
dedicate maintaining good quality externs, I'm not sure we can do it
magically.

Anyway thank you for the effort, I'm sure it will help other people.
Might be quite complementary with what Joshua is doing.

Best,
Nicolas

Huck

unread,
May 16, 2012, 8:43:29 AM5/16/12
to haxe...@googlegroups.com
Here are some clarifications

becasue of javascript's untyped nature, its impossible to determine ALL the parameter types. but, it is possible to determine many from the code itself (variable assignments, return values, etc.).The example i produced here was a quick prototype and yes it has a lot of dynamics, but i did only 5% of the deduction work,  if the tool was properly built, we could find much much more and get at least 80% of data types correctly filed in.

now @ nicholas: for sure any class generated by a tool would have to be reviewed by a human, but at least the tool can make 98% of the work, leaving humans with a simple review to add whats missing. It would become trivial to maintain and add new externs for the fast moving javascript world. Without it, all the work must be done manually, and i have enough experience in software programming and opensource work to know that versions fall behind, always. it is even the case now. three.js is at r47 and jquery is largely incomplete. and jquery-ui? and other proprietary javascript libraries?

now, sadly i dont have any more time to dedicate to this tool, im on short shcedule project, but i wanted to get the ball rolling and demonstrate the large potential it has. This tool will make a huge difference in haxe ecosystem, but for this it has to be developed. the code i posted here is only a prototype, but it needs a developer assigned a few days on it to start from scratch and redesign it correctly using Jint and build this tool.

i really hope someone can take the ball from here and work on it. and remember, even google dart doesn't have it and its a huge limiting factor for it as well. here is a chance to get ahead before coffeescript takes it all...

clemos

unread,
May 16, 2012, 9:13:49 AM5/16/12
to haxe...@googlegroups.com
Hi

The tool looks very promising.

I have also been working on a similar tool for PHP, which takes
peardoc xmls and generates externs from them.
I also made one before for Java / javadoc, when I was working on HaXe
+ Red5 with Rhino...

I have never released any of them because there are still two quite
big issues I never really managed to solve:

- you'll likely need to manually change some definitions, to type them
more, change them or correct them, etc,
and then all this is deleted when you generate the externs again...
So you need a good "patching" mecanism to have enough flexibility.

- in PHP there is a quite annoying issue with (anonymous) objects vs
associative arrays.
Most PHP APIs will use associative array, so you have to convert these
to anonymous at runtime, and the other way round...
I think it may be possible to do this more or less cleanly with
macros, but I have never had the time to really try that.

Anyway, I have had a quick look at Joshua's BuildHx and it looks
really promising.
https://github.com/jgranick/buildhx
It seems to solve my first issue by providing a nice way to alter
generated definitions with a .xml "patch".
Moreover it seems modular and easy to extend. This was not the case
for my projects either...

I think we should join forces on this, and use a common structure to
solve the extern generation, and BuildHx is a very good start.
I'll try to add php support to it when I have some time.
I think you may also want to check this project and maybe contribute.

Regards,
Clément

Huck

unread,
May 16, 2012, 9:27:01 AM5/16/12
to haxe...@googlegroups.com
cool, now were talking :)

the big "breakthrough" in my tool above is the use if Jint (http://jint.codeplex.com/) which does an amazing job at parsing even the most complicated javascript files (parsed jquery and three without a hintch) adn returns a DOM of the code, easy to read. This in itself is very powerful as it allows to reverse engineer the code, and generate "something". be it haxe externs or more.

now buildhx still seems to require JSDuck tags, and xml definitions, these must still be written and maintained, its one evil for another. So the use of Jint could be the perfect complement to buildhx. Instead of generating .hx externs with Jint, we could generate the xmls, and then merge the changes with existing ones. Then after use buildhx to compile them. The way we do it to me is irrelevant, as long as we do it.

i think that if we can fix the javascript/haxe dependence mismatch, haxe can truly shine and become mass market in the HUGE javascript world.

in the end, i agree we should all give some time to this issue, as it will bring more users, and thus a bigger and more alive community; good for us.

Huck

unread,
May 16, 2012, 9:35:55 AM5/16/12
to haxe...@googlegroups.com
a quick addendum to aboce. The problem with buildhx is that it requires JSDuck annotations, but most javascript projects dont have them, and we cant expect that they will add them. so it kinda kills the purpose of the tool for a pan-javascript world generator.

now, an idea occurred to me. if i was to redesign this tool, i would proceed by parsing the javascript DOM created by Jint, and recreate one in memory that maps to "any" OOP language. (example, class A, has 2 variables, B and C, and ahh, this function determines B as an Int, and ahh, this one determines C as a class with this prototype...).  so we would end up with our own custom DOM in memory, and from this DOM, i could output haxe externs, or literally convert the javascript to full haxe, or c++, or java, etc. now the beauty of this is that this DOM in memory could be serialized to xml, yaml or whatever. the users could then add their refinements to the missing parts of this xml used to generate the JavaScript. and reloaded at every new generation. we could then add the delta from the javascript, while maintaining the changes done by hand. hence allowing to keep improvements.

just ideas here. and in another design approach it could be used to generate either JSDuck metadata for buildhx, or the xmls themselves.

lots of possibilities indeed from actually deep reading into the javascript of ANY library..

clemos

unread,
May 16, 2012, 9:44:08 AM5/16/12
to haxe...@googlegroups.com
Hi Huck

From what I understand BuildHx "currently" uses JSDuck,
But one could create his own parser to support other input material
(see: https://github.com/jgranick/buildhx/tree/master/buildhx/parsers)
At least, that's what I was planning to do for PHP/peardoc...

Regards,
Clément

Joshua Granick

unread,
May 16, 2012, 1:19:48 PM5/16/12
to haxe...@googlegroups.com
BuildHX was built off an older tool I created which was able to parse
JSDuck output to generate JS extern classes automatically.

I recently improved on the prior tool to open the door for multiple kinds
of parsing, as well as manual definitions in an XML file. When you are
able to parse documents to generate the definitions automatically, you may
still need to tweak or adjust the types by hand. BuildHX is designed to
allow this workflow.

Fintan Boyle recently contributed a YUIDoc parser, so you can use BuildHX
to generate externs for libraries like the EaselJS framework.

You can use BuildHX in cases where you do not have an automated solution
to load the types and definitions for the target library. The "joapp" and
"box2d-native" projects that I have on GitHub are both manually defined.

If you are able to automatically derive types using JInt, you could create
a JIntParser for BuildHX, which could read a source directory and populate
the types it finds there:


<source path="my/js/files" parser="jint" />



Similar to what I have done for Sencha Touch, you could fill in the blanks
manually with the rest of the XML definition file for any given library.

I am also investigating Doxygen, which can help export types for C++
libraries. It would be great to have an automated path for generating C++
bindings.

BuildHX is not written in C#... it's in Haxe, of course, but that makes it
easier for it to run on multiple platforms using Neko.

Cauê Waneck

unread,
May 16, 2012, 1:26:00 PM5/16/12
to haxe...@googlegroups.com
I recently improved on the prior tool to open the door for multiple kinds of parsing, as well as manual definitions in an XML file. When you are able to parse documents to generate the definitions automatically, you may still need to tweak or adjust the types by hand. BuildHX is designed to allow this workflow.

That's very cool! 

If you are able to automatically derive types using JInt, you could create a JIntParser for BuildHX, which could read a source directory and populate the types it finds there:

 <source path="my/js/files" parser="jint" />

Similar to what I have done for Sencha Touch, you could fill in the blanks manually with the rest of the XML definition file for any given library.
BuildHX is not written in C#... it's in Haxe, of course, but that makes it easier for it to run on multiple platforms using Neko.

I can try to compile it with the c# generator, It'll be a good test, and we'll be able to use Jint! :) 

Huck

unread,
May 16, 2012, 1:38:55 PM5/16/12
to haxe...@googlegroups.com
Cool!  things are getting really interesting now :) I think using Jint to supplement buildhx is a great idea.

I have trouble finding free time, but at the same time i believe this is a really good cause, so let me know if i can help in any way (only can give so much time though).

for one i've had some experience yesterday with the output from Jint, so i can definitely give some advice on how to use it.

first, throw away the code i did yesterday, its a mess and should be considered for instructional purposes only.

but Jint provides a DOM of the javascript code which can be parsed, each line is a statement, and each statement is made of various expression clauses of different nature. So i suggest building an iterator for each statement/expression from the Jint DOM and build an internal representation of the useful data. each time a returnStatement or an assignment expression is found, use the Member info to lookup the types and restore type information from code analysis. then this internal DOm could be serialized both ways into XML, and/or merged with the buildhx xml format. every javascript parsing could apply the delta to the exising DOM, hence updating the definition with each successive new javascript file version.

might seem complicated but its actually pretty simple, the trick is just to build a proper iterative analyser for the Jint DOM. let me know if there is anything else i can do to help.

regards,

Cauê Waneck

unread,
May 16, 2012, 1:43:18 PM5/16/12
to haxe...@googlegroups.com
Cool! I'll have a look at what you did later on! :)

2012/5/16 Huck <jdboud...@gmail.com>

Joshua Granick

unread,
May 16, 2012, 2:14:45 PM5/16/12
to haxe...@googlegroups.com
Since BuildHX is compiled for Neko, it can be distributed and used from haxelib. Ideally, I would like to continue this setup, so I don't think the tool should be compiled as C#.

However, we could create a standalone Jint-based executable and put it in the "/bin" directory along with jsduck and (probably) doxygen. It could accept a directory of JS files, and output type information in JSON or XML files.

These could either be formatted natively for BuildHX, or BuildHX could have a parser to understand it. I would recommend the latter, since that would allow much more verbose type information (dumping almost all the information you can get) which we could then sort through and use. Although there is information that would not be used for now, you never know how things might grow in the future. Having a verbose output format may make it easier to improve later in BuildHX.

Huck

unread,
May 16, 2012, 2:17:15 PM5/16/12
to haxe...@googlegroups.com
yeah, this is how i would see it too, as an external utility tool to be invoked from buildhx. thanks to mono it can run pretty much on any platform neko can.

Cauê Waneck

unread,
May 16, 2012, 2:28:16 PM5/16/12
to haxe...@googlegroups.com
Since BuildHX is compiled for Neko, it can be distributed and used from haxelib. Ideally, I would like to continue this setup, so I don't think the tool should be compiled as C#.

Yes, makes sense. Even though the neko app.n could just invoke e.g. mono or the executable, it really means that we will have to depend on the user having mono or .Net runtime installed.

However, we could create a standalone Jint-based executable and put it in the "/bin" directory along with jsduck and (probably) doxygen. It could accept a directory of JS files, and output 
type information in JSON or XML files.

Ok, seems good! I'll leave it to use the C# target for an actual project later then ! hahaha 

Jimm Pratt

unread,
Sep 8, 2015, 3:16:07 AM9/8/15
to Haxe


On Wednesday, 16 May 2012 03:18:49 UTC+2, Huck wrote:
Hello Haxers,

Im here to propose a solution to one of the biggest shortcommings of haxe on the javascript front

Greetings Huck!

I realize I'm late to the party, but as I recently joined a company that uses Haxe for Flash-to-Javascript development, I started Googling for the reverse to convert stuff I've written in JS a bit easier than doing it by hand.  And voilá, here I am.  Has this 'project' progressed any further in recent years?  Or are there other open-sourced tools available that my Google-search-fu is failing to find? 

Yaroslav Sivakov

unread,
Sep 9, 2015, 6:04:43 AM9/9/15
to Haxe
Hello, Jimm! I port several libs from js to haxe and may recommend you pre-process js files with refactor (http://lib.haxe.org/p/refactor), then - manual editing. Just install refactor library and run from scripts folder:
js_to_haxe.cmd <path_to_js_source_directory>

Message has been deleted

[mck]

unread,
Sep 19, 2015, 6:08:40 AM9/19/15
to Haxe
Hi Yaroslav,

I am currently working on documenting Haxe and Javascript
http://matthijskamstra.github.io/haxejs/
and Haxe and Node.js
http://matthijskamstra.github.io/haxenode/

I wanted to write a piece about automated conversion of externs.
Your project looks like it could be helpful, but I don't get it to work.

Currently I think it's for windows and I work on mac

Is this true?

grt
Matthijs

Yaroslav Sivakov

unread,
Sep 19, 2015, 6:34:24 AM9/19/15
to haxe...@googlegroups.com
Hello, Matthijs!

I test refactor only on Windows, but I don't use platform-specific things (*.cmd helpers are for Windows only, but you can call "haxelib run refactor" directly, it must work on Mac64 too).
Try:
    haxelib run refactor convert --exclude-string-literals --exclude-comments PATH_TO_SOURCE_JS_FOLDER *.js PATH_TO_DEST_HAXE_FOLDER /[.]js/.hx/ js_to_haxe.rules




19.09.2015 13:06, Matthijs Kamstra пишет:
Hi Yaroslav, 

I am currently working on documenting Haxe and Javascript 
and Haxe and Node.js

I wanted to write a piece about automated conversion of externs.
Your project looks like it could be helpful, but I don't get it to work.

Currently I think it's for windows and I work on mac

Is this true?

grt 
Matthijs



On Wednesday, September 9, 2015 at 12:04:43 PM UTC+2, Yaroslav Sivakov wrote:
Hello, Jimm! I port several libs from js to haxe and may recommend you pre-process js files with refactor (http://lib.haxe.org/p/refactor), then - manual editing. Just install refactor library and run from scripts folder:
js_to_haxe.cmd <path_to_js_source_directory>


 
---
You received this message because you are subscribed to a topic in the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

--

Yaroslav Sivakov

[mck]

unread,
Sep 22, 2015, 9:09:48 AM9/22/15
to Haxe
Awesome it works,
I could have figured this out myself

but thx


I will see if it helps with conversion to javascript externs

Jimm Pratt

unread,
Sep 22, 2015, 10:23:15 AM9/22/15
to Haxe
On Wednesday, 9 September 2015 12:04:43 UTC+2, Yaroslav Sivakov wrote:
Hello, Jimm! I port several libs from js to haxe and may recommend you pre-process js files with refactor (http://lib.haxe.org/p/refactor), then - manual editing. Just install refactor library and run from scripts folder:
js_to_haxe.cmd <path_to_js_source_directory>


Thanks for the info!  Installed refactor, jumped into the scripts folder and tried:

js_to_haxe.cmd e:\wyndorfcomponents\html5\audio\test\js\screenfull.js


and got a warning about not providing destination... so I mod'd my line:

js_to_haxe.cmd e:\wyndorfcomponents\html5\audio\test\js\screenfull.js e:\wyndorfcomponents\html5\audio\test\js\screenfull.hx


and get back the prompt.  no file appears in either the scripts folder or the destination.   strange...   :( 

Yaroslav Sivakov

unread,
Sep 22, 2015, 10:26:17 AM9/22/15
to haxe...@googlegroups.com
Please, try:
js_to_haxe.cmd e:\wyndorfcomponents\html5\audio\test\js e:\wyndorfcomponents\html5\audio\test\js


22.09.2015 17:23, Jimm Pratt пишет:
--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

--

Yaroslav Sivakov

Jimm Pratt

unread,
Sep 22, 2015, 10:31:45 AM9/22/15
to Haxe


On Tuesday, 22 September 2015 16:26:17 UTC+2, Yaroslav Sivakov wrote:
Please, try:
js_to_haxe.cmd e:\wyndorfcomponents\html5\audio\test\js e:\wyndorfcomponents\html5\audio\test\js


Oddly enough, that *did* work!  Or, at least generated .hx files for all files in the directory.

Thanks for the input!  Now to see if it really made a conversion...

-jimm 

Confidant

unread,
Oct 13, 2016, 6:45:43 PM10/13/16
to Haxe
haxelib run refactor

…does not seem to work on Mac. :(

jacek szymanski

unread,
Oct 14, 2016, 3:20:23 AM10/14/16
to haxe...@googlegroups.com

It uses a .ndll which I once compiled and submitted, perhaps it's out of date, but it seems it works for me. Could you post some error message?


js.





From: Confidant
Sent: Friday, October 14, 2016 12:45AM
To: Haxe
Subject: [haxe] Re: Tool to convert javascript to Haxe Extern class files

haxelib run refactor

…does not seem to work on Mac. :(
You received this message because you are subscribed to the Google Groups "Haxe" group.
Message has been deleted

Confidant

unread,
Oct 14, 2016, 11:51:33 PM10/14/16
to Haxe
I hope I'm not missing something glaringly obvious; I have never used haxelib this way before. Anyway, first I tried:

>haxelib run refactor js_to_haxe x3dom.js
ERROR
: Unknow command 'js_to_haxe'.

Then I did this:

>haxelib run refactor js_to_haxe.cmd x3dom.js
Called from ? line 1
Called from Main.hx line 69
Called from hant/Process.hx line 190
Called from hant/Process.hx line 95
Called from a C function
Called from hant/Process.hx line 169
Uncaught exception - Process creation failure : /usr/lib/haxe/lib/refactor/3,4,1/scripts/js_to_haxe.cmd

Yaroslav Sivakov

unread,
Oct 15, 2016, 4:04:40 AM10/15/16
to Haxe
To convert one file:

haxelib run refactor convertFile --exclude-string-literals --exclude-comments INPUT_FILE.js OUTPUT_FILE.hx js_to_haxe.rules

To convert many files:

haxelib run refactor convert --exclude-string-literals --exclude-comments INPUT_DIR *.js OUTPUT_DIR /[.]js$/.hx/ js_to_haxe.rules

Confidant

unread,
Oct 16, 2016, 10:49:32 PM10/16/16
to Haxe
I get this now:

haxelib run refactor convertFile --exclude-string-literals --exclude-comments x3dom.js x3dom.hx js_to_haxe.rules

Called from ? line 1
Called from Main.hx line 53
Called from Commands.hx line 344

Called from a C function
Called from RefactorConvert.hx line 17

Called from a C function
Called from RefactorReplace.hx line 43
Called from TextFile.hx line 57
Called from RefactorReplace.hx line 45
Called from RefactorReplace.hx line 70
Called from C:\MyProg\_tools\motion-twin\haxe\std/neko/_std/EReg.hx line 66
Uncaught exception - An error occured while running pcre_exec
MacBookPro:dist allan$

I'm wondering about that reference to the C: drive because that is not on my computer.

Yaroslav Sivakov

unread,
Oct 17, 2016, 7:46:18 AM10/17/16
to Haxe
Hello, Confidant! I download x3dom.js and test: same error. Now I have several comments:

1) refactor/convert is not fully-automated tool: it is a helper to decrease manual work while converting;
2) x3dom.js is minificated JS, that not suitable for partially-manual conversion, you need original library code to place into refactor/convert (at least, you must beauty the code);
3) exception related to very long lines in your x3dom.js (refactor use neko/pcre library for conversion, which not support very long lines);
4) file x3dom.js is too big for such type of conversion (again: please, use original sources).

Confidant

unread,
Oct 17, 2016, 12:03:21 PM10/17/16
to Haxe
Very helpful, thank you!
Reply all
Reply to author
Forward
0 new messages