backbone.js learning note [3]

May 14, 2012 Leave a comment

[ update 5/14/2012 ] This single page app is now available at http://whatsmyspeed.appspot.com/. Decided to go (back) with google app engine instead of heroku due to (initial start) performance reason.

I am definitely addicted to backbone.js and I just threw some backbone into the running speed calculator I wrote some time ago (with node.js):

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Speed Calculator</title>
	<style type="text/css">
		body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; }
		a { color: #00B7FF; }
		label {width:100px;font-weight:bold;display:block;float:left;}
		input[type="text"] {width:120px;margin-right:5px;}
	</style>
</head>
<body>
	<div id="container">
	   <p> 
		  <label>Distance</label>
		  <input id="distance" type="text" placeholder="distance in miles">
		</p>
		<p>
		  <label>Time</label>
		  <input id="time" type="text" placeholder="ex: 24:25, 01:45:17">
		</p>
		<p>
		  <label>Speed</label>
		  <input id="speed" type="text">
		</p>
	</div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
	<script>
		var Speed=Backbone.Model.extend({
			defaults: {
				distance:0,
				time:0
			}
		});
		var SpeedView=Backbone.View.extend({
			el:$('body'),
			events: {
				'blur input#time': 'update_model',
				'blur input#distance': 'update_model'
			},
			initialize: function() {
				_.bindAll(this, 'render');
				this.model.bind('change', this.render);
			},
			update_model: function() {
				this.model.set({
					time: $('#time').val()
					,distance: $('#distance').val()
				});	
			},
			render: function() {
				$('#speed').val('');
				var dist_str=this.model.get('distance')
					, time_str=this.model.get('time')
				if( dist_str!='' && time_str!='' && !isNaN(dist_str) ) {
					var speed=this._calc_speed(dist_str, time_str);
					if(speed!=null) {
						$('#speed').val(speed.toFixed(3));
					}
				}
				return false;
			},
			_calc_speed: function(dist_str, time_str) {
				var dist_reg=/^([0-9]+(?:\.[0-9]+)?)$/
					, dist_res=dist_reg.exec( dist_str )
					, time_reg=/^(?:(?:(2[0-3]|[0-1]?[0-9])[:])?([0-5]?[0-9])[:])?([0-5]?[0-9](?:\.[0-9]+)?)$/
					, time_res=time_reg.exec( time_str );
				if(dist_res && time_res) {
					var hours=(time_res[1]||0)*1
						, minutes=(time_res[2]||0)*1
						, seconds=(time_res[3]||0)*1
					total_seconds=hours*3600+minutes*60+seconds;
					if(total_seconds>0) {
						return 3600*dist_res[1]/total_seconds;
					} else {
						return null;
					}
				}
				return null;
			}
		});
		var speed=new Speed();
		var speedview=new SpeedView({model:speed});
	</script>
</body>
</html>
Advertisements
Categories: backbone.js, javascript

backbone.js study note [2]

May 13, 2012 Leave a comment

Here’s an improved and complete example to the first learning note on backbone.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>stock price simple demo</title>
</head>
<body>
    <div id="data"></div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>

    <script>
        var Stock=Backbone.Model.extend({
            defaults: {
                price: 123
            }
        });

        var StockList=Backbone.Collection.extend({
            model: Stock
        });

        var ItemView=Backbone.View.extend({
            tagName: 'li',
            initialize: function() {
                _.bindAll(this, 'render');
                this.model.bind('change:price', this.render);
            },
            render: function() {
                $(this.el).html('<span>'+this.model.get('price')+'</span>');
                return this;
            }
        });

        var stock1=new Stock({price:333});
        var stock2=new Stock({price:555.667});

        var StockView=Backbone.View.extend({
            el: $('#data'),
            initialize: function() {
                _.bindAll(this, 'render');
                this.collection=new StockList();
                this.collection.add(stock1);
                this.collection.add(stock2);
                this.render();
            },
            render: function() {
                $(this.el).append('<ul></ul>');
                _(this.collection.models).each( function(item) {
                    var itemview=new ItemView({model:item});
                    $('ul', this.el).append(itemview.render().el);
                }, this);
            }
        });
        var stockview=new StockView();
    </script>
</body>
</html>

To test what it does (so far this is the most impressive feature of backbone, the rendering is actually linked directly to the change of model), open a Javascript console (in Chrome or with Firebug in Firefox), and type

stock1.set({ price: 10 })
stock2.set({ price: 999 })

, pay attention to the changes on the page.

References:
http://arturadib.com/hello-backbonejs/docs/5.html

Categories: backbone.js, javascript

How to make an Ajax form without capturing key press event on the input element

May 13, 2012 Leave a comment

OK this is a very common task: build a form, collect user input and send to server for processing (through Ajax therefore upon response the page should remain the same). One of the ways to accomplish this is to bind the ajax handling function to both the submit button (or an anchor link)’s click event and the input field’s key press event (only when Enter key is pressed):

<!DOCTYPE html> 
<html>
<head>                  
    <meta charset="utf-8">                                               
    <title>submit test using onclick and onkeydown event</title>
</head>             
<body>
    Name:   <input type="text" name="user_name" value="" id="user_name" onkeydown="kp_handler();">
    <p><input type="button" value="Continue &rarr;" onclick="handle_submit();"></p>
    <script type="text/javascript">
        function kp_handler(evt) {
                if(!evt && window.event) evt=window.event;
                if(evt.keyCode==13) {
                    handle_submit();
                }   
        }           
        function handle_submit() {                      
            // you might want to do ajax here to submit data to the server
            // as a demo I just print the data to the client's browser
            var msg='You have entered '+ document.getElementById('user_name').value;
            try {
                console.log(msg);
            } catch (e) {
                alert(msg);
            }
        }
    </script>
</body>
</html>

However, a better approach is to do it through a dummy form enclosing the text input and submit button. The benefit of of this is the Enter key event is automatically handled by form’s onsubmit attribute hence there’s no need to capture the onkeydown event on the text input element (figuring whether the Enter key is pressed is messy as you can see from the first approch):

<!DOCTYPE html> 
<html>
<head>                  
    <meta charset="utf-8">                                               
    <title>submit test using only onsubmit event</title>
</head>             
<body>
    <form id="some_form" onsubmit="javascript: handle_submit(); return false;">
        Name:   <input type="text" name="user_name" value="" id="user_name">
    <p><input type="submit" value="Continue &rarr;" ></p>
    </form>
    <script type="text/javascript">
        function handle_submit() {
            // you might want to do ajax here to submit data to the server
            // as a demo I just print the data to the client's browser
            var msg='You have entered '+ document.getElementById('user_name').value;
            try {
                console.log(msg);
            } catch (e) {
                alert(msg);
            }
        }
    </script>
</body>
</html>

It’s worth noting that the return false statement has to be put at the end of the onsubmit attribute (moving it into handle_submit will result in the form submitting to the page itself).
Comments and feedbacks are welcome.

Categories: javascript

A simple password generator written in node.js

Probably not a very advanced password generator but should be adequate for general purpose, see https://github.com/midnightcodr/gen_pass for details.

Simple html to text converter

May 3, 2012 2 comments

This is follow-up post on sending html email using swift mailer [ see previous post here ].

Since it’s never fun to have to write the same (or similar) stuff twice, the other morning I started to look for something than can do some basic html to text conversion, that is, turn br, p into newline, at the minimum. Through googling I discovered this handy php script to do the job. For example, html2text is able to convert the following html

    Dear Customer,
    <p>blah blah...</p>
    <p />
    Sincerely,<br />
    ABC Company Service Dept<br />
    <a href="http://example.com">A link</a>

into plain text

    Dear Customer,

    blah blah...


    Sincerely,
    ABC Company Service Dept
    [A link](http://example.com)

To use the code can’t be easier:

...
require_once 'path/to/html2text.php';
$html="<p>some html text here</p>";  // original html message
$plain=convert_html_to_text($html);   // converted plain text
...

Here’s a complete example on how to use it with swift mailer to send out html email (at a low SPAM score):

<?php
        require_once 'lib/swift_required.php'; // or absolute path if swift mailer library is not under current directory
        require_once 'path/to/html2text.php';
        define('mailhost', 'localhost'); // change if using external smtp server
        $to='some_recipient@email.address';
        $subject='HTML msg sending test';
        $body_html='<p>This is a <strong>test</strong>.</p>';
        $plain=convert_html_to_text($body_html); 
        $transport=Swift_SmtpTransport::newInstance(mailhost, 25);
        $mailer=Swift_Mailer::newInstance($transport);
        $message=Swift_Message::newInstance($subject)
            ->setFrom( array('noreply@yourcompany.com'=>'Your Company Name') )
            ->setTo( array($to) )
            ->setBody($plain)
            ->addPart($body_html, 'text/html');
        $result = $mailer->send($message);
Categories: html2text, php, swift_mailer

How-to: Lower html email spam score using swift mailer

April 19, 2012 Leave a comment

Swift mailer is yet another great PHP emailing library. Working as a web developer, I am faced quite often with the tasks of sending out html email. One particular area I always pay attention to is try to lower the emails’ spam score so they won’t end up in recipient’s junk or spam box. Here’s the ‘magic’ code that does the trick:

<?php
        require_once 'lib/swift_required.php'; // or absolute path if swift mailer library is not under current directory
        define('mailhost', 'localhost'); // or external smtp server
        $to='some_recipient@email.address';
        $subject='HTML msg sending test';
        $body='This is a test.';
        $body_html='<p>This is a <strong>test</strong>.</p>';
        $transport=Swift_SmtpTransport::newInstance(mailhost, 25);
        $mailer=Swift_Mailer::newInstance($transport);
        $message=Swift_Message::newInstance($subject)
            ->setFrom( array('noreply@yourcompany.com'=>'Your Company Name') )
            ->setTo( array($to) )
            ->setBody($body)
            ->addPart($body_html, 'text/html');
        $result = $mailer->send($message);

In real-life examples, I’ve seen score dropping by as much as 2.1 by sending html message along with its plain-text counterpart. The reasoning behind this is well explained in this stackoverflow question:
http://stackoverflow.com/questions/5787185/is-it-sensible-to-send-html-only-email-these-days.

Categories: php, spam score, swift_mailer

Use external smtp server to send nagios alerts

April 18, 2012 7 comments

By default Nagios uses localhost to send out email, this would be a problem if the nagios server’s IP is not designated to send emails. A quick solution is to use utilities that support sending emails through external smtp server, here’s a nice one:

http://caspian.dotconf.net/menu/Software/SendEmail/

Steps (Assuming Nagios version is 3):
1) Download the zip file from http://caspian.dotconf.net/menu/Software/SendEmail/#download, unzip and copy sendEmail.pl to /usr/local/bin

2) Modify commands.cfg so the notify-host-by-email and notify-service-by-email are similar to the followings:
define command{
command_name notify-host-by-email
command_line /usr/bin/printf "%b" "***** Nagios *****\n\nNotification Type: $NOTIFICATIONTYPE$\nHost: $HOSTNAME$\nState: $HOSTSTATE$\nAddress: $HOSTADDRESS$\nInfo: $HOSTOUTPUT$\n\nDate/Time: $LONGDATETIME$\n" | /usr/local/bin/sendEmail -f nagios_notification@your_domain.com -s smtp.server.ip_or_hostname -u "** $NOTIFICATIONTYPE$ Host Alert: $HOSTNAME$ is $HOSTSTATE$ **" -t $CONTACTEMAIL$
}

define command{
command_name notify-service-by-email
command_line /usr/bin/printf "%b" "***** Nagios *****\n\nNotification Type: $NOTIFICATIONTYPE$\n\nService: $SERVICEDESC$\nHost: $HOSTALIAS$\nAddress: $HOSTADDRESS$\nState: $SERVICESTATE$\n\nDate/Time: $LONGDATETIME$\n\nAdditional Info:\n\n$SERVICEOUTPUT$" | /usr/local/bin/sendEmail -f nagios_notification@your_domain.com -s smtp.server.ip_or_hostname -u "** $NOTIFICATIONTYPE$ Service Alert: $HOSTALIAS$/$SERVICEDESC$ is $SERVICESTATE$ **" -t $CONTACTEMAIL$
}

change nagios_notification@your_domain.com and smtp.server.ip_or_hostname to suit your need of course. Consult http://caspian.dotconf.net/menu/Software/SendEmail/#download for more command line options if the smtp server requires authentication, for example.

3) Make sure the new configuration is syntax-error free:
/etc/init.d/nagios checkconfig

4) Restart nagios
/etc/init.d/nagios restart

Notes:
If for some reason nagios doesn’t send out email, please do the followings:
1) enable debugging in /usr/local/bin/sendEmail.pl by setting “logFile” to, say, “/var/log/sendEmail”, change its mode to 666
2) check if nagios contacts contain valid email address. I found out sendEmail doesn’t work with records like
systemadmin: my_real@email.address in /etc/aliases.

Categories: nagios, sendEmail