Using Javascript JSLint validator in Eclipse and Aptana Studio

JSLint is Javascript validator. It saves your ass from common Javascript pitfalls. This post tells you how to use JSLint with Eclipse, or more precisisely Aptana Studio. For example, JSLint will caught extra commas in your JS files which would choke on Internet Explorer, but run on other browsers.

Aptana Studio Javascript has ability to scan your Javascript while typing and highlight the errors.

By default Aptana Studio uses a validator called Mozilla validator which is very lax. Your Javascript code will run on Firefox, but that alone doesn’t make many web developers happy 🙁

First you need to enable JSList validator in Settings -> Aptana Studio -> Validation -> Javascript.

Now you can see how bad your Javascript code is (bottom window):

Errors and warnings are highlighted in the Javascript editor left marginal when you type. There is also Problems view which shows all the errors and warnings in your workspace. The Problems view can be found Show -> View -> Problems.

1. Hinting globals for JSLint

You can also use JSLint global hints per source file to hint what globals the file has available, so JSLint won’t complain.

For example, to hint that global krusovice namespace is available, add the following line to the beginning of the file:

/*global krusovice*/

Note that not having wrapping spaces is important here.

2. Common warnings to ignore

JSLint is very accurate with every detail – like a Finnish-Swedish lady when it comes to cleaning your apartment. You probably don’t want to see red marker all over you code, so you might want to tune down warnings a bit.

Add these to Settings -> Aptana Studio -> Validation -> Javascript -> Ignore.

Don’t complain about missing jQuery or Console:

.*'(\$|jQuery)' is not defined.*

And

.*'console' is not defined.*

3. Using sane tab setting and fixing mixed spaces and tabs

Turn on: Settings -> Aptana Studio -> Javascript -> Tab policy -> Use spaces to make your source code to be friendly with all the other text editors in the world who use tab size 8. (Who Eclipse has managed to f*k up this?)

You probably want also to fix those “Mixed tabs and spaces” errors. Use AnyEdit plug-in for Eclipse to convert tabs to spaces in the selected file (see Installation section).

First you need to set sane tab site for AnyEdit, which defaults to 2 spaces (looks like you can nbe even more f*ed up as stated above). You need to fix this in Settings -> General -> Editor -> AnyEdit tools -> Convert. Set Eclipse default, 4, there.

Then select all text in the editor, right click -> Convert tabs to spaces.

What is missing

I could not find a way to ignore files. This is very irritating if you have something like jQuery UI in your source tree and you cannot supress warnings for the problematic files. Ignore regular expressions patterns don’t seem to match path or file part of the error.

 

\"\" Subscribe to RSS feed Follow me on Twitter Follow me on Facebook Follow me Google+

Unprotecting Microsoft Word .docx document

Let’s say that you get a form, for example from the government, in Microsoft Word format. You need to fill in the fields which are supposed to be nicely laid out for you. However there are problems filling in those fields because of document formatting, Microsoft Word version incompatibility, etc. argh reasons. This wouldn’t happen in the beatiful word of Office productivity suite, would it?

You could easily fill in the form if you could simply just edit the document and put the text there. But this is prevented using Microsoft Word form password protection mechanism. You need to know the password to enable the editing of the document.

The documention “protection” is not actually very big protection at all. You simply have a flag in the .docx file telling “oh please dear user do not change my beautiful document and just try to have your text in the predefined fields”. The authors of the document are probably right and an average Joe will destroy the document formatting in Word. On the other hand if you know what you are doing you just can get your paperwork done. The password, saved inside the document, is not very much protection, as you can manually gut the document and flip the flag inside.

.docx is actually zip archive containing XML files and you can manipulate its contents with a text editor and ZIP program. Unzip:

mkdir temp
cd temp
unzip ../"KEHITTÄMISTUEN MAKSATUSHAKEMUS.docx"

Edit the unzipped file word/settings.xml using your favorite plain-text editor.

Remove attributes in the following element:

<w:documentProtection w:edit="forms" w:enforcement="1" 
  w:cryptProviderType="rsaFull" 
  w:cryptAlgorithmClass="hash" 
  w:cryptAlgorithmType="typeAny" 
  w:cryptAlgorithmSid="4" 
  w:cryptSpinCount="50000" 
  w:hash="iMNelgcwaqcjZrxjRjtl0SRWLpY=" 
  w:salt="ik/s9VEtUXAkIehywGuyqQ=="/>

Now it looks like:

<w:documentProtection />

Re-zip:

zip -ur ../KEHITTÄMISTUEN\ MAKSATUSHAKEMUS.docx *

Re-open in Microsoft Word.

Poof. The form protection is gone. Sip coffee and continue with your inspirating paper work.

\"\" Subscribe to RSS feed Follow me on Twitter Follow me on Facebook Follow me Google+

Top level domains .py and .js

Now when ICANN has freed the top level domain names for the allocation I hope we could register .py and .js domains for the open source framework uses. They already have io.

We just need a sponsor organization and some 200 000 USD for the evaluation fee.

Anyone?

I know you want __init__.py (though underscore is not an allowed character in home name).

(thanks for Petri for the orignal idea)

\"\" Subscribe to RSS feed Follow me on Twitter Follow me on Facebook Follow me Google+

Inserting leads to Zoho CRM using PHP

Here is a simple PHP class (one  file) which you can use to insert leads to Zoho CRM. It is designed to be hooked up with your site contact form. Instead of emailing the contact form results, they go directly to the CRM and are available for the sales person to call. The code based on the orignal Python based mfabrik.zoho package. PHP curl needed as a requirement.

<?php
/**
 * Simple Zoho CRM inserter.
 *
 * MIT licensed. Copyright 2011 Pete Sevander and Mikko Ohtamaa.
 *
 */

class ZohoException extends Exception { }

class Zoho {

    public function __construct($username, $password, $apikey, $extra_auth_params = array(), $auth_url="https://accounts.zoho.com/login") {
        $this->username = $username;
        $this->password = $password;
        $this->apikey = $apikey;

        $this->ticket = null;
    }

    public function open() {
        $this->ticket = $this->_createTicket();
    }

    public function _createTicket() {

        $params = array(
            "servicename" => "ZohoCRM",
            "FROM_AGENT" => "true",
            "LOGIN_ID" => $this->username,
            "PASSWORD" => $this->password
        );

        //$params = array_map('urlencode', $params);

        $url = "https://accounts.zoho.com/login";

        $body = openUrl($url, $params);

        $data = $this->_parse_ticket_response($body);
        $this->data = $data;

        if (isset($data["WARNING"]) || isset($data['CAUSE'])) {
            $warning = (isset($data["WARNING"])) ? $data["WARNING"] : $data["CAUSE"];
            if ($warning != "null") {
                throw new ZohoException("Could not auth: " . $warning);
            }
        }
        if ($data["RESULT"] != "TRUE") {
            throw new ZohoException("Ticket result was not valid");
        }

        return $data["TICKET"];
    }

    public function _parse_ticket_response($data) {

        $output = array();

        $lines = explode("\n", $data);

        foreach($lines as $line) {
            if (substr($line, 0,1) == "#") {
                continue;
            }
            if ($line == "") {
                continue;
            }
            if (!strstr($line, "=")) {
                continue;
            }
            $line = explode("=", $line);
            $output[$line[0]] = $line[1];
        }

        return $output;
    }

    public function ensure_opened() {
        if ($this->ticket == null) {
            throw new ZohoException("Login first");
        }
    }

    /**
    * https://crm.zoho.com/crm/private/xml/Leads/insertRecords?newFormat=1&apikey=APIkey&ticket=Ticket
    **/
    public function insertRecords($leads, $extra_post_parameters=array()) {
        $this->ensure_opened();

        $xmldata = $this->XMLfy($leads);

        $post = array(
            'newFormat' => 1,
            'ticket' => $this->ticket,
            'apikey' => $this->apikey,
            'version' => 2,
            'xmlData' => $xmldata,
            'duplicateCheck' => 2,
            'wfTrigger' => 'true'
        );

        array_merge($post, $extra_post_parameters);

        // We'll bump created time to make sure that duplicate data entry
        // gets bumped up on the salesdroids list

        // $created = strftime('%Y-%m-%d %H:%M');
        // $post['Created Time'] = $created;

        // XXX: Good idea but Zoho silently ignores changes to the creation time

        $q = http_build_query($post);

        //print_r($post);

        $response = openUrl("https://crm.zoho.com/crm/private/xml/Leads/insertRecords", $q);

        //print_r($response);
        //print_r($xmldata);
        $this->check_successful_xml($response);

        return true;

    }

    public function getRecords($columns ='leads(Name)') {
        $this->ensure_opened();

        $post = array(
            'newFormat' => 1,
            'ticket' => $this->ticket,
            'apikey' => $this->apikey,
            'version' => 2,
            'selectColumns' => $columns,
        );

        $q = http_build_query($post);
        $response = openUrl("https://crm.zoho.com/crm/private/json/Leads/getRecords", $q );

        echo $response;

    }

    public function check_successful_xml($response) {
        $html = new DOMDocument();
        $html->loadXML($response);

        if ($err = $html->getElementsByTagName('error')->item(0)) {
            throw new ZohoException($err->getElementsByTagName('message')->item(0)->nodeValue);
        }

        return true;
    }

    public function XMLfy ($arr) {
        $xml = "<Leads>";
        $no = 1;
        foreach ($arr as $a) {
            $xml .= "<row no=\"$no\">";
            foreach ($a as $key => $val) {
                $xml .= "<FL val=\"$key\">$val</FL>";
            }
            $xml .= "</row>";
            $no += 1;
        }
        $xml .= "</Leads>";
        return $xml;
    }
}

function openUrl($url, $data=null) {
    $ch = curl_init();
    $timeout = 5;

    if($data) {
        curl_setopt($ch,CURLOPT_POST,1);
        curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch,CURLOPT_VERBOSE, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

       // log output
       //$f = fopen("/tmp/zoho-curl.txt", "wt");
       //curl_setopt($ch,CURLOPT_STDERR, $f);

   }

    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
    curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}

?>

And this is how you use it:

<?php

    $ZOHO_USER="yyyyy@xxxxxx.com";
    $ZOHO_PASSWORD="v3ryS3cr3t";
    $ZOHO_API_KEY='GET THIS FROM ZOHO CRM SETTINGS';

    require_once 'Zoho.php';

    $z = new Zoho($ZOHO_USER, $ZOHO_PASSWORD, $ZOHO_API_KEY);

    try {
        $z->open();

        $leads = array(
            'First Name' => 'Mikko',
            'Last Name' => 'Ohtamaa',
            'Company' => 'opensourcehacker.com',
            'Phone' => '+358 12 123 1234',
            'Email' => 'mikko @ foobar dot com',
            'Lead Owner' => 'yyyyy@xxxxxx.com',
        );

        try {
            $z->insertRecords(array($leads));
            $renderForm = false;
            echo '<h3>Contact information sent successfully. We will contact you soon.</h3><br /><strong>Data sent:</strong><dl>';
            foreach ($values as $key => $value) {
                echo '<dt><strong>' . $form->getElement($key)->getLabel() . '</strong></dt>';
                echo '<dd>' . $value . '</dd>';
            }
            echo '</dl>';

        } catch (ZohoException $e) {
            echo '<span>Error inserting data: ' . $e->getMessage() . '</span>';
        } 

    } catch (ZohoException $e) {
        echo '<span>Can\'t connect to Zoho: ' . $e->getMessage() . '</span>';
    }

?>

Some things to note

  • Owner must be given and be valid Zoho user
  • Company and Last Name fields are the only required fields by default
  • Zoho CRM checks duplicates using email field and thus using the same email address for (test) inserts won’t yield to visible results in My Leads view when duplicateCheck=2
  • Creation Time field cannot be changed
  • You can customize fields in Zoho CRM settings

 

\"\" Subscribe to RSS feed Follow me on Twitter Follow me on Facebook Follow me Google+