11 septembre 2009


You might as well jump!

It's time to announce another Blogger Birthday feature! Many users have been asking for an easy way to implement "Read more" links on their blog's index page. In fact, for years bloggers have been implementing "Read more" jump breaks themselves by manually editing their HTML --- a process that was complicated and error prone.

Today we are excited to announce our latest birthday present:Jump Breaks.

With Jump Breaks you can show just a snippet of your post on your blog's index page. Blogger will insert a "Read more" link to the full post page where your readers can keep reading.



How to Access Gmail When It’s Down [Gmail]

Last week's Gmail outage is just the latest in a long series of outages in our favorite webmail application, but you don't have to let that stop you from accessing your email and getting things done.

Access Gmail Through Alternate Modes

Just because the Gmail web interface went down doesn't mean that Gmail is entirely down—often you can continue to access your account using one of the alternate web interfaces, which often are still accessible even when the regular web interface goes down.
Here's a quick look at each alternate method, one at a time, from the simplest to the most complex. (The more complex solutions are often better long-term solutions, while the simpler solutions are probably the easiest if Gmail just went down and you haven't already prepared for it.)

Try Plain HTML

Your best bet is to bookmark the link for the Plain HTML version of Gmail (or just bookmark this post), so you can quickly switch to this alternate mode if Gmail is giving you trouble loading. http://mail.google.com/mail/?ui=html . It doesn't have all the fancy features that regular old Gmail does, but it can do the job just fine in a pinch.

Use Safe Mode

If you use a lot of different Gmail Labs features, you might find that some of them will conflict with each other, or possibly cause Gmail to stop working. You can use the Safe Mode link to disable all the Labs features and hopefully get Gmail back up and running again. Just visit this URL: http://mail.google.com/mail/?labs=0. Some people recommend using the older version or bypassing browser checking links, but they won't let you access the Labs settings.

Use the Mobile Versions

You can access the mobile phone versions of Gmail from your desktop computer, although they are very stripped down and lacking features. You'll be better off with the Plain HTML version, but in a pinch you can try the regular mobile version http://mail.google.com/mail/?ui=mobile or the more user-friendly iPhone version http://mail.google.com/mail/x/gdlakb-/gp/.

Use the iGoogle Gadget

We've seen numerous comments and emails from readers during Gmail outages recommending that the excellent Gmail gadget for iGoogle usually still works during a Gmail downtime. If you aren't an iGoogle user, you can still use the gadget by simply browsing to the following URL: http://www.google.com/ig/gmailmax

Use Gmail Offline Access

If you haven't already checked out the Google Gears-powered offline mode for Gmail, this is a must-use for anybody that really depends on Gmail access. You can continue to use your email whether Gmail is running or not, or even when your own internet goes out. It's not perfect, since it doesn't store every single email in your inbox locally, but it does store enough email to be a great solution.
The biggest benefit in daily use is the Flaky Connection Mode, which is a hybrid between the offline and online modes, and makes Gmail response time much faster for everyday email tasks for those on slower connections. In this mode, Gmail effectively works like a desktop client.

Access Gmail Through IMAP / POP3

During the last Gmail outage, IMAP and POP3 access weren't affected at all, so those using a desktop or mobile client to access their email were still able to send and receive without even knowing there was an issue. Even if you use the web interface as your primary method of email access, it's a good idea to at least keep a Thunderbird installation setup with IMAP access to your email in a pinch.
We've already got you covered with a complete guide to setting up Thunderbird as the ultimate Gmail IMAP client, but since then, setting up Gmail in Thunderbird has turned into an easy process, requiring only a few clicks through the account settings. If you are an Outlook user, you can follow a detailed guide I've written to set up IMAP in Outlook 2007. If you've got a mobile phone, the Gmail Help site has instructions on setting up just about any smart phone with IMAP access to your email. If you really want to prove your nerd credentials, you can even access your Gmail from the command line.

Prepare For the Next Outage

Gmail doesn't have to go down globally for your email access to be cut off—your internet could go down, or your account could even be disabled. Whatever the case, it's a good idea to have a backup plan just in case the worst should happen.
We've got you covered with a number of methods for backing up your Gmail, starting with the really obvious solution of just using Thunderbird to back up your email with POP access, but you can backup your email with Fetchmail on Windows, Getmail on Linux, the standalone Gmail Backup tool, or even use Google Groups to backup your Gmail account.
What email accessing workaround, if any, worked for you during the last Gmail outage? Let us know in the comments.
The How-To Geek nervously wore the letters off the F5 key during the last Gmail outage, and hopes it doesn't happen again—Ever! His geeky articles can be found daily here on Lifehacker, How-To Geek, and Twitter.

The 7 Software Development Wastes - Part 6 - Delays

Introduction

Interestingly, this weeks blog covers the 6th waste - Delays - as identified in Lean. How appropriate after the long delay since my last blog post on Task Switching. Herein lies an example of what Delays in software development can cause. Delays introduce discontinuity and trigger additional wastes already covered like Relearning. It's important in any process, including software, to have continuity. This reduces cycle time and minimizes other wastes like Relearning, Task Switching etc.

Focus on the end-to-end process, not individuals

It's important to identify Delays early on and try to rectify them as soon as possible in order to maximize team productivity. It's interesting... I have been reading many interesting threads on the Agile forums lately about measuring developer productivity, team productivity etc. Managers/executives have us focus our efforts and attention on individuals instead of looking at the end-to-end process to find the real issues that address productivity and enhance team effectiveness.

<!--break-->

It's actually unbelievable to me that organizations get trapped like this. Always thinking that Developers are the bottleneck. If we learn from what Lean teaches us, simple value stream mapping can uncover the real gems that can increase productivity.

Reducing delays between sprints

It's important to ensure that the value stream is tuned for maximum efficiency where there are little to no delays at any point in the process. For example, yesterday someone posted a question on one of the forums asking if it's possible to not have delays between sprints. Well of course it is possible but it takes hard work to get this right. You have to ensure that the backlog is properly groomed. So you need an effective PO who understands the market, the client etc. You need well written stories. You need estimates from developers early so the PO can make decisions ahead of the planning meeting. It's all about designing delays out of the system so that there are smooth hand-offs at all the transition points. And it's worth mapping this end-to-end process and identifying delays at each of these points.

Common Delays

So what are some of the more common delays you can look for and what can you do to avoid them?

1. Project approvals - waiting for projects to get approved is the most cardinal of all sins as this usually has handfuls of developers sitting around twiddling their thumbs and is a blatant disrespect for peoples time. Coupled with this is the fact that waiting causes dissatisfied and disgruntled employees and only serves to ruin the culture in an organization

2. Waiting for a proper prioritized list of requirements - so that work can get started.

3. Waiting for resources to become available - generally impacts projects significantly. This one is not necessarily an easy one to solve as there are generally budgetary concerns. But this then begs the question - is the company taking on too much? You can't be successful if you're not focused and properly staffed.

4. Change approval processes - well you don't want to hear my opinion on this. Suffice to say, these processes need to be eliminated entirely. And all Agile processes inherently solve these problems. Shortening Sprints helps big time.

5. Increases in work-in-progress - The more work-in-process, the more developers have to wait before they can deploy their code to production.

6. Delays getting client to sign-off on acceptance tests - We have a services business and we find that this is a huge problem for our organization. Not getting sign-off is just a liability for the company as you're not getting paid until you get sign-off

Take the time to assess where delays are occurring and I can guarantee you that the effort spent doing this is hugely beneficial to your productivity, efficiency and overall bottom line.

9 septembre 2009


TechPosters Archives Tech-Oriented Posters and Cheat Sheets [Cheat Sheets]

Whether you need a poster to use for a presentation or a cheat card to keep by your monitor, TechPosters has a sizable archive of posters, diagrams, reference charts, and cheat sheets.
The hundreds of entries at TechPosters span dozens of categories including everything from Access to XML and everything in between. Need keyboard shortcuts for Indesign? A visual representation of the Linux kernel? You'll find it at TechPosters.
If you find a particularly interesting document out of the bunch make sure to share a link to it in the comments below. Have your own favorite resource for cheat sheets and technical posters? Sound off in the comments.

iPhone and iPod touch OS 3.1 Available for Download [Downloads]

iPhone/iPod touch only: Apple today announced an update to iPhone OS 3.1 today, introducing a new 'Genius' recommendation feature for the App Store. bug fixes and performance boosters, and several other small but worthwhile updates.
It's also added a Ringtone section to the App Store on your device (for a whopping $1.29 a pop—which is why we recommend making them yourself [Windows guide; Mac guide]). Other than that, Apple's not promising a lot from this update other than support for the newly released iTunes 9, its new features (e.g., Genius Mixes), and a few other nice tweaks. Below is a quick look at some of the other most notable updates from the release notes:
  • Save video from Mail and MMS into Camera Roll (We'll believe the MMS saving when we finally see MMS)
  • Option to 'Save as new clip' when trimming a video on iPhone 3GS
  • Better iPhone 3G Wi-Fi performance when Bluetooth is turned on
  • Paste phone numbers into the Keypad
  • Anti-phishing features in Safari
  • Improved Exchange calendar syncing and invitation handling
Hit up iTunes, plug in your device, and click the Check for Updates button to get started on the 240+MB download.

Build Web Apps for iPhone using Dashcode


So far, much mobile developer attention has been fixated on the iPhone SDK released by Apple to build native iPhone applications. This is understandable, since with the SDK you can write native iPhone apps that take full advantage of the capabilities provided by the device, such as accessing the accelerometer, the camera, as well as obtain geographical locations using Core Location.
However, building Web applications for the iPhone has advantages too. For example, there is no need to wait for approval from Apple, as in the case of hosting the applications in AppStore. Also, the tools provided by Apple makes it very easy to build Web applications that look just like native iPhone applications. And when it comes to developers' skill-sets, developing Web applications is far easier than building native applications - all you need is some Javascript skills and you are ready to go!
In this article, I will take you through the Dashcode tool provided by Apple (part of the iPhone SDK; hence you need to download it first) to build compelling Web applications for the iPhone.

Trying Out the Various Templates

When you first launch Dashcode (the easiest way to launch it is through Spotlight), you will see that Dashcode has already created some templates for you to build your Web applications quickly (see Figure 1).

Figure 1: The various templates provided by Dashcode
The best way to learn is to select each template (other than the Custom template) and examine the content of each application. When you have selected a template, examine their contents and press Command-r to test the application on the iPhone Simulator. Go ahead and have fun with each template. When you have enough fun and get yourself acquainted with the environment, come back and we shall create an iPhone Web application from scratch and you will see how each part is built.

Building the UI

Alright, now that you are back, create a new Custom project In Dashcode. Notice that by default, Dashcode created a content and a footer parts for you (see Figure 2). Parts are the various views that you seen on your Web applications, such as buttons, text, etc. For this section, you will create a simple currency convertor Web application for the iPhone.

Figure 2: The parts in the Custom template
Select each of these parts and press the delete key. We shall delete these two parts and add our own parts manually.
Using the Library (Window'Show Library), drag-and-drop a Stack Layout part to the design surface (see Figure 3).

Figure 3: Using the Library to drag and drop parts onto your application
Expand the stackLayout part and you should see that it contains two subviews - view1 and view2. Select view1 and change its size to 320px by 356px (see Figure 4) via the Inspector window (Window'Show Inspector). Do the same for view2.

Figure 4: Changing the size for view1 and view2 via the Inspector window
Double-click on view1 and rename it as mainScreen. Do the same for view2 and rename it as settings (see Figure 5).

Figure 5: Renaming the two subviews
In the Library, drag-and-drop the Rounded Rectangle Shape part onto the mainScreen view (see Figure 6).

Figure 6: Adding the Rounded Rectangle Shape part to the subview
It its Inspector window, select the Fill & Stroke tab and in the Style tab select Gradient fill (see Figure 7) and select two colors.

Figure 7: Using the gradient fill to fill the part
Select the Effects tab and check the Glass and Recess checkboxes (see Figure 8).

Figure 8: Adding glass effect to the part
Select the Metrics tab and select the Absolute layout (see Figure 9).

Figure 9: Using absolute layout for parts positioning
Add the following parts to the Rounded Rectangle Shape part (see Figure 10) and name them as shown:
  • Text
  • TextField
  • Pop-up Menu
  • Push Button

Figure 10: Adding additional parts to the subview
Select the settings subview and repeat the same steps you have performed above. Figure 11 shows the parts added to the settings subview.

Figure 11: Populating the settings subview
You are now ready to view the application on the iPhone Simulator. Press Command-r to view the application on the iPhone Simulator (see Figure 12). Notice that the application is hosted by mobile Safari on the iPhone.

Figure 12: Viewing the application on the iPhone Simulator
Notice that you can only see the mainScreen subview. To see the settings subview, you need to write some code to navigate to it from the mainScreen subview.

Coding the Application

So you are now ready to write some code. With the mainScreen subview selected, right-click on the Settings button and select Events'onclick (see Figure 13).

Figure 13: Creating an event handler for the onclick event
You will be asked to name the event handler for this event. Name it as shown in Figure 14.

Figure 14: Naming the handler for the event
Notice that the code editor now appears at the bottom of the designer (see Figure 15).

Figure 15: The code editor where you can add your code
Enter the following code:
function btnSettings_ClickHandler(event)
{
    var views = document.getElementById('stackLayout');
    var settings = document.getElementById('settings');
    if (views && views.object && settings) {
        views.object.setCurrentView(settings);
    }
}
Select the settings subview and right-click on the Save Settings button and select Events'onclick. Name the handler as btnSave_ClickHandler. Enter the following code:
function btnSave_ClickHandler(event)
{
    var views = document.getElementById('stackLayout');
    var front = document.getElementById('mainScreen');
    if (views && views.object && front) {
        views.object.setCurrentView(front, true);
    }
}
Test the application again by pressing Command-r. This time, you will be able to navigate to the settings view by tapping on the Settings button in the mainScreen subview (see Figure 16).
Figure 16. Tapping on the Settings button navigates to the settings subview

Database Access

So far, your application displays two screens where you can perform some currency conversion as well as set the exchange rates for the different currencies. For simplicity, I am going to assume that you are converting the currencies into Singapore Dollars (SGD). All the exchange rates would be based on the SGD as the base currency.
To allow the users to store their own exchange rates, you will make use of the local database feature as defined in HTML 5 (which is supported by Mobile Safari). Doing so allows users of your application to store the exchange rate locally on their iPhones.
In the main.js file, add the following lines of code for performing database operations:
var database = null;                           // The client-side database
var DB_tableName = "CurrencyKeyValueTable";    // database name
 
// Function: initDB() - Init and create the local database, if possible
function initDB()
{
    try {
        if (window.openDatabase) {
            database = openDatabase("ExchangeRatesDB", "1.0", 
                                    "Exchange Rates Database", 1000);
            if (database) {
                database.transaction(function(tx) {
                    tx.executeSql("SELECT COUNT(*) FROM " + DB_tableName, [],
                    function(tx, result) {
                        loadRates();
                    },
                    function(tx, error) {
                        // Database doesn't exist. Let's create one.
                        tx.executeSql("CREATE TABLE " + DB_tableName +
                        " (id INTEGER PRIMARY KEY," +
                        "  key TEXT," +
                        "  value TEXT)", [], function(tx, result) {
                            initRates();
                            loadRates ();
                        });
                    });
                });
            }
        }
    } catch(e) {
        database = null;
    }
}
 
// Function: initRates() - Initialize the default exchange rates
function initRates()
{
    if (database) {
        database.transaction(function (tx) {
            tx.executeSql("INSERT INTO " + DB_tableName + 
                " (id, key, value) VALUES (?, ?, ?)", [0, 'USD', 1.44]);
            tx.executeSql("INSERT INTO " + DB_tableName + 
                " (id, key, value) VALUES (?, ?, ?)", [1, 'EUR', 2.05]);
            tx.executeSql("INSERT INTO " + DB_tableName + 
                " (id, key, value) VALUES (?, ?, ?)", [2, 'AUS', 1.19]);
        });
    }
}
 
// Function: loadRates() - Load the currency exchange rates from DB
function loadRates()
{
    var element;   
    var popUpElement = document.getElementById('popupConvertTo');
 
    if (database) {
        database.transaction(function(tx) {
            tx.executeSql("SELECT key, value FROM " + DB_tableName, [],
            function(tx, result) {
                for (var i = 0; i < result.rows.length; ++i) {
                    var row = result.rows.item(i);
                    var key = row['key'];
                    var value = row['value'];
 
                    //---populate the pop-up menu part---
                    popUpElement.options[i].text = key;
                    popUpElement.options[i].value = value;
 
                    if (key == 'USD') {
                        element = document.getElementById('txtUSD');
                    }
                    else {
                        if (key == 'EUR') {
                            element = document.getElementById('txtEUR');
                        }
                        else if (key == 'AUS') {
                            element = document.getElementById('txtAUS');
                        }
                    }
                    element.value = value;
                }
            },
            function(tx, error) {
                showError('Failed to retrieve stored information from database - ' + 
                    error.message);
            });
        });
    }
    else {
        loadDefaultRates();
    }
}
 
// Function: saveRates() - Save the currency exchange rates into DB
function saveRates()
{
    if (database) {
        var elementUSD = document.getElementById('txtUSD');
        var elementEUR = document.getElementById('txtEUR');
        var elementAUS = document.getElementById('txtAUS');
 
        database.transaction(function (tx) {
            tx.executeSql("UPDATE " + DB_tableName + " SET key = 'USD', 
                value = ? WHERE id = 0", [elementUSD.value]);
            tx.executeSql("UPDATE " + DB_tableName + " SET key = 'EUR', 
                value = ? WHERE id = 1", [elementEUR.value]);
            tx.executeSql("UPDATE " + DB_tableName + " SET key = 'AUS', 
                value = ? WHERE id = 2", [elementAUS.value]);
        });
    }
    loadRates();
}
 
// Function: deleteTable() - Delete currency exchange table from DB
function deleteTable()
{
    try {
        if (window.openDatabase) {
            database = openDatabase("ExchangeRatesDB", "1.0", 
                                    "Exchange Rates Database");
            if (database) {
                database.transaction(function(tx) {
                    tx.executeSql("DROP TABLE " + DB_tableName, []);
                });
            }
        }
    } catch(e) { 
    }
}
 
// Function: loadDefaultRates() - Load the default exchange rates
function loadDefaultRates()
{
    var popUpElement = document.getElementById('popupConvertTo');
    var element = document.getElementById('txtUSD');
    element.value = "1.44";
    popUpElement.options[0].text = "USD";
    popUpElement.options[0].value = element.value;
 
    element = document.getElementById('txtEUR');
    element.value = "2.05";
    popUpElement.options[1].text = "EUR";
    popUpElement.options[1].value = element.value;
 
    element = document.getElementById('txtAUS');
    element.value = "1.19";
    popUpElement.options[2].text = "AUS";
    popUpElement.options[2].value = element.value;
}
The database code above is pretty straightforward - store the exchange rates inside the database and populate the pop-up menu part when the rates are retrieved.
Modify the load() function as follows:
//
// Function: load()
// Called by HTML body element's onload event when the Web application is ready to 
// start
//
function load()
{
    dashcode.setupParts();
 
    initDB();    
    if (!database) {
        loadDefaultRates();
    }
}
Press Command-r to test the application. When the application is loaded, the pop-up menu will now display the three different currencies (see Figure 17).
Figure 17. The pop-up menu part displaying the different currencies
When you tap on the Settings button, the exchange rates would also be displayed in the settings subview (see Figure 18).
Figure 18. The exchange rates displayed in the settings subview

Performing the Conversion

You are now ready to perform the actual conversion of the currencies. In Dashcode, select the mainScreen subview and right-click on the Convert! Button and select Events'onclick (see Figure 19).
Figure 19. Handling the onclick event for the Convert! button
Name the event handler as btnConvert_ClickHandler and code it as follows:
function btnConvert_ClickHandler(event)
{
    var amount = document.getElementById("txtAmount").value; 
    var rates = document.getElementById("popupConvertTo").value;
    var result = amount * rates;
    alert(result);
}
Press Command-r to test the application. Enter an amount and select the currency to convert. Tapping on the Convert! button will now display the amount converted (see Figure 20).
Figure 20. Try converting some currencies!

Converting your Web Application into an iPhone Native Application

Now that your application is completed, you may deploy your application onto a Web server so that users can access your application through the Safari browser on their iPhones. However, since this is a Web application, the user must have access to the Internet, or else there is no way to access your application. And since our application does not make use of any server-based data, it is a good candidate to convert into a native iPhone application. The easiest way would be to host the Web application within the Safari browser, which is represented by the WebView view in the iPhone SDK.
In this section, I will show you how you can convert an iPhone Web application into a native iPhone application.
First, deploy your Web application by clicking the Share item in Dashcode (see Figure 21). Click the Deploy button so that all the files of the application will be saved to a Web publishing directory. Take note of the Web publishing directory shown in Dashcode. It is saved in /Users//Sites/CurrencyConvertor/. You will make use of the files contained within this folder shortly.
Figure 21. Deploying a Web application in Dashcode
Launch Xcode and create a new View-based Application project. Name the project as CurrencyConvertor.
In Finder, navigate to the /Users//Sites/CurrencyConvertor/ folder and select the files shown in Figure 22.
Figure 22. All the project files created by Dashcode
Drag-and-drop all the selected files onto the Resources folder in Xcode. Xcode will prompt you with a dialog (see Figure 23). Check the Copy items into destination group's folder (if needed) checkbox and click Add.
Figure 23. Adding all the Dashcode files into the Resource folder in Xcode
Perform a global Find-and-Replace (by pressing Shift-Command-F). Search and replace the following strings with an empty string (see Figure 24):
" "Parts/"
" "Images/"
Figure 24. Replacing all instances of "Parts/" and "Images/" with an empty string
This will update the various HTML and JavaScript files that reference other files using the Parts/ and Images/ folder. Files stored in the Resources folder of your Xcode application have no directory structure when they are deployed; hence all the files are in a flat directory.
Select the files shown in Figure 25 and drag-and-drop them onto the Copy Bundle Resources (16) folder. This will ensure that all the HTML, JavaScript, CSS, and images files will be deployed together with your application.
Figure 25. Copying all the Web files into the targets folder so that they are deployed together with your application
In the CurrencyConvertorViewController.h file, add the following statements to define an outlet:
#import 
 
@interface CurrencyConvertorViewController : UIViewController {
 IBOutlet UIWebView *webView;
}
 
@property (nonatomic, retain) UIWebView *webView;
 
@end
Double-click on the CurrencyConvertorViewController.xib file to open it in Interface Builder.
Add a WebView view to the View window and control-click and drag the File's Owner item to the WebView view (see Figure 26). Select webView.
Figure 26. Connecting an outlet to a view
In the CurrencyConvertorViewController.m file, add the following statements:
#import "CurrencyConvertorViewController.h"
 
@implementation CurrencyConvertorViewController
 
@synthesize webView;
 
- (void)viewDidLoad {
 NSString *path = [[NSBundle mainBundle] pathForResource:@"index" 
                        ofType:@"html"];
 [webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath: path 
                            isDirectory:NO] ]];
    [super viewDidLoad];
}
That's it! Press Command-r to test the application on the iPhone Simulator. The Web application is now hosted within the WebView view (see Figure 27). What you have just done is convert a Web application into a native application!
Figure 27. Running the Web application as a native iPhone application

Summary

In this article, you have seen how easy it is to build Web applications for the iPhone using the Dashcode tool included in the iPhone SDK. Not only that, you have also learned how to convert a Web applications into a native application. If you are currently building Web applications for the iPhone, drop a note below to share with us what type of applications you are building.



http://mobiforge.com/developing/story/build-web-apps-iphone-using-dashcode