Sep 30

Duplication is the mother of all evil in programming. Remaining DRY at all costs should be your goal at all times. A pattern repeats itself one time and your code complexity goes up exponentially.
One great way to DRY up your code is via Traits. Traits are functional equivalent of base classes where you can collect most often used functions and inject these Traits into your objects. Here’s one simple way to do it in Javascript (using extjs here):

MyTrait = {
   xhr: function(config) { return Ext.Ajax.request(config) },
   submit: function(basic_form,config) {
                //perform some checks on config 
               // and call basic_form.submit 
   },
   //...add more utility functions
}
function MyGrid(config) {MyGrid.superclass.constructor.call(this,config)}
Ext.extend(MyGrid, Ext.grid.GridPanel, MyTrait);
Tagged with:
Sep 28

Although the extjs grid is an awesome component, IMO, it suffers from one major drawback – it’s inability to place active components within data cells. At least it’s not straightforward. Here’s a simple solution to place clickable links within cells. The trick is to place s which look like links and then intercept rowclick and determine which of many links was clicked on.

Here’s an example of a custom Grid Component:

function MyComponent() {
   MyComponent.superclass.constructor.call(this);
}
Ext.extend(MyComponent, Ext.grid.GridPanel);
MyComponent.prototype.initComponent = function() {
  var action_tmpl = new Ext.XTemplate(
     "<span class='link' id='edit-{id}'>Edit</span>",
     "<span class='link' id='delete-{id}'>Delete</span>"
   );
   action_tmpl.compile();
   var content = {
     // grid related config
     columns: [
        {header: 'First Name', dataIndex:'fname'},
        {header: 'Action', dataIndex:'id', 
          renderer: function(c) { 
              return action_tmpl.applyTemplate({id: id});
          }}
     ]
   }
   MyComponent.superclass.initComponent.call(Ext.apply(this,content));
}
MyComponent.prototype.afterRender = function() {
  MyComponent.superclass.afterRender.call(this);
  this.on('rowclick', this.row_click, this);
}
 
MyComponent.prototype.row_click=function(grid, ri, evt) {
   var rec = grid.getStore().getAt(ri);
   // See Below for within_el method
   if(evt.within_el('edit-'+r.id)) {
       alert('Edit clicked');
   } else if(evt.within_el('delete-'+r.id)) {
        alert('Delete clicked');
   }
}

The within_el method on Ext.EventObject object looks like this:

Ext.apply(Ext.EventObject, {
    within_el:function(el) {
        el = Ext.get(el);
        if(!el)
            return false;
        var evt_xy = this.getXY();
        var evt_x = evt_xy[0];
        var evt_y = evt_xy[1];
        return (evt_x > el.getLeft() && evt_x < el.getRight() && evt_y > el.getTop() && evt_y < el.getBottom());
    }
});
Tagged with:
Sep 21

The example at yaws web site to read the file upload is a good starting point but it's too simplistic. I extended the example so it's useful in the real world. (Update: Thanks to Steve Vinoski, this module(yaws_multipart) is now part of the yaws git tree).

  1. It reads all parameters – files uploaded and other simple parameters .
  2. It takes a few options to help file uploads. Specifically:
    1. {max_file_size, MaxBytes} : If file exceeds MaxBytes bytes, return an error
    2. no_temp_file: read the uploded file in memory without any temp files
    3. {temp_file,FullFilePath}: Specify full path for the temp file. If not given, a unique file name is generated
    4. {temp_dir, TempDir} : Specify a directory to store uploaded temp file. By default '/tmp' is used.

Using it is simple. Just call read_multipart_form from your 'out' function and it'll return a tuple with first element either 'get_more', 'done' or 'error'. The 'get_more' implies more data needs to be read and you must call read_multipart_form again. 'done' implies it's done reading all parameters and you're free to proceed. The 'done' tuple also returns a 'dict' full of params. This dict can be queried for parameters by name. For file upload parameters it returns one of the following lists:

[{filename, "name of the uploaded file as entered on the form"},
  {value, Contents_of_the_file_all_in_memory}]
OR
[{filename, "name of the uploaded file as entered on the form"},
  {temp_file, "full pathname of the temp file"}]

In the second case, it's your responsibility to remove the temp file. Usage example:

-module(my_yaws_controller).
-export([out/1]).
 
out(Arg) ->
     Options = [no_temp_file],
     case yaws_multipart:read_multipart_form(Arg, Options) of
             {done, Params} -> 
                   io:format("Params : ~p",[Params]),
                   [{filename, File_name},{value,File_content}] = dict:find("my_file", Params),
                  Another_param = dict:find("another_param", Params);
                  % do something with File_name, File_content and Another_param
              {error, Reason} ->
                   io:format("Error reading multipart form: ~s", [Reason]);
              Other -> Other
      end
.
Tagged with:
Sep 13

If you run your asterisk behind Firewalls (which you probably do), you might run into issues with your ISP blocking outgoing Emails from your Asterisk Box. Here’s a simple solution which lets you use the Gmail servers instead, eliminating these issues.
Steps to use Gmail for Asterisk here

Few simple notes :

  1. You can use your Google Apps Account too. Just use your full Email as username , eg. john@mycompany.com
  2. Make sure the Asterisk hostname as reported by ‘hostname’ command is in /etc/hosts – on the line with 127.0.0.1 as IP address – otherwise, sendmail would take few minutes to start and send emails.
Tagged with:
Jul 23

Like many small businesses, we use Google Apps for all our Email and Collaboration needs and Firefox being our preferred browser, we’d wanted to teach Firefox to use our Google Apps email to send emails by default. Here are the steps I found from a quick google search :

  1. Open up Firefox
  2. type about:config in the address bar and click on ‘I promise’ button to continue.
  3. in the Filter box, type: gecko.handlerService.allowRegisterFromDifferentHost
  4. If the value is set to False, double click on the line to turn it to ‘true’
  5. in the address bar again, copy and paste these : javascript:window.navigator.registerProtocolHandler(”mailto”,”https://mail.google.com/a/yourdomain.com/mail/?extsrc=mailto&url=%s”,”Google Apps”)
  6. Remember to replace yourdomain.com with your domain. Also, make sure those are double quotes. After pasting into the address bar, just delete each double quote character and retype them as double quote again – to be sure.
  7. Hit Enter while still in the address bar.
  8. Goto Edit/Preferences or Tools/Options – depending upon your version of Firefox
  9. Goto Applications
  10. Find ‘mailto’ in the list and click on the dropdown – it should now have an entry called ‘Google Apps’. Pick this, click Close.
  11. Goto a website and pick File/Send Link – it should open up your Google Apps email (assuming you’re already logged into the Google Apps account).
    Tagged with:
    Jun 26

    Rhtml in Ruby, Template Toolkit in Perl, Python’s Django templates, Java’s JSP or Freemarker, and ASP .Net files. All have the same philosophy – render HTML with data streamed from the corresponding web framework ‘controller’ modules.

    It’s a great concept – lets you refactor View Templates and come up with ugly looking prototypes quickly. I say ugly since most enterprise programmers tend to have little or no web design skills. Learning effective UI Design is not trivial and asking your programmers to come up with slick UI is a lost cause.

    Then you hire Graphic Designers and UI Developers. And your slick RHTML model starts to break horribly.  Web Designers’ tools such as DreamWeaver etc do not understand the server side Templating languages or they understand parts of it. The Web Developer has absolutely no interest in learning the weird syntax And it’s MUCH harder to design and test web pages in Dreamweaver with pages refactored in mutliple files!

    When faced with the stalemate, we went back to basics. Separation of concerns!! Divide and Rule. Let two teams work with their favorite tools and we’ll connect the bridge with good old JSON transport. No need to do server side templating, rendering and refactoring. The backend developers had no need to mess around with HTML, CSS, Gifs and PNGs!

    So, here’s our setup which keeps everyone happy. For now.

    The only connection between Developers( including  Javascript developers) and designers is via <div> IDs. Once those container blocks are placed in HTML pages, the Programmer renders the UI widgets and takes care of AJAX communication with back end.

    The Web Designers can continue using Dreamweaver and it’s associated parameterized templates to manage refactoring.

    Going pure JSON also means, we can do away with massive rendering Engines in Rails, Merb or other frameworks and work with much simpler Data Delivery Engines which are REST compliant and serve pure JSON. We’ll talk about building such an Engine using Rack in a separate post.

    Tagged with:
    Jun 23

    Okay, it’s time to put the content for your website together. Easy, right? There is probably tons of stuff about the product or service you provide laying around the office so you’ll just compile the technical information about each and list it out. Well, if only it were that simple.

    The problem is most products and services are unique or fall into a pretty generic group along with everyone else who sells the same thing. So, how are you going to get found by the visitor and ’speak’ to them so they first find, then choose your business?

    You are going to start by talking their language and entering the conversation in their head. You will earn the trust of these people when you talk to them the same way they talk to each other and themselves. Try to imagine what the website visitor is going through to need your product or service. When they sit down to search, what would they be looking for and how they might start their search. Would they start with searching the exact product name and technical details? Probably not, how would they know what those were? Keep in mind, if they knew of a product/business already, they would go straight to the website, there would be no search conducted. So…

    Most likely the potential visitor would start by searching for information about the problem at hand. By this I mean the pain point are they trying to address.That would be something they know, but what they don’t always know is how to solve it and/or what the solution is. That’s where your website comes in. Your website would lead with information about solving problems, not information about the product or service itself. Now, here’s the perfect example of what I’m talking about.

    I know this is an old over-used example, but…it’s just so good I can’t resist using it, yet again.

    Nobody who bought a drill wanted a drill. They wanted a hole. What this means for you is that instead of providing information about drills, you should deliver information about making holes.

    Tagged with:
    Jun 22

    It’s hard for a business to survive today.  This has caused lot’s of companies to incorporate practically any method of prospecting new business such as constant cold calls, daily eblast, ineffectively designed direct mail, etc..

    With a rapid fire of  sales genres being applied in attempt to win customers, the buyer is steadily becoming desensitized and blocking most of this crap out. The buyer knows they can just google a service / product  if they need to and become annoyed at the unwelcome sales contact. Obviously this leaves a bad taste in their mouth. In the end the buyer will be the one to approach a business should they decide to and only if the business is deemed worthy.

    That’s why it’s super important that you have a professional web presence built and are positioned and ready to allow the buyer/searcher to find you first instead of you calling them. With most people starting their search for products or services on the web, they can do the research and check out places before they dive in and make contact.  Make sure your website is in good position out there delivering the information the searcher/buyer is looking to find.

    When these buyers contact you via website, they  already know what you do and how you can help them.  By letting the prospect approach you, their perception of you is different. You will be a consultant to them, not a pesky peddler with unwanted goods that were not asked for.  That alone gives you a good chance at selling to them and gains you instant respect.

    Think of  positioning your website vs. prospecting this way;  if you needed a doctor, you would research and choose one you felt comfortable with.  You probably wouldn’t choose the prospecting doctor who happen to call you at breakfast one week wondering if you had a migrane headache they could help with nor would you choose the prospecting doctor who sent you a flyer in the mail offering a significant new patient discount that expires in two weeks.

    What it boils down to is the doctor doesn’t find the patient, the patient find them. This creates the patient confidence to accept the diagnosis and follow recommended orders no matter how inconvenient or painful.

    Get competitive and make sure your website is out there and ready to be found when these potential customers start their research. Lastly, make sure your website is delivering information that will help the visitor get started, then want to contact you to learn more. That is website positioning, not prospecting.

    Tagged with:
    Jun 22

    The Java Virtual Machine debuted around 1995.  People who are old enough to remember Netscape probably remember very first Applets and claims of how embedded Java bytecode was going to change the world order and eradicate world poverty.

    Poor applet died with Netscape and died again when Internet Explorer refused to bundle the JVM.

    But JVM lived on and after years of optimizations, it’s probably the best Virtual Machine around. Some benchmarks give it an edge over C++  which is not hard to explain since even memory leak free C++ code suffers from memory fragmentation.  But, I’m excited again with the JVM for an entirely different reason.  While Java was better and cleaner and simpler than C++, it was still quite verbose. Dynamic Languages like Perl, Python and Ruby offered terseness and expressiveness unknown to the Java Programmers. CPUs got faster. Good Programmers got more expensive. It made sense to trade CPU time for programming time. Why waste time writing 10 lines of java code when an one liner Perl would do the same thing? Number of bugs is directly proportional to the number of lines of code. Less code is better code.  For years, the Java world (and the Microsoft world) tried to hide behind ever more complex tools like Eclipse, Netbeans and Visual Studio. Tools might be nice but they rot the programmers’ mind. They dumb  them down and provide a false sense of simplicity. Hiding a Language’s complexity behind even more complex tools is a terrible idea.

    I know of many highly paid Microsoft programmers who copied Visual Studio generated DCOM code around without understanding what was it doing.  The technology was so darn complex that hardly anyone understood the guts of it.

    So, why am I beginning to like Java again?

    It’s not really the Java Language itself. It’s the new crop of JVM based higher level languages that have cropped up recently, that make me believe in this Virtual Machine again.  Take a look at Scala, Groovy and JRuby. All based on the JVM and all are modern languages with the same expressiveness that I’ve come to like in Ruby and Perl. Best of all, these langauges conform to the Java bytecode! The entire Java Library is instantly available to these languages. No need to wait for your favorite Java Library to get ported to any of these.  Given the fact that almost every library has already been ported to Java, it means, you can have your cake and eat it too.

    Ruby is beautiful and fast moving. But Scala is beautiful, fast moving and is super rich with libraries!

    Finally, we can truly start using the right tool for the job.

    The pervasiveness of JVM means truly mobile code is now a possibility.  Imagine code snippets written in Plain Old Java and Scala and Groovy and JRuby being shipped over the Internet for remote execution! Netscape and Applets live on!!

    Tagged with:
    Jun 19

    Why isn’t there a standard report that lists all Concurrent Requests that have ended in error? Which System Administrator does not want to schedule such a report to run every morning? Oracle does have a report that reports on all Concurrent Requests (FNDCPCRQ). I don’t want to browse through 1445 reports that ran yesterday, do I? Ok, so I rigged that standard program to produce what I want.

    SELECT
    cr.request_id ReqId,
    cp.description Prog,
    lk.meaning STATUS,
    fu.user_name Requestor,
    to_char(cr.actual_start_date,'DD-MON-RR HH24:MI:SS') Started,
    to_char(cr.actual_completion_date,'DD-MON-RR HH24:MI:SS') Completed
    FROM
    fnd_concurrent_requests cr,
    fnd_concurrent_programs_vl cp,
    fnd_lookups lk,
    fnd_user fu,
    fnd_application fa
    WHERE cr.concurrent_program_id =  cp.concurrent_program_id
    AND   cp.application_id        =  cr.program_application_id
    AND   cp.application_id        =  fa.application_id
    AND   cr.status_code           =  lk.lookup_code
    AND   lk.lookup_type           =  'CP_STATUS_CODE'
    AND   lk.meaning               IN ('Error','Warning')
    AND   cr.requested_by          =  fu.user_id
    AND   cr.actual_start_date     BETWEEN nvl(Fnd_Date.canonical_to_date('$p_start_date'),sysdate-1)
    AND nvl(Fnd_Date.canonical_to_date('$p_end_date'),sysdate)
    ORDER BY lk.meaning, cr.request_id;

    And if I want to send an e-mail of counts, spool the output and grep for Errors/Warnings… I kept the output simple, with no headers etc so that it is smart phone friendly…

    errors=`grep 'Error' $spool_file|wc -l|cut -d' ' -f1`
    warnings=`grep 'Warning' $spool_file|wc -l|cut -d' ' -f1`
     
    mutt -s "Unsuccessful Concurrent Programs" -a $spool_file $p_email&lt;&lt;EOF
    $errors Errors; $warnings Warnings -- See attachment
    EOF
    preload preload preload