Google introduced new format for JSON results

Google announced new JSON-C format for Youtube API, in that announcement they mentioned that direct transformation of ATOM to JSON is not very effective and actually make no much sense.
It’s actually not just announcement – they already created docs which explain new format in details.

Our existing JSON format isn’t perfect, however. It’s very much a literal translation from Atom. As is often the case with literal translations, the current JSON format is wordier than it needs to be, and it lacks some of the elegance that a native dialect would offer.

We’ve rethought out current JSON implementation, and moved away from a literal representation of the Atom data to a format that we hope will be more pleasing to those who are fluent in JSON. The vestigial XML namespace prefixes are no more, and we’ve removed many pieces of metadata specific to Atom documents that come across as noise in JSON. Repeating data elements are always structured as true JSON lists, and useful video metadata that exist as XML attributes in Atom have been rearranged to make more sense in the JSON document. You’ll also find that the new JSON results are more compact than Atom XML, which is of special importance to code running from limited-bandwith mobile applications.

Sounds very promising and I have a hope that new format (which is more compact and lightweight) will open the door for mobile devices to use GData API. Especially for Android, which have no official support of GData API. I believe it happens because current protocol (based on quite complex and big ATOM) is not very well suited for mobile devices – it’s too big (network) and complex (performance/memory). Hover there are couple of implementations of existent GData API:

  1. Android-GData – it looks like it is working solution and used by couple of projects, but it’s main drawback that it is too big and have a lot of dependencies
  2. Another solution is to use code which is not included now in the android-platform but still exists in the GIT.

I just tried to use alt=jsonc with calendar and picassa-web-albums and it looks like at least Picassa API also support new Json-C format ! and the generated response is about 2 times smaller than standard JSON.

http://picasaweb.google.com/data/feed/api/user/userId?alt=jsonc

http://picasaweb.google.com/data/feed/api/user/userId?alt=json

If you want to see more details from google about JSONC and other GData protocol updates and tricks you can see that youtube-video.  I was wondered to see really nice Partial-GET feature of GData which allow you to enumerate the fields/objects you want to see in the response.

TinyMCE JMySpell and Jazzy spellchecker implementation

In my previous post I was asked about the “May be JMySpell is a better backend.”  On that moment I don’t know the answer – JMySpell library was new to me.

So, I download and implement spellchecker with JMySpell to get the answer.  Now JSpellChecker support 3 spellchecker engines (google, Jazzy and JMySpell) and I can briefly compare them all.

Google engine is easy to start with (you don’t need to  have any dictionaries) but it doesn’t give you the guarantee that it will be stable and you will not overcome the limit of requests. Jazzy engine looks like most advanced engine but it’s not easy to prepare dictionaries (Mozilla dictionaries could be used with some manipulations). The advantage of JMySpell is that it can use OpenOffice dictionaries. (You can download any dictionary from OpenOffice wiki). On my view Jazzy have more settings for spellchecker object than JMySpell, but actually I don’t do really deep comparison in quality of spell-checking.

Here is excerpt from the official JMySpell site:

This allows us to use the dictionaries from OpenOffice.org in Java applications, whether they’re J2SE applications or J2EE web applications. Since at the moment there is only one 100% Java Open-Source spell checker (Jazzy), and the inclusion of dictionaries, particularly the Spanish dictionary, is difficult, the objective of this project is to fill this gap.

Here is the list of changes for the https://sourceforge.net/projects/jspellchecker/ project

  1. Code refactored to support different implementations of spell-checkers. new class TinyMCESpellCheckerServlet define request reading, delegate spell-checking to abstract methods and write response in JSON
  2. JMySpell spellchecker implementation has been added (JMySpellCheckerServlet)
  3. Servlet paths changed to (please update tiny_mce config scripts)
    • jazzy servlet path become “/jazzy-spellchecker”
    • google servlet path become “/google-spellchecker”
    • new JMySpell servlet path has been added “/jmyspell-spellchecker”
  4. Location of dictionaries in the “spellchecker” application reorganized
    jazzy dictionaries should be located under “/WEB-INF/dictionaries/jazzy” before it was “/WEB-INF/dictionaries”
    JMySpell dictionaries should be located under “/WEB-INF/dictionaries/jmyspell” in form of zip files named to correspond to the language attribute in TinyMCE config script

Here is the example configuration


tinyMCE.init({
 theme : "advanced",
 mode : "textareas",
 plugins : "spellchecker",
 theme_advanced_buttons3_add : "spellchecker",
 spellchecker_languages : "+English=en-us,Swedish=sv"
 spellchecker_rpc_url    : "/spellchecker/jmyspell-spellchecker", //spellcheck url for jazzy use /spellchecker/jazzy-spellchecker

the following files should be present in the “/WEB-INF/dictionaries/jmyspell” directory

  • en-us.zip
  • sv.zip

On the moment I tested JMySpell en-us dictionary from TinyMCE and it works fine. And I’m looking forward to perform more QA for JMySpell spellchecker engine and probably it’s possible to do with help of community, since I’m not linguist. The authors of JMySpell states that their library implements MySpell algorithm (which was used by OpenOffice as spellchecker engine before version 2.02). On the moment OpenOffice use Hunspell spellchecker library. Few words about Hunspell

  • Improved suggestion using n-gram similarity, rule and dictionary based pronounciation data.
  • Morphological analysis, stemming and generation.
  • Hunspell is based on MySpell and works also with MySpell dictionaries.

How to use autofocus in Android

I’m having Android G1 device and while I’m doing the photos with integrated camera software I see that device is trying to focus before taking the photos (I hear the beep and see green border after camera is focused)
But here is the issue – how to focus the camera using the Android API from you android application ?
In the book “Professional Application Android Development” I’ve found only short example about using camera and it doesn’t use any autofocus features of the device/API. (see chapter 10 “Accessing Android Hardware”/”Using Camera”). It is actually an entry point but not the solution to take good pictures (I must admit it’s quite optimistic to say that G1 could make photos with good quality – probably only in a sunny day. But again – it will never be even close to the photos from Nokia N82)
CameraPreiew class (com.example.android.apis.graphics package) from the API-Examples shows only the way to start activity with preview from camera.

The key here is to call camera.autoFocus(autoFocusCallBack) and after we focused method autofocusCallback.onAutoFocus(boolean success, Camera camera) is called – call the camera.takePicture (Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg)

here is the example code (take a notice that everything here is happen inside onKeyDown event handler)

public final boolean onKeyDown(int keyCode, KeyEvent event) {
synchronized(this) {
    if (!bIsPictureTaking) {
        //we care only about two buttons here
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_CAMERA) {
            //that method support tow modes with and without autofocus
            if (USE_AUTOFOCUS){
                //autofocus mode
                if (!bIsPictureTaking && !bIsAutoFocusStarted){
                    //start autofocus if it was-not started
                    AutoFocusCallBackImpl autoFocusCallBack = new AutoFocusCallBackImpl();
                    cDevice.autoFocus(autoFocusCallBack);
                    //set the bIsAutoFocusStarted trigger to false to avoid extra autofocus attempts
                    bIsAutoFocusStarted = true;
                    return true;
                }

                long autoFocusTime = event.getEventTime() - event.getDownTime();
                //autoFocusTime is the time we spent in the autofocusing
                boolean isAutofocusTimeout = (bIsAutoFocusStarted && autoFocusTime > AUTOFOCUS_TIME_LIMIT_MILISECONDS);
                if (bIsAutoFocused){
                    Log.i(TAG, "Autofocused, taking picture. Autofocus time="+autoFocusTime+" ms");
                } else if (isAutofocusTimeout){
                    Log.i(TAG, "Autofocus timeout reached, taking picture. time for focus is:"+autoFocusTime+" ms");
                }

                if (bIsAutoFocused || isAutofocusTimeout){
                    //if camera got focused or we have autofocus-timeout - take the picture (we will never be focused in the darkness)
                    takePicture();
                }
            } else {
                //non-autofocus mode, nothing special just take the picture
                takePicture();
            }
        }

        //support for the BACK button to exit from activity
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            setResult(LifecycleConstants.CAMERA_CANCELLED);
            return super.onKeyDown(keyCode, event);
        }
    }
}
return true;
}

private class AutoFocusCallBackImpl implements Camera.AutoFocusCallback {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        bIsAutoFocused = success; //update the flag used in onKeyDown()
        Log.i(TAG, "Inside autofocus callback. autofocused="+success);
        //play the autofocus sound
        MediaPlayer.create(CameraActivity.this, R.raw.auto_focus).start();
    }
}

private void takePicture(){
    bIsPictureTaking = true;  //set it to true to avoid onKeyDown dispatching during taking picture. it may be time-consuming
    bIsAutoFocused = false; //reset to false
    bIsAutoFocusStarted = false; //reset to false

    //create the file to write output content (picture) to
    String fileName = myDateFormat.format(new Date()).concat(".jpg");
    ContentValues values = new ContentValues();
    values.put(Media.TITLE, fileName);
    values.put(Media.DESCRIPTION, "Image capture by camera");
    Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
    OutputStream os = null;
    try {
         os = (FileOutputStream) getContentResolver().openOutputStream(uri);
    } catch (Exception ex) {
        Logger.getLogger("CameraActivity").log(Level.WARNING,"Failed to take Picture", ex);
        setResult(LifecycleConstants.CAMERA_FAILED_TO_TAKE_PHOTO);
        finish();
        return;
    }

    //create ImageCaptureCallback and pass output stream to it
    ImageCaptureCallback iccb = new ImageCaptureCallback(os, uri.toString());

    //you also could add shuter callback to play sound for example
    cDevice.takePicture(null, null, iccb);
    findViewById(R.id.surface).setVisibility(View.INVISIBLE);
    findViewById(R.id.SavingPhotoPanel).setVisibility(View.VISIBLE);
}

private class ImageCaptureCallback implements PictureCallback {

private OutputStream foStream;
private final String sFileName;

public ImageCaptureCallback(OutputStream filoutputStream, String fileName) {
    this.foStream = filoutputStream;
    this.sFileName = fileName;
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {
    boolean exception = false;
    //write image and close output-stream
    try {
        foStream.write(data);
        foStream.flush();
    } catch (Exception ex) {
        exception = true;
        android.util.Log.v(getClass().getSimpleName(), "Error while taking photo", ex);
        ex.printStackTrace();
    } finally {
        if (foStream != null){
            try {
                foStream.close();
            } catch (Exception ex){
                android.util.Log.v(getClass().getSimpleName(), "Error while taking photo", ex);
                ex.printStackTrace();
            }
        }
    }

    //pass the information back to the caller-activity via Intent with Bundle (intent.putExtras(bundle))
    Bundle bundle = new Bundle();
    if (sFileName != null) {
        //set the file-name property, so caller activity will be able to resolve the file to which picture was written to
        bundle.putString(LifecycleConstants.PHOTO_URI, sFileName);
    }
    Intent intent = new Intent();
    intent.putExtras(bundle);
    setResult(exception ? LifecycleConstants.CAMERA_FAILED_TO_TAKE_PHOTO : LifecycleConstants.CAMERA_PHOTO_TAKEN, intent);
    finish();
}
}

It’s the description of my short experience with Android autofocus, if you are interested in that topic you could explore ZXing library (which is actually scan Bar-Codes and QR-Codes but it also use autofocus inside //continuous autofocus)
and the very interesting ideas could be found in the “Snap Photo Pro” for Android, that software uses the accelerometer to stabilize the image. it also has the white-balance and other features. But it’s not an open-source, it’s a paid software. It would be very interesting to know how image-stabilization is implemented and I think it would be very useful component if they will make their software available as a component (like ZXing) which you can use/integrate with your application via Intent/Activity

    Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
    activity.startActivityForResult(intentScan, requestCode);

Free online meeting tool

I just find the really good and free solution for online meetings – it’s ‘Mikogo‘.
It’s probably not the best from the best – I must agree that WebEx functionality is wider and it has a lot of other tools, but Mikogo has such killer pros

  • It’s free (and it’s the most important argument)
  • It run well on 64 bit systems. Microsoft SharedView doesn’t support 64-bit Windows-XP
  • It have “record” feature, so you can record your meetings
  • a lot of other features (but not too much to be hard to use)

Before using Mikogo I’ve used several online meeting applications – one of them are paid services like WebEx and GoToMeeting. Nothing bad about them (they are cool services), but they are quite expensive tools. As for MS SharedView – it don’t want to run on my WindowsXP 64bit, so I have to install and use it on my 32-bit Windows inside VMWare plus SharedView don’t hide it’s menu and that eats vertical screen-space, so the picture was not pretty-good if presenter has big screen resolution.
Yeah, I also use Skype Unite-extra to share my screen, but the quality of the picture was quite blurry, so I don’t think it’s an option for online meetings.

Conifgure JBoss mail-service for SMTP over SSL

I always have troubles with sending email-messages from my application which I host locally.
The issue is that my ISP provider SMTP works only via SSL. I was able to setup Outlook to work with it and since ISP use not trusted certificate I was asked to confirm that that certificate is trusted.
So, actually (going ahead) we have two problems

  1. Configure /deploy/mail-service.xml to use correct port and other SSL parameters
  2. Add ISP certificate into the java keystore (since the certificate is not trusted)

So, after couple of experiments and googling I find that following combination of parameters work for me

<server>
    <mbean code="org.jboss.mail.MailService" name="jboss:service=Mail">
        <attribute name="JNDIName">java:/Mail</attribute>
        <attribute name="User">${username}</attribute>
        <attribute name="Password">${password}</attribute>

        <attribute name="Configuration">
            <configuration>
                <!-- Change to your mail server prototocol -->
                <property name="mail.store.protocol" value="pop3"></property>
                <property name="mail.transport.protocol" value="smtp"></property>

                <!-- Change to the user who will receive mail  -->
                <property name="mail.user" value="${username}"></property>

                <!-- Change to the mail server  -->
                <property name="mail.pop3.host" value="${pop3-server}"></property>

                <!-- SSL parameters STARTED-->
                <property name="mail.smtp.host" value="${smtp-server}"></property>
                <property name="mail.smtp.auth" value="true"></property>
                <!-- The mail server port -->
                <property name="mail.smtp.port" value="465"></property>
                <property name="mail.smtp.ssl.enable" value="true"></property>
                <property name="mail.smtp.socketFactory.class" value="javax.net.ssl.SSLSocketFactory"></property>
                <!-- SSL parameters ENDED -->

                <property name="mail.smtp.connectiontimeout" value="20000"></property>
                <property name="mail.smtp.timeout" value="20000"></property>

                <!-- Change to the address mail will be from  -->
                <property name="mail.from" value="${yourname@yourisp}"></property>

                <!-- Enable debugging to see a lot of inetresting about SMTP protocol -->
                <property name="mail.debug" value="true"></property>
            </configuration>
        </attribute>
        <depends>jboss:service=Naming</depends>
    </mbean>
</server>

So, that configuration seems at least trying to connect to my SMTP server, but emails are still not sent out. The reason is the SSL-certificate which my ISP used is signed by cacert.org, which issue free certificates.
To fix this issue I have to install that certificate into my java keystore and the easiest way to do it was to use InstallCert program (the link to source-code)
I run java my-smtp-server:465 input “1″ and program generate jssecacerts. After that I updated cacerts file in my %JRE-HOME%/lib/security with generated file (of course I backed up previous cacerts) and that was enough to start using my SSL email.

To find more details or solve more issues you can read the JavaMail FAQ which cover a lot of topics, for example I think it worth to use gmail or yahoo smtp for your email testing purposes, since they are always present and you are not depend on your ISP SMTP

Creating Excel reports from java is easy

Yeah, things sometime become really easy if you choose right tools and approach.
I’ve to create relatively complex Excel report which is not “die-hard” task itself (you can use Apache-POI or JExcel API)
But creating the formatting with Apache-POI API is really boring and it is too time consuming task. Since project was a JBoss-Seam based I also have an option to create it with Seam-Excel-support (btw, Seam use JExcel inside).  Much better then just a POI-API – you can define your Excel template in JSF template. Good enough, but still too much dancing around formatting is needed.

So, I decided to try to use JXLS which I use before for relatively simple reports.
JXLS allow you to define your dynamic Excel template right in Excel file, so you can just take an report example with required formatting and insert iteration tags (it also have condition tags). JXLS use JEXL as expression language so we can insert quite complex expressions and call java methods on objects.
So, everything works fine, I provide the data to JXLS, write output to OutputStream and was able to update formatting on the fly without any coding.

The only thing make me unhappy – my report require generation of dynamic sheets but this feature just failed in the latest JXLS release (0.9.8). It throws ClassCastException during sheet copy operation java.lang.ClassCastException: org.apache.poi.hssf.util.CellRangeAddress cannot be cast to java.lang.Comparable
It looks like nobody check this feature (never run this code) since CellRangeAddress is NOT Comparable. As I got from inspecting the code in subversion it was refactored to work with new POI API and TreeSet was used as a container for CellRangeAddress (maybe just mechanic error)
So, that sad issue may be easily fixed if all TreeSet instances created in the “net.sf.jxls.util.Util.java” will be changed to HashSet

    public static void copyRow(HSSFSheet sheet, HSSFRow oldRow, HSSFRow newRow) {
        //TreeSet --> HashSet
        Set mergedRegions = new HashSet();
    }
    public static void copyRow(HSSFSheet srcSheet, HSSFSheet destSheet, HSSFRow srcRow, HSSFRow destRow) {
        //TreeSet --> HashSet
        Set mergedRegions = new HashSet();
    }

    public static void copyRow(HSSFSheet srcSheet, HSSFSheet destSheet, HSSFRow srcRow, HSSFRow destRow, String expressionToReplace, String expressionReplacement) {
        //TreeSet --> HashSet
        Set mergedRegions = new HashSet();
    }

You can apply that patches on your own, by downloading jxls with sources and call “mvn clean install” from source code folder.

Another issue I’ve found about JXLS – is perfomance, on my reporting example (which has about 32 sheets) template processing was quite long (about 3-5 seconds) which is not good if your reports are frequently generated. I have a plan to profile and fix that performance issue in my free time.

Happy templating with JXLS, it’s really good tool and this article is my attempt to support that library and the efforts which JXLS developers put on it.
Thank You Guys !

How to Become an Early Riser

Very nice solution which upgrade your lifestyle and get you more productive time each day.
How to Become an Early Riser

The idea in short is to “Go to bed when you’re sleepy and then get up at a fixed time”. It’s hard to start such practice but after some time it become your habit.
As a result your body perform self-regulations (adapted) to that, so if you go to bad too late one day your body will force you to fall asleep sooner next day.

Posted using ShareThis

Gmail failure 502 on September 1, 2009

Today, September 1, 2009, Gmail was down from 20-00/8pm GMT it is actually in progress now , but my IMAP access from Outlook still works, cool.
Gmail shows “502 Server error” in the title and “The server encountered a temporary error and could not complete your request.” in the page. I was able to load it with standart (static HTML/non-ajax) mode, but it looks awful, Outlook with IMAP is much better.

Interesting – is it some attack on Google or what ?
The only issue I experienced with Outlook/IMAP is the absence of gmail contact’s in Outlook and it’s actually slower then Gmail web-application.
But that could be fixed by exporting contacts from GMail in CSV/Outlook format and importing it in Outlook.
Here is instructions for Export/Import GMail contacts

  1. Click on Contacts in your GMail
  2. Click Export (right corner)
  3. Choose “Everyone” and “Outlook CSV format (for importing into Outlook or another application)”
  4. Open “File/Import and Export” in Outlook
  5. Select “Import from another program or file”
  6. Select comma-separated values (Windows)
    not sure which encoding GMail use, but russian names inserted as question marks “????”
  7. Select “Do not import duplicate items” if you don’t want to override your contacts
  8. Select destination folder for contacts. I’ve choosed “Contacts” in “Personal Folders”

But.. anyway, I’m still the fan of Gmail web application and Google Docs.

Here is the link to Gmail IMAP intructions – select your IMAP client and GO! BTW, I suppose my Android G1 also use IMAP access. Sorry, upps, you have to enable IMAP in GMail first. The bad news is that you need Gmail web application for that, so it’s better to enable it to use later.

Anyway, it is just a backup option for me which help to read couple of recent emails and I steel need to make GMail contacts export/import to work with my GMail in Outlook.
I’d prefer Google and Microsoft will include it (or write plugin) to import GMail contacts in the next version of Outlook :-) Sounds like a joke, isn’t it ?

Howto delete large emails from GMail

Problem description
I use GMail almost every day during 4 years (and I love it) and on the moment I have a tons of emails and about 1.5 Gb of email storage size.
I’m sure that a most of that is eaten by couple of big attachments. The issue is that GMail web interface doesn’t have the ability to sort by email-size and that’s why you can’t find the biggest ones emails to delete them first. As well you may need to use some specific filtering to your emails which are not available in GMail web interface.
Solution

  1. Download your GMail emails with IMAP to your favorite email-client
  2. Open “[GMail]/All Mail” folder and wait for messages are downloaded.
  3. Sort by email size or apply whatever filter you need
  4. Delete emails you don’t won’t to keep in GMail

Important Note since downloading of all your emails could take a while and you even can be blocked by GMail – split your downloads into few days. So download during 1-2 hours each day.
Email should be deleted form the “All Mail” folder since deletion it from your “Gmail Labels” will just remove that label form that email but not delete it. GMail have special topic “Deleting IMAP messages”.

If you delete a message from your inbox or one of your custom folders in your IMAP client, it will still appear in [Gmail]/All Mail.

It is interesting for me which application behaves better with handling thousands of emails – Outlook or Thunderbird. My experience is that Outlook 2007 becomes crazy now – it try to synchronize with GMail and I’m experiencing problems with it. CPU loading is high (30-70%), network is loaded (it’s understandable) and click on email to view it and on navigation buttons just stuck the Outlook.
BTW, what I like from Outlook – it has special “Search Folders” folder with “Large Mail” folder in which I can group my emails with “Enormous >5MB” , “Huge 1-5 MB” etc. It’s perfectly suits my needs :-)

TinyMCE spellchecker java implementation

TinyMCE rich-editor have a plugin to provide Ajax-spell-checking functionality. See the link to TinyMCE plugin documentation
So, if you have a PHP and PSPell/ASpell on your server – then you are fine and you can use them, but this post is about the situation then you don’t have them or want to use your own implementation. In that case we can configure “spellcheck” plugin to use our own service.
What we have to do is to create a webservice compatible with the “TinyMCE spellchecker plugin” and configure spellcheck with the URL to that service. Because of browser security reasons this service should be hosted on the same domain as the application which use it (ajax calls can be blocked if requested URL is on another domain then your page). And since we are using java then we can use open-source Jazzy spellchecker library to implement spell-checking functions required by the TinyMCE spellchecker plugin

tinyMCE.init({
	theme : "advanced",
	mode : "textareas",
	plugins : "spellchecker",
	theme_advanced_buttons3_add : "spellchecker",
	spellchecker_languages : "+English=en,Swedish=sv"
        spellchecker_rpc_url    : "/spellchecker/jazzy-spell-check", //spellcheck url
});

In the configuration example above we set the link to our splechecker-service-url with the “spellchecker_rpc_url : “/spellchecker/jazzy-spell-check”;”
“/spellchecker/jazzy-spell-check” will be served by the servlet which use Jazzy project.
TinyMCE spellchecker plugin send JSON request to spellchecker_rpc_url with two possible methods:

  1. checkWords – send the array of words as params attribute and expect the JSONArray of misspelled words in the result JSON-response attribute.
  2. getSuggestions – send the checked word as the first and only element of params attribute and expects the JSONArray of suggested words the result JSON-response attribute.

So, when user click on “check spellcheck” button, plugin get the list of words and send them as the JSON request, with two parameters “method”=”checkWords” and “params”=”JSONArray(words)”. Servlet return the list of misspelled words in the JSON-response "{'id':null,'result': JSONArray(misspelled-words),'error':null}" , misspelled words are highlighted and once user click on one of them – request to get the list of suggested words is send to the server. “method”=”getSuggestions” and “params”=”JSONArray(checked-word)” . Server return the "{'id':null,'result': JSONArray(word-suggestions),'error':null}" JSON-response and list of suggestions is displayed to the user.

Update: You can see the backend java source code at the jspellchecker sourceforge project. SVN is accessible via “svn co https://jspellchecker.svn.sourceforge.net/svnroot/jspellchecker jspellchecker” or you can browse source-code . Please take a notice that source-code doesn’t include dictionaries. The dictionaries are located in the /WEB-INF/dictionary/${lang}-${country-code}.
Special thanks to the Rich Irwin who initially provide me the code.
The quality of spell-checking with jazzy depends on the quality of your dictionary. I think it possible to get thelist of words from Mozilla Dictionaries by saving XPI and opening it as ZIP file, saving dictionary file and remove “/xyz” from the end of the words, but please check the licensing notice before. You can also extract dictionaries form aspell (have no details how to do it)