« April 2005 | Main | June 2005 »

May 06, 2005

Flickr.com with FlickrNet – Photo Sharing Power Tools

Just bought by Yahoo, http://flickr.com has photo sharing priorities in the right place for families. For $25 per year you get 240 GB of incremental storage of personal images where each image can be up to 5MB. Downloads are unlimited. Uploads are limited to 20GB per month. The subscription fee also gives you an ad free interface.

After uploading over 2000 family pictures, I found myself wanting a custom processing tool for transferring meta data I had been storing in filenames to the Tags and Date Taken properties managed by flickr.

Enter Flickr.Net.

I started with the code last updated 2005-2-26 found on GDN Workspaces and looked at the site on WDevs.com which actually seemed to have slightly older code on it.

Because the flikr API makes heavy use of optional arguments, I yielded to temptation and upgraded the project to Visual Studio 2005 beta 1 so I could use nullable types as method arguments.

The result of the modifications to FlickrNet listed below can be downloaded from here http://toneengel.com/d/2005-05-06,FlickrNet,1.12.zip :

·          Added the method Flickr.PhotoSearch to enable searching private photos by date uploaded. It now supports the full API for flikr.photos.search.

·          Added a number of PhotoSearch* methods to search by text, tags, date taken, date loaded, and license.

·          Added enums as appropriate for TagMode, SearchExtras, and SearchMode.

·          Extended the Photos xml mapping class to handle the additional attributes returned by the SearchExtras flags.

·          Added a PhotosSetDates method to allow setting date taken, granularity and date loaded.

·          Added some retry logic to the DoGetResponse method to avoid unhandled timeout exceptions when the servers are heavily loaded.

 

May 04, 2005

Remote Desktop Connection Diagnostics

May 03, 2005

Filenames Are Dead

While we all still use computers with hierarchically organized folders of files, where each file is known primarily by its filename, the truth is that filenames are dead. Content and meta-data based searching killed them. And it’s about time.

Okay….in reality we’ll all be using filenames still for a while, but you can take a step towards the future by equipping yourself with the best currently available search tools and don’t worry so much about the organization of your folders. Spend time instead making sure that your stuff has the appropriate metadata. Where you stick the metadata doesn’t matter so much so long as it’s an integral part of the object.

Many threads of development are pushing us towards the end of filenames. Here are some:

·        X1 Desktop Search the best currently available search engine for files, contacts, e-mail, pictures and music on your PC.

·        Google Desktop Search the best free currently available search engine for files, contacts, e-mail, pictures and music on your PC.

·        Apple’s Tiger OS Spotlight excellent search engine for files, contacts, e-mail, pictures and music on your Mac.

·        Outlook Search Folders are a full replacement for organizing mail into separate folders.

·        GMail’s Labels are not quite powerful enough to really manage 2GB of e-mail, but expect them to improve as people use more of their capacity.

·        Yahoo’s Flickr enables distributed metadata management of your picture collection.

Links relating to the theme:

‘Tags’ Ease Sifting of Digital Data

 

DataGridView Validation

Windows Forms 2.0 has a new general purpose data display control called a DataGridView. It is intended to be easier to use and more powerful than the original DataGrid control.

The following experience may help you when it comes to adding data validation logic to a rather simple application of the DataGridView control.

An obvious (but WRONG) place to start is the CellValidating event of the DataGridView object. Here is a fairly reusable implementation of a CellValidating event delegate method:

 

    this.grid.CellValidating += new DataGridViewCellValidatingEventHandler(grid_CellValidating);

 

    void grid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {

        DataGridViewCell cell = grid.Rows[e.RowIndex].Cells[e.ColumnIndex];

        TypeConverter tc = TypeDescriptor.GetConverter(cell.ValueType);

        try {

            object newValue = tc.ConvertFrom(e.FormattedValue);

            object oldValue = cell.Value;

            try {

                cell.Value = newValue;

            } finally {

                cell.Value = oldValue;

            }

        } catch (Exception ex) {

            grid.Rows[e.RowIndex].ErrorText = ex.Message;

            SystemSounds.Beep.Play();

            e.Cancel = true;

        }

    }

 

There are a few general things to point out about this method:

·        It uses a TypeConverter to determine if the new value (e.FormattedValue) can be converted to the type of value stored in the cell. Using a TypeConverter is a good general approach because FormattedValue isn’t always a string. It can, in theory, be just about any type.

·        It provisionally assigns the new value to the cell’s value to trigger any argument checking done by the underlying DataSource’s property setter. If there is a value range restriction on the data, you should be checking it at the first public interface level, not in some form specific UI code.

·        A finally block is used to restore the current value of the cell after the provisional assignment. There are several things not to like about this technique. The setter can have side effects (not good coding practice, but it happens). The setter can be resource intensive.

·        Validation errors result in exceptions being thrown. The exception’s message is set as the grid row’s ErrorText property and a beep sound is generated. The ErrorText property will cause a small error notification icon to appear in the row header with a tool tip set to the exception’s message.

·        The Validating event doesn’t happen when a value is simply assigned to a grid cell. For example if your paste-from-clipboard method attempts to assign the contents of the clipboard to a grid cell, you’ll have to implement separate validation logic there and validation failure notification logic.

When you use the ErrorText property, don’t forget to reset it after the problem has been fixed. The simplest way to do this is with the Validated event:

    this.grid.CellValidated += new DataGridViewCellEventHandler(grid_CellValidated);

 

    void grid_CellValidated(object sender, DataGridViewCellEventArgs e) {

        grid.Rows[e.RowIndex].ErrorText = String.Empty;

    }

 

The RIGHT place to put your validation logic is in the DataSource’s property setters, throw an ArgumentValueException for bad values, and use the DataError event instead of the CellValidating event to handle the exceptions:

    this.grid.DataError += new DataGridViewDataErrorEventHandler(grid_DataError);

 

    DateTime lastDataError = DateTime.MinValue;

    void grid_DataError(object sender, DataGridViewDataErrorEventArgs e) {

        e.Cancel = true;

        e.ThrowException = false;

 

        // A single error may cause secondary calls to this handler, ignore these.

        if (grid.Rows[e.RowIndex].ErrorText != String.Empty && null == e.Exception) return;

 

        TimeSpan sinceLast = DateTime.Now - lastDataError;

        lastDataError = DateTime.Now;

 

        string message;

        if (null == e.Exception)

            message = "Bad value.";

        else {

            message = e.Exception.Message;

            if (e.Exception is System.Reflection.TargetInvocationException)

                if (e.Exception.InnerException is FormatException)

                    message = "Bad value format. Check the type of value entered.";

        }

        grid.Rows[e.RowIndex].ErrorText = message;

        if (sinceLast.TotalSeconds < 1.0)

            MessageBox.Show(message + "\r\n\r\nPress Ctrl-Z to restore previous value.", "Bad Value");

        else

            SystemSounds.Beep.Play();

    }

 

The DataError event has a richer (more complicated) calling context than the CellValidating event, but this is a good thing. It allows you to be consistent and focused about your error handling and notification.

A few comments about the grid_DataError method:

·        The e.Context field of the event arguments is a DataGridViewDataErrorContext, which is a flags style enumerator that tells you the general context of the data error. You may want to specialize your handling based on the context in production situations.

·        In addition to the Cancel property there is a ThrowException property. Generally you can set these to true and false respectively because you’re going to handle the problem and take care of notifying the user.

·        A single error may cause a secondary call to the handler. This is the kind of thing that may get fixed by the time 2.0 goes into production. For now, ignore the second call by noticing that the exception property is null and an error message has already been set.

·        Many exception messages are fairly cryptic from an ordinary user’s perspective. Do whatever massaging is necessary for your application.

·        In addition to setting the ErrorText property for a small visual indicator of an error condition, either play a beep sound or, if this error followed the last by less than a second, put up a dialog to display the message directly and require the user to acknowledge it.

Hope this helps you…

 

 

 

May 02, 2005

Photography, Picasa, Managing Photographs Remains Hard

Picasa 2, free photo management software distributed by Google, is a wonderfully done application which delivers a number of really new features and yet it still is struggling to really win in the category.

Among the not-seen-before features are the following:

·        Managed images can be “edited” without altering the original picture. To commit the changes, you have to save a copy.

·        Integration with Hello (also offered by Google) allows peer-to-peer distribution of pictures and allows the recipient to choose their own resolution preferences.
The idea is to avoid e-mail reduced copies of pictures from friends and family. With Hello, you can choose which what resolution to receive. Brilliant.

·        When you rotate a picture, it really rotates. Just one of the many things to like about a really clean, fast interface.

 

The adoption thwarting issues remaining with Picasa include the following:

·        The whole notion of combining the distribution of sets of photographs with chat sessions almost works. The key thing missing is that the only way to distribute photos is through the initiation of a chat session to a single destination. This means if I have some new pictures of the children, I potentially need to initiate many individual transfers to pump them all out to friends and family. What’s really needed is to have each of these connections establish a persistent link between folders on distributed PCs. Any pictures I drop in my “friends and family” folder should automatically get pumped out to anyone I’ve ever connected to the folder as soon as their PCs are online. It should be a recipient preference whether new pictures from a particular contact are automatically retrieved at full resolution or left as thumbnails. Some configurable notification options should exist on arrival of new images.

·        A second hard problem which needs to be solved is how to manage distributed storage of a pool of shared pictures. A little redundancy is required for safety, availability and performance. Full replication isn’t practical or desirable.

·        The short story is that with its current feature set, Picasa is a sexy photo editing tool but Hello is not a practical means for sharing pictures with friends and family. Unless you don’t have more than one or two of either…

Minor nits:

·        There’s no simple way to quickly rename all the pictures in a folder.
There is a batch rename tool, but it has no real flexibility. You can rename all the selected pictures using the same name with options of including the date taken and the original resolution. There’s no control over the format of the date and time. You can easily “label” a picture. But labels end up in the Picasa private metadata, stored in an INI file. If you rename the picture, do you break the link to the metadata you provided?

·        There’s no way of fixing EXIF dates if the camera’s clock was set wrong when the pictures were taken.
As an aside here. Until the EXIF format starts including a time zone along with the date and time, the only sensible thing you can set your camera’s clock to is UTC. Take a vacation spanning several time zones and see how confusing it is to combine pictures taken with different cameras into a single chronological sequence.

·        There’s a “Save copy…” command which almost commits the picture edits back to the original files. But not quite. Picture rotation doesn’t get written out. Other kinds of edits do result in a new image being written that incorporates the changes.

·        It doesn’t abide by the date and time formats configured in Windows. Actually it does. It’s just in the Rename dialog that it displays a static format instead of the one actually used. Unfortunately (for me) is uses the same separator between date parts and time parts.

·        Google’s Picasa newsgroup is heavily spammed.

 

The reason this last one is so hard to get right is that some picture editing operations, like rotating a jpeg by 90 degrees, are inherently damaging to the quality of the image. Since printing a picture can easily take care of the 90 degree rotation, there’s no reason to rotate the image. Just pick landscape instead of portrait print mode. If you intend to do anything on-line with the picture though, you’ll almost definitely have to rotate it to put it up.

 

 

May 01, 2005

Configuring a LinkSys WRT54G as a Wireless Ethernet Bridge

I found myself wanting a wireless Ethernet bridge to simplify locating an Axis 2100 video camera. I had an existing LinkSys WRT51ab in the area, so I went looking for an 802.11b bridge device.

The first thing I tried was the LinkSys WGA54G Wireless-G Game Adapter ($100) which it turned out was definitely NOT a bridge device, despite the assurances of Best Buy sales staff.

It turns out that there’s an active community hacking the WRT54G 802.11gb wireless broadband/router. LinkSys released source code for the firmware some time ago under GPL license which has been enhanced in many ways; one of which is to enable wireless Ethernet bridging. Since the WRT54G can currently be had for $40 after $30 of rebates from Best Buy, it’s also a much cheaper solution using much more flexible (though somewhat larger) hardware.

Having saved $60 on hardware, I didn’t feel too bad subscribing to http://www.sveasoft.com for $20 for one year of code access, but have so far not gotten any value from their software, more below on why not…

The instructions below are from here and worked like a charm. Some notes:

1.      Tried sveasoft’s TalismanBasic_V1.0.1_wrt54gv3.bin first. It wouldn’t let me change its configuration (possibly a MAC address typo before the download) and the forums indicated that client mode support doesn’t work due to a known bug (so it should be fixed soon…).

2.      The need to telnet to it after every power failure to enter the “echo 1 > /proc/sys/net/ipv4/conf/eth1/proxy_arp” is a drag and the main reason to hope for a sveasoft fix.

3.      sveasoft’s in a fight with the GPL crowd over their modifications to the “Alchemy” firmware code which came from a GPL release by LinkSys.

4.      The LinkSys wrt51ab is a bit unreliable and has no available firmware upgrades. I don’t recommend it for new installations. It has to be rebooted frequently to connect to its configuration web. The 801.11a activity light is blinking furiously even though there’s nobody there (I hope).

Topic Title HOWTO: Use Linksys WRT54G as a wireless ethernet bridge

Date Posted: 02/07/2005 02:00 PM Posted By: user1234(Platinum Member)

This howto is intended to help people who currently use a wireless router in their house, and also have additional PCs or devices without wifi cards which cannot be connected to the wireless router using a cable because they're too far from it (like in another room).

This howto will explain how to use the wrt54g a to connect these remote PCs to the internet and your home network, without using wifi cards. This is possible using 3rd party firmware (sveasoft) which allows the wrt54g to operate in "client" mode, where it forwards packets from its connected devices to the main wireless router, using a wireless link.

I got my wrt54g running in client mode - that is, it serves as a bridge between a PC attached to it and the main wireless router. Here's my complete setup, starting with the wired connections (markeded by "<===>"):

Room 1: Cable Modem <===> D-Link DI-624 Wireless Router <===> PC-1
Room 2: WRT54G <===> PC-2

The DI-624 and the WRT54G connect to each other wirelessly. I also have a mobile laptop which connects wirelessly to the DI-624.
So in this case, the WRT54G let me use PC-2 without having a wifi card in that PC. In fact, I could connect up to 4 PCs to the wrt54g, and save the price of 4 wifi-54g pci cards, plus I don't have to install drivers for wifi cards (a pain in Linux). The wrt54g acts like a "wireless ethernet bridge", which in fact is another product sold by linksys (WET54G) for around $150. This is also useful when you have devices (in a room which doesn't have ethernet connections) which can only connect using a ethernet cable, but cannot connect wirelessly - like XBOX !

So how do you do it ? Here's the list of steps - you should be doing these steps (except step 1) from a PC attached to the wrt54g (e.g. PC-2 in my setup). Physically attaching a PC to the wrt54g is required only for this initial set up phase, because we need to login and set up the various options. Note that this doesn't require any changes to your main router's configuration, so it's quite safe with regard to not messing up your current networks' setup.

1. Download the "wrt54g alchemy firmware" (google this, or go here) version 6rc5 from the internet (it is the only one compatible with the new models wrt54g V2.2 & wrt54gs V1.1).
2. Upload the firmware to the wrt54g via the "Administration->Firmware Upgrade" option in the router's web interface.
3. Reset the device (press reset button until power led flashes - this could take 20 seconds or more). In the following steps, leave all settings which are not mentioned in the description at their default (only change the ones specifically mentioned in the step).

Note: We will use addresses that end in 128-255 for the wrt54g router and it's attached PCs. To make sure there is no overlap in the addresses assigned by the two routers, we have to make sure that your main router doesn't assign addresses to its own clients in that range. For example, if your main router address is 192.168.0.1, its DHCP address range could be 192.168.0.50 - 192.168.0.120.

4a. In "Setup::Basic setup" screen, set Internet Connection Type to "Auotomatic Configuration - DHCP".
4b. Set the local IP to 192.168.0.129, assuming your main router is 192.168.0.x (in general, if your main router is a.b.c.d set the wrt54g to a.b.c.129).
4c. Set the Subnet Mask to 255.255.255.128.
4d. Set the "Gateway" to the IP address of your main router (e.g. 192.168.0.1).
4e. Set the DHCP Server to Enabled, and starting IP Address to something above 129 (e.g. 140).
4f. Save the settings on this page. You may need to reboot the attached PC, since the subnet mask has changed.

5. In "Setup::Advanced Routing" screen, make sure operating mode is "Gateway".

6. In "Wireless::Basic Settings" screen, set Wireless mode to "Client", wireless network mode to "mixed", and SSID to your main wireless router's SSID.

7. In "Wireless::Security" screen, set yor WEP/WPA settings which match the main wireless router. You should now be connected to the main wireless router. Note: if you have MAC filtering set up on the main router (which allows only specific clients to connect), then obviously you have to add the client router to the list of allowed clients.
To verify that you've established a connection to the main router, you can check the "Status::Router" screen, which should show an IP Address assigned by the main router (which would end with a number below 128), and the "Status::Wireless" page should show the AP Signal strength together with the mac address of the main router. Also you should now be able to ping the main router and even log in to it (using h ttp://192.168.0.1) from the PC attached to the client router (the wrt54g).

8. In "Security::Firewall" screen, disable firewall protection, as this subnet is already behind your main router's firewall. Also make sure that "Block Anonymous Internet Requests" is unchecked.

9. In "Administration::Management" screen, you can leave all settings at their default. You may want to enable remote management and Telnet or SSHD, especially if you want to be able to log in to the wrt54g from a computer which is not directly attached to it.

10. To enable PCs attached to the main router to be able connect to PCs attached to the wrt54g: Login into the wrt54g using telnel or ssh by running the command "telnet 192.168.0.129", login as “root” and the same password as for the web interface. Then type this command:

# echo 1 > /proc/sys/net/ipv4/conf/eth1/proxy_arp

The following command confirms the current contents of the proxy_arp file, “0” on power up, “1” after the command above:

# cat /proc/sys/net/ipv4/conf/eth1/proxy_arp

Now you should be able to ping/telnet to any PC attached to the wrt54g from any PC attached to the main router. Btw, this assumes that the subnet mask of the main router is the default 255.255.255.0.

Important note about the last step : The last step (which is an optional step) allows PCs attached to the main router to be able to connect to PCs attached to the client router, by specifying the IP of the destination PC, for example "telnet 192.168.0.150". But they are still on two different subnets which do not share their broadcast messages, therefore when browsing PCs on the local network you will not automatically see the PCs attached to the other router. But you can always connect to them by explicitly specifying the IP. Btw, this step was added after the initial posting of this HOWTO and solves a lot of the issues people discussed later in this thread, so don't worry if you read posts in this thread about problems with communicating between PCs attached to different routers. Also note that this proxy_arp setting is not saved in the WRT54G non-volatile memory like all the other settings, so when the router is rebooted (like after a power outage), it will be cleared and you will need to repeat step 10 to set the proxy_arp back on.

Done !!! That's it !!!!

So in summary, you don't need two wrt54g routers, nor do you need WDS capable routers. A single wrt54g (with the right firmware) can operate as a "client" of any other wireless router, and create a bridge so any device connected to it will be able to access your network and the internet. The above works great for me, even with 3-4 PCs attached to the wrt54g (verified that it works).