In Search of Concise Software

A journey to find those pieces of software or technology that facilitate productive and maintainable software development

Thursday, June 11, 2009

ErlIDE for low-memory machines

If you are like me and have been using ErlIDE only occasionally because of the memory requirements of Eclipse. To be absolutely honest ErlIDE added to Eclipse IDE for Java Developers runs too slowly for my tastes on my Mac mini. I felt like I would have to upgrade my RAM just to run it tolerably. This is due to a combination of Eclipse's gradually growing system requirements and my extreme performance expectations arising from using an 8-core 64-bit workstation with 8GB of RAM at work.

I took a minimalist approach knowing that Eclipse piles around twenty auxiliary features for useful, but non-essential (for ErlIDE) things like Java, ANT, web, CVS, XML and task-focused UI support. Basing my new ErlIDE on the bare Eclipse 3.4 Platform Runtime yielded a much snappier experience and significantly less physical and virtual memory usage.

So in summary, if you want a speedier ErlIDE on a lower-end machine do the following:

  1. Download Eclipse 3.4.2 Platform Runtime
  2. Run Eclipse
  3. Install ErlIDE through Help->Software Updates...
  4. Enjoy a (hopefully) faster, lighter ErlIDE

Thursday, March 26, 2009

Erlang R13A for MacPorts

UPDATE: Just selfupdate MacPorts if it isn't showing R12B (which is now released) and update erlang instead.

UPDATE: I have rewritten this article after reading Jim's comment on how to set up a local MacPorts repository.

Since there is not yet a Portfile for Erlang R13A in MacPorts I built one myself. MacPorts makes this remarkably easy since the Portfile format is so easy to read and write.

Save the following as ~/Desktop/Portfile:

# $Id$

PortSystem 1.0
name  erlang
version  R13A
revision        1
categories lang erlang
maintainers gmail.com:alain.odea
platforms darwin
description The Erlang Programming Language
long_description                                                        \
                Erlang is a programming language designed at the        \
                Ericsson Computer Science Laboratory. Open-source       \
                Erlang is being released to help encourage the spread   \
                of Erlang outside Ericsson.                             \
                                                                        \
                We are releasing free of charge:                        \
                    The entire source code of the current Erlang        \
                    system.                                             \
                    Extensive libraries of code for building robust     \
                    fault-tolerant distributed applications.            \
                    All with documentation.                             \
                                                                        \
                All the above software has been battle tested in a      \
                number of Ericsson products, for example the new        \
                Ericsson ATM switch. 

homepage        http://www.erlang.org/
master_sites    http://www.erlang.org/download/                         \
                http://www3.erlang.org/download/                        \
                http://www.csd.uu.se/ftp/mirror/erlang/download/        \
                http://www1.erlang.org/download/
                

distfiles       otp_src_${version}${extract.suffix}                    \
                otp_doc_man_${version}${extract.suffix}                \
                otp_doc_html_${version}${extract.suffix}

checksums       otp_src_R13A.tar.gz \
                    md5     76804ff9c18710184cf0c0230a0443fc \
                    sha1    9fa0db27611559d697fe269c3fb9a405ae24d147 \
                    rmd160  42ba3c4815fa702d19281f1d42faaec72a75c703 \
                otp_doc_man_R13A.tar.gz \
                    md5     883e097796abd2cda4727fe3527dc1b6 \
                    sha1    98ce2fbc2daf7ec88ca38334412b9e85ca9cd53c \
                    rmd160  c082bda26b85cd6bd2ede8dd2c538e2ef50bbd2c \
                otp_doc_html_R13A.tar.gz \
                    md5     2bbecc1c5537e0cd1c0fc406082b6c56 \
                    sha1    fb3ed9c0d619d8bbd70af5c6b0e4e90c49771e0d \
                    rmd160  873b30cd8c5f2617c62aba0314197c54097a27cf

extract.only    otp_src_${version}${extract.suffix}

pre-patch       { file rename ${workpath}/otp_src_${version} ${workpath}/${name}-${version} }

# http://www.erlang.org/pipermail/erlang-bugs/2008-October/001023.html
# http://www.erlang.org/pipermail/erlang-bugs/2008-October/001024.html
# http://support.process-one.net/browse/EUNIT-13
patchfiles patch-toolbar.erl \
                patch-erts_emulator_Makefile.in \
                patch-lib_ssl_c_src_esock_openssl.c \
                patch-lib_ssl_c_src_Makefile.dist \
                patch-lib_ssl_c_src_Makefile.in \
                patch-decode_big.c.diff \
                patch-decode_fun.c.diff \
                patch-eunit_xml.diff

configure.args  --prefix=${destroot}${prefix} \
                --enable-kernel-poll            \
                --disable-smp-support           \
                --enable-hipe

variant smp description {enable symmetric multiprocessing} {
 configure.args-delete --disable-smp-support
}

variant ssl description {enable SSL/TLS encryption} {
 configure.args-append    --with-ssl=${prefix}
 configure.ldflags-append -lz
 depends_build-append     port:openssl
 depends_run-append       port:openssl
}

variant no_hipe description {disable HiPE native compilation support} {
 # Currently produces bus errors in 10.5.3 due to changes in
 # signal handling
 configure.args-delete   --enable-hipe
}


platform i386 {
   pre-configure {
      file copy ${filespath}/mach_override.h ${workpath}/${name}-${version}/erts/emulator/hipe
      file copy ${filespath}/mach_override.c ${workpath}/${name}-${version}/erts/emulator/hipe
   }
}



depends_build   port:gawk \
                port:wxWidgets
depends_run     port:tk

post-destroot {
 system "tar -C ${destroot}${prefix}/lib/erlang -zxvf ${distpath}/otp_doc_html_${version}${extract.suffix}"
 system "tar -C ${destroot}${prefix}/lib/erlang -zxvf ${distpath}/otp_doc_man_${version}${extract.suffix}"
 
        set erts_dir   erts-5.7

        reinplace s|${destroot}|| ${destroot}${prefix}/lib/erlang/bin/erl
        reinplace s|${destroot}|| ${destroot}${prefix}/lib/erlang/bin/start
        reinplace s|${destroot}|| ${destroot}${prefix}/lib/erlang/${erts_dir}/bin/erl
        reinplace s|${destroot}|| ${destroot}${prefix}/lib/erlang/${erts_dir}/bin/start

 foreach x {dialyzer ear ecc elink epmd erl erlc escript run_erl start to_erl typer} { file delete -force ${destroot}${prefix}/bin/${x} }
 foreach x {dialyzer erl erlc escript run_erl start to_erl typer} { system "ln -s ../lib/erlang/bin/${x} ${destroot}${prefix}/bin/${x}" }

 file delete -force ${destroot}${prefix}/lib/erlang/bin/epmd
 system "ln -s ../${erts_dir}/bin/epmd ${destroot}${prefix}/lib/erlang/bin/epmd"
}

Save the following script to ~/Desktop/mkerlangport.sh:

#!/usr/bin/env bash
macports_repo=/opt/local/var/macports/sources/rsync.macports.org
local_repo=/opt/local/var/macports/sources/local
sources=/opt/local/etc/macports/sources.conf
port=lang/erlang
cat ${sources} | grep file://${local_repo} > /dev/null
if [ ! $? ]
then
    tmpfile=`mktemp -t sources.conf`
    cat ${sources} > ${tmpfile}
    echo "file://${local_repo} [nosync]" | cat ${tmpfile} > ${sources}
fi
mkdir -p ${local_repo}/${port}/files
cp ${macports_repo}/release/ports/${port}/files/* ${local_repo}/${port}/files
cp ~/Desktop/Portfile ${local_repo}/${port}/Portfile
portindex ${local_repo}

Run this script in terminal as sudo bash ~/Desktop/mkerlangport.sh. It should report

Creating software index in /opt/local/var/macports/sources/local
Adding port lang/erlang

Total number of ports parsed: 1 
Ports successfully parsed: 1  
Ports failed:   0

Once you have created the Portfile and installed it as instructed above you can sudo port install erlang @R13A +smp +ssl to get R13A. If you have R12B already installed you should sudo port deactivate erlang first. I am not sure if upgrade works since I haven't tried it.

Wednesday, February 25, 2009

Instant Windows SVN Server with SSL and ActiveDirectory

I am not joking. After a significant amount of fiddling and application of Occam's Razor I have come to a configuration of Apache 2.2 that delivers a completely functional and relatively secure SVN server. To be honest it isn't instant, but it is pretty easy to do and will give a robust configuration that should not need post-install tweaking.

Get the pre-requisite software and libraries in place

  1. Download and install the MSI for Apache 2.2 for Windows with OpenSSL
  2. Download the archive of Apache 2.2 Subversion binaries
  3. Extract svn-win32-1.5.5.zip
  4. Copy bin\intl3_svn.dll and bin\libdb44.dll to Apache2.2\bin
  5. Copy bin\mod_authz_svn.so and bin\mod_dav_svn.so to Apache2.2\modules
  6. Download the Apache 2.2 version of mod_auth_sspi
  7. Extract mod_auth_sspi-1.0.4-2.2.2.zip
  8. Copy bin\mod_auth_sspi.so to Apache2.2\modules

Sign Yourself an SSL Certificate (it is better to buy one, but this is cheaper)

Create Apache2.2\createSSLCert.bat with the following content:
bin\openssl req -config conf\openssl.cnf -new -out my-server.csr
bin\openssl genrsa -out conf\privkey.pem 2048
bin\openssl rsa -in conf\privkey.pem -out conf\server.key
bin\openssl req -new -key conf\server.key -out conf\server.csr -config conf\openssl.cnf
bin\openssl x509 -in conf\server.csr -out conf\server.crt -req -signkey conf\server.key -days 4000
bin\openssl x509 -in conf\server.crt -out conf\server.der.crt -outform DER

Carefully fill out the SSL Certificate Details

It is critical that the Common Name on the Certificate match the fully qualified domain name of the server. I found that Apache was unable to use it for SSL otherwise. A mismatched Common Name (CN) also confuses the hell out of client software. Double-click createSSLCert.bat to start the process of building the SSL cert and key. There are a lot of prompts so be patient.

Create new file Apache2.2\conf\extras\httpd-dav-svn.conf:

LoadModule ssl_module modules/mod_ssl.so
LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule sspi_auth_module modules/mod_auth_sspi.so
Listen 443
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl
SSLPassPhraseDialog  builtin
SSLSessionCache        shm:logs/ssl_scache(512000)
SSLSessionCacheTimeout  300
SSLMutex default
<VirtualHost _default_:443>
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile conf/server.crt
SSLCertificateKeyFile conf/server.key
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
CustomLog logs/ssl_request.log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
<Location />
    DAV svn
    SVNListParentPath on
    SVNParentPath C:/Repositories
    AuthType SSPI
    SSPIAuth On
    SSPIAuthoritative On
    SSPIOfferBasic On
    SSPIBasicPreferred On
#    SSPIDomain DEVDOMAIN (Optional)
    Require valid-user
</Location>
</VirtualHost>
Add to end of Apache2.2\conf\httpd.conf:
Include conf/extra/httpd-dav-svn.conf

IMPORTANT: Restart the server (use shutdown -r -t 3 from the Command Prompt if you are using RDP)
You need to restart because otherwise the modules will not load correctly. I am not exactly sure why, but I tried this several times without restarting and it failed every time. This is not superstition it is actually required.

Add a new repository to your server

  1. Add svn-win32-1.5.5\bin to your System Path
  2. Run svnadmin create C:\Repositories\svn

One particularly nice thing is that you can add any number of repositories without having to dig into Apache's config and without restarting Apache.

Take a look at https://localhost/ with your web browser. You should now have a functional Subversion server authenticating against your ActiveDirectory Domain listing svn as a repository. Enjoy :)

Tested Working Clients

  • svn command line on Windows
  • Internet Explorer 6 on Windows
  • Chrome on Windows
  • Firefox on Windows
  • svn command line on Mac OS X
  • Subversive in Eclipse on Mac OS X
  • WebKit on Mac OS X

Oddly enough Internet Explorer actually chokes if SSPIBasicPreferred is not on. In theory it should successfully authenticate with NTLM in the single sign-on style, but it hangs or gets rejected by the server instead. We are using SSL anyway so HTTP Basic is reasonably safe.

Saturday, December 27, 2008

Alas Poor Erlang, I Knew Ye Well!

UPDATE: the negativity about Erlang in this post no longer reflects my current opinion. Thank you Justin Sheehy for making webmachine which has handily carried me across my hurdles with implementing RESTful Web Services in Erlang.

The death of useful insight from a new idea encountered or approach studied begins a time of denial for me and then a time of mourning. Erlang stopped providing me with useful insight months ago, yet I doggedly pursued it hoping I would experience more of the mind-opening joy I had when I first encountered it. This has not happened. Worse than that I feel a seething resentment for Erlang now since it continually pops up in my head as a possible solution to things I am ill-equipped to solve using it. None of this is a fault of Erlang, but rather a reality of my inexperience with Functional Programming and the lack of modules in Erlang for structuring and developing RESTful Web Services the way I would like (UPDATE: WebMachine looks like it may invalidate this post, stay tuned).

Certainly Yaws and mochiweb let you build RESTful Web Services, but I find myself fumbling with them rather than solving my real domain problems. I am not sure if this is a side-effect of transparent data structures in Erlang vs objects in Java or what. I do know that I find it easier to grow a solution gradually with Restlet (a Java REST framework). Nothing inherently prevents Erlang from providing developers with a good framework for building RESTful Web Services. I believe Erlang is inherently better suited to the purpose at a runtime level than Java, but Yaws and mochiweb do not fit my way of thinking.

It would be very interesting to see OTP-style behaviours for Resources and Routers (and the various other actors of the Restlet framework) which could be implemented simply in Erlang. Much of the design is already there in Restlet. I simply do not have the time or expertise to develop it in Erlang. I imagine that much of the high-level architecture of Restlet could be reproduced in Erlang with ease by an experienced Erlang developer.

So I am now mourning the loss of useful insight from Erlang and the likely impossibility of ever using it productively beyond desktop automation. Alas poor Erlang, I knew ye well!

Monday, December 22, 2008

Java REST API for Dojo using Restlet

The Dijits of The Dojo Toolkit make it possible to handle the entire user experience with static HTML+JS+CSS. The hard part — at least for me — is how to dynamically generate and cache the JSON representations used to populate the Dijits with actual data.

Finding REST in all the wrong places

I looked into many solutions, the most naïve of which was my own J2EE Servlet that generated JSON through reflection. The problems with this are manifold, but among the biggest are lack of security and poor support for caching. Other REST solutions in other languages like Ruby and Python caught my interest, but quickly faded away. While Rails and Django stood out as very good for REST, they would have added unnecessary learning and complexity with the legacy Java system to which I wanted to add a RESTful face. A Java REST API is what I needed, but I could not find an appropriate framework or library for my needs.

Restlet: finally a REST Framework for me

I recently found Restlet, which has actually been around for a few years now and has matured substantially. Restlet is clearly the most comprehensive Object Oriented Framework for supporting RESTful interactions. Every aspect of REST that I can think of that I would want is there. Better than that though is how it is presented. Despite supporting so much of REST, Restlet is not hard to do small things with either. Even better again is how easy it is to progressively improve your Resources with things like Tags for caching. You do not need to design out the whole system with Restlet. You build as you go.

How does this help with Dojo Applications?

A Dojo Application as I envision it would have a set of static templates for representing various interactions and information for the user. The actual content of these templates would be filled in with AJAX from JSON data sourced from a REST API. In this model Restlet would be very useful because it has full support for JSON Representations of Resources already and is easy to build on.

How would this be deployed?

An HTTP server tuned for static content delivery would be used to serve the Dojo-powered HTML+JS user interface documents. This server would delegate data API requests to the Restlet Application using AJP. In this way it is easy to separate authentication and transport concerns from the REST data API concerns. A server such as Apache httpd could handle ActiveDirectory authentication, support for HTTPS and SSL client authentication. Application-specific authorizations such as which user is allowed to do what with what and the generation of representations would be handled by the Restlet Application. Many Restlet Application instances could be distributed in a cluster to be nearer to specific data to leverage CPU caching for reduced latency. When you go down this RESTful road it seems to open the way to supporting basic web functionality like bookmarking and caching which many web app frameworks like JSF seem to ignore completely.

Sunday, November 23, 2008

Getting erlang_hgsvn to dance with Subversion 1.5

Protocol-driven programming in Erlang can be extremely rewarding. It can also lead you down paths where the subtlest change in the external system you are interfacing with breaks your code. I had just such an experience when I upgraded my workstation from Ubuntu Hardy Heron to Intrepid Ibex.

To my horror my carefully constructed merging system (based on erlang_hgsvn) crashed when I tried to run it. First I investigated what might have changed. I quickly identified that Subversion 1.5 was the standard in the Intrepid repository. I looked at the output from svn log and found it to be an exact match to Subversion 1.4. Something more subtle must be at work I told myself.

Something more subtle was at work. It turns out that Subversion 1.5 does not flush STDOUT strategically at the end of a log entry like Subversion 1.4. Instead it appears to be flushed seemingly at random. Initially I cursed myself for having made the assumption that this would continue to work. I went over and over in my mind why I would have done that instead of using a simple getline approach. Then I remembered the performance issues and I set my mind to retaining a protocol-driven design. This time it would be not be sensitive to the exact boundaries of data yielded by svn log.

To tolerate arbitrary termination of data yielded by svn log I chose to make all parsing routines able to fallback on a receive block to get more data. The design I chose uses a rolling 8 byte binary parsing window to match the telltale aspects of a log entry. It turns out to be more code than the original list-based implementation. However, I found it much easier to walk my friend through the binary-based implementation.

The core of the design — the binary rolling window — was inspired by a fast get_line solution by Per Gustafsson. Originally I looked at Per's solution in horror since it seemed to have needless repetition of pattern-matching clauses. I later learned that this repetition was, in fact, the implementation of a highly-efficient binary parsing window. I modified and reused this technique in erlang_hgsvn to support Subversion 1.5. I hope it has also improved its performance for large repository conversion, but I have not yet done any performance metrics.

You do not need to tie yourself down to obvious get_line solutions to make things work. Quite often that approach will get you into bigger trouble. This trouble can be seen fairly obviously when loading a large file without line terminators into most text editors including — to my surprise and diasappointment — Vim. Using a protocol-driven approach to data processing makes it much easier to avoid memory crashes in these circumstances and also gives you the insight you need to store and parse data stored in binary file formats. Erlang opens such arcane niches of data processing to the average developer.

Wednesday, October 29, 2008

Hello ErlIDE: Installation to Hello World

IDEs Don't Kill Code Bases, People Kill Code Bases

I have just gotten over my mental block for trying ErlIDE. The biggest conflict for me was that my exploration of Erlang was in part a rebellion against Java and IDE-centric programming. ErlIDE is an excellent solution for Erlang development. I now use it in lieu of TextMate and Vim for my desktop automation projects such as erlang_hgsvn which I use daily to merge SVN branches. Vlad Dumitrescu has created an excellent product and I will do my best to contribute in whatever way I can to its success.

Many people have had difficulty installing and using ErlIDE. This step by step guide will show how to install ErlIDE and make effective use of it so that it helps rather than frustrates you.

(Linux only) Allow Large Number of Open Files

When using Erlang it is generally advised to significantly raise the limit on the number of open files per process. Add the following lines to /etc/security/limits.conf (right above # End of file):

* soft nofile 1048576
* hard nofile 1048576

Install Erlang/OTP (if you have not already)

  • Ubuntu Linux: run the following in Terminal:
    sudo apt-get update
    sudo apt-get install erlang
  • Windows: run the Windows Installer for Erlang R12B-4
  • Mac OS X: install MacPorts and then run the following in Terminal:
    sudo port selfupdate
    sudo port install erlang

Install Eclipse and ErlIDE

  1. Download Eclipse IDE for Java Developers
  2. Extract it where you want to run it from (there is no installer, just an archive)
  3. Launch Eclipse by double-clicking eclipse (Linux), eclipse.exe (Windows), or Eclipse (Mac) in the eclipse folder
  4. Select Help (menu) → Software Updates... (a dialog will appear)
  5. Click Add Site...(another dialog will appear)
  6. Enter http://erlide.sourceforge.net/update into the Location field, then click OK (dialog will close)
  7. Select the checkbox by http://erlide.sourceforge.net/update and click Install... (another dialog will appear)
  8. Select Next
  9. Select I accept ... radio button and click Finish (a progress dialog will appear)
  10. (wait for confirmation dialog) Select Yes (Eclipse will restart)

Add Primary Erlang Runtime

Without these steps things like syntax highlighting, code completion and other significant aspects of the ErlIDE UI will not work properly. The IDE will function basically, but it will not work as intended.

  1. Select Window (menu) → Preferences... (Windows/Linux) or Eclipse (menu) → Preferences... (Mac) (a dialog will appear)
  2. Expand Erlang and select Installed runtimes
  3. Click Add... (a dialog will appear) and Enter Erlang in the Runtime name field
  4. Click Browse... and select the root of your Erlang/OTP install (mine is /opt/local/lib/erlang), then click OK (dialog will close)
  5. Click OK (preferences dialog will close)

Create Hello World Project

  1. (wait for Eclipse to restart) Select Window (menu) → Close All Perspectives
  2. Select Window (menu) → Open Perspective → Other... (a dialog will appear)
  3. Select Erlang and click OK (dialog will close and Erlang Perspective will load)
  4. In the Erlang Navigator bring up the context menu (right-click/control-click) and select New Erlang Project (a dialog will appear)
  5. Enter hello_world in the Project Name field and click Finish (dialog will close and hello_world project will appear in Erlang Navigator view)

Start Erlang Node To Run Code

  1. Select hello_world project, bring up the context menu and select Run As → Run Configurations... (a dialog will appear)
  2. Enter hello_world in the Name field
  3. Double-click Erlang application (a new confguration will appear in the right-hand panel)
  4. In the Main tab under Projects click the checkbox beside hello_world
  5. In the Runtimes tab click the checkbox beside Start the Erlang node if not running already and enter hello_world in the Node name field
  6. Click Run (dialog will close and Console will appear with hello_world Erlang node)
  7. Leave the Console running for the next part

Write Hello World Live!

  1. On the hello_world project bring up the context menu (right-click/control-click) and select New Module (dialog will appear)
  2. Enter hello_world in Module name field
  3. To the left of the Apply button, enter say_hello in the first box and 0 in the second box and click Apply
  4. Click Finish (dialog will close and an editor for hello_world.erl will be opened)
  5. In the Console type hello_world:say_hello().
  6. Oops! It displays ok and shows no greeting! Let's fix that
  7. In the hello_world.erl editor replace ok in say_hello with io:format("Hello World!") and save (Ctrl-S/Command-S)
  8. In the Console type hello_world:say_hello().
  9. Great! It displays "Hello World!" for us! Let's get it to say something else
  10. In the hello_world.erl editor replace "Hello World!" in say_hello with "Hello ErlIDE!") and save (Ctrl-S/Command-S)
  11. In the Console type hello_world:say_hello().
  12. Nifty! It displays "Hello ErlIDE!" for us! We can change the code at runtime.

Embrace Convention

When I first tried ErlIDE over a year ago I found the predetermined project structure irritating. I now realize that this project structure is an accepted convention in the Erlang community. It reflects the way that most Erlang/OTP applications are distributed.

Go With The Flow

Buy into ErlIDE's default project structure even though it can now be overridden. It will make it easier for you to work with ErlIDE and easier for other Erlang developers to use what you have created. We have had trouble using Eclipse integration for J2EE at work because of the non-standard layout of our projects. Make the right choice upfront and adopt the conventional Erlang project structure. I wish Joe had mentioned this in his book...

Understated Power Overstated Roughness

ErlIDE is much less rough around the edges than I would expect for a 0.3 release. It is also understating its capabilities and the quality of the Eclipse integration. There is definitely work to be done, but it is an excellent foundation.

ErlIDE is the best tool I have used for Erlang development. It is the clear winner in ease of use for comparable functionality. For anyone already familiar with Eclipse ErlIDE is familiar and comfortable to use. I think ErlIDE will be instrumental in getting more Java developers to use Erlang. I will be actively contributing whatever fixes and features I can to ErlIDE.