Monday, November 28, 2011

iPhone | Convert UILabel to Circle

This is how you can convert a UILabel to circle:

steps:
1)Add Quartz Core framework to application frameworks

2) Import QuartzCore.h file to implementation file.

3) #define kRectArmLength 24.0 (Not necessary, as you can decide while initializing label with frame)

//Label will be a square (equal width & height)

UILabel *lblCircle = [[UILabel alloc] initWithFrame:CGRectMake(10,20, kRectArmLength, kRectArmLength)];

//set corner radius just half of the square arm length

lblCircle.layer.cornerRadius= kRectArmLength/2;

lblCircle.clipsToBounds=YES;

lblCircle.backgroundColor = [UIColor redColor];

[self.view adsSubview: lblCircle];

Wednesday, November 16, 2011

Phonegap | Whitelist rejection in phonegap compilation with Xcode

While having an other domain server based service. Our phonegap application failed with ERROR logs :
whitelist rejection in phonegap compilation
The solution is to Whitelist (allow) the host to be accessible via phonegap, to accomplish it
In Phonegap.plist file,
Add new row to External Host (Key value pair)
for value, put your host name : (SERVER.COM).
e.g.
1) ERROR whitelist rejection: url('http://localhost:XXXX/myproject/index')
Type: localhost in value column for for External Host
2) ERROR whitelist rejection: url('http://myserver.com/dashboard/mobilews.php?')
Type: myserver in value column for External Host


May be putting "*" , the asterisk as a value of the host that references an external URL , will do the trick. but not safe.
hope this helps, It works great for us :)

see my comments below for more info, as phonegap is cordova now!

Saturday, November 5, 2011

iPhone build error | Codesign failed with exit code 1| object file format invalid or unsuitable

Recently, I have installed Xcode 4.x, this have shown weird errors with existing app , and asked for a lot of change to make it compatible with new complier.
Project timelines are always important, So I reverted back to Xcode 3.2.6

Everything went Okay. But when I tried to apply ( code signing) provisioning certificates to install application into iPhone, Build Failed with error;
Command /usr/bin/codesign failed with exit code 1
with description-
{*}.app object file format invalid or unsuitable


Then I moved to the solution library of developers (stack overflow), As most of the the developers do :)
After spending lot of hours, Saw this answer by emcmanus.

sudo mv /usr/bin/codesign_allocate /usr/bin/codesign_allocate_old
sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate /usr/bin


Tried first command, Blindly..
My terminal CLI answered : No such file or directory!

Then, I Explored /usr/bin folder, and observed yes! It was not there. (there is nothing to keep as back up , after renaming it. Symlinking is the ultimate goal )
I run "sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate /usr/bin"
to create symlink.
and YES! symlink did the trick...


Excellent... Hope this will do the trick for, who is in this trap :)

Thursday, October 20, 2011

iPhone | code crash : Mutated Collection during fast enumeration

If you are going to use , fast enumeration in your objective C code?
for (id {object} in {collection}) {...}" )

You shall not be able to modify the collection (add or remove) during enumeration.
Because, thread will have a lock on the resources being used.

for that either go with the :

1) for(NSUInteger i=0 ; i< [ {collection} length];i++){…}
2) Put the add/remove logic in another thread

Hope this helps!

Saturday, October 15, 2011

Shipment Tracker - Package tracking app for US

Shipment Tracker is live on app store :)
Developed this application for Appcandy productions.

http://itunes.apple.com/us/app/shipment-tracker/id471306380?mt=8

Cheers!

iPhone | UIImage

I was reading a blog article "How to use optimized Image in iPhone Development?",

That article suggests, it is best to use “imageWithContentsOfFile” over [UImage imageNamed:@"YOUR_IMAGE_NAME"]; because image name will not flush image out of memory even if it is set to nil.

Correct! it will not flush, But its good to keep that image in cache, Most of the time, application user moves to-and-fro in app ,
So its not a good idea to get it always from main bundle and get it converted everytime!

Sharing the good part of UIImage:

As per apple developer reference guide for UIImage imageNamed method:

+ (UIImage *)imageNamed:(NSString *)name

name
The name of the file. If this is the first time the image is being loaded, the method looks for an image with the specified name in the application’s main bundle.
If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.

Return Value
The image object for the specified file, or nil if the method could not find the specified image.

On a device running iOS 4 or later, the behavior is identical if the device’s screen has a scale of 1.0. If the screen has a scale of 2.0, this method first searches for an image file with the same filename with an @2x suffix appended to it. For example, if the file’s name is button, it first searches for button@2x. If it finds a 2x, it loads that image and sets the scale property of the returned UIImage object to 2.0. Otherwise, it loads the unmodified filename and sets the scale property to 1.0.
Special Considerations
On iOS 4 and later, if the file is in PNG format, it is not necessary to specify the .PNG filename extension. Prior to iOS 4, you must specify the filename extension.

Thursday, October 13, 2011

iPhone | Customize the UITableView header and footer view

To Customize the table header and footer view , Just go fo it....


CGRect newFrame = CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, self.myHeaderView.frame.size.height);
self.myHeaderView.backgroundColor = [UIColor clearColor];
self.myHeaderView.frame = newFrame;
self.tableView.tableHeaderView = self.myHeaderView; // note this will override UITableView's 'sectionHeaderHeight' property

// set up the table's footer view based on our UIView 'myFooterView' outlet
newFrame = CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, self.myFooterView.frame.size.height);
self.myFooterView.backgroundColor = [UIColor clearColor];
self.myFooterView.frame = newFrame;
self.tableView.tableFooterView = self.myFooterView; // note this will override UITableView's 'sectionFooterHeight' property

Thursday, August 25, 2011

isNumeric javascript

There is no predefined function to test ,if a value is numeric .
This function helps to check whether a variable's value is numeric or not.


var isNumeric = function(x) {
// returns true if x is numeric and false if it is not.
var RegExp = /^(-)?(\d*)(\.?)(\d*)$/;
return String(x).match(RegExp);
}


Hope this helps!

Thursday, August 18, 2011

PHP date bug | date ends at 2037

While developing an application having backend in PHP ,when I tried to go past the year 2037 the system jumped back to 1970!
This is a known bug in PHP and is a limitation in counter that is 32 bits long,64bit machines are not vulnerable to this.

http://bugs.php.net/bug.php?id=7103

As per forum

The last date/time that is working:
19.01.2038 03:14:07 ( =2147480047 )

The workaround for this issue is to have 64 bit machine/OS, if you are running any unix based machines. Also make sure that the time_t is set to 64bit !

Hope this helps... and save your time.

Sunday, July 31, 2011

Restart Apache in MAC OS X

Apache webserver service can be restarted using the following command in a Mac OS X Terminal window:

sudo /usr/sbin/apachectl restart

Today, when I used this command to restart apache , from terminal after making some changes in php.ini file. it resulted in an error:

+ apachectl: /usr/sbin/apachectl: line 82: ulimit: open files: cannot modify limit: Invalid argument

Then I looked into line 82 of apachectl, the shell script was referring to the ULIMIT_MAX_FILES variable, which was set to:

ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"

Changing the line as follows fixed the problem:

ULIMIT_MAX_FILES=""


My MAC OS X version is 10.6.5.
Hope this helps!

Friday, July 29, 2011

Drupal reset super user (admin) password

To reset Admin password in Drupal7 , there is a drupal hash script to generate a password hash from plain text.

To set new password for user 'admin' to 'mynewpass', then first in the drupal root directory, run the script:
$ ./scripts/password-hash.sh 'mynewpass'

Then it will echo something like this:

password: mynewpass        hash: $S$CGM3hk.Fvl/pQlirfJmIQiXMOdifVR.wPoyT9e81ktxAStq7pmGK

then use following SQL to update the password:

UPDATE users SET pass='$S$CGM3hk.Fvl/pQlirfJmIQiXMOdifVR.wPoyT9e81ktxAStq7pmGK' where uid=1;
//Drupal use uid=1 for super user (Site administrator)
For drupal6 , output of md5('mynewpass') will work.

Hope this helps!

Saturday, July 16, 2011

Structs vs Classes C# and C++

Someone may argue:
in C++ Structs are largely redundant Why C# still have them & not discarded it like multiple inheritance ?

Here is the answer :

In C++, a struct and a class are pretty much the same thing.
The only difference is the default visibility level (public for structs, private for classes).

However, in C# structs and classes are different.
1) In C#, structs are value types (instances stored directly on the stack, or inline within heap-based objects), whereas classes are reference types (instances stored on the heap).Classes are accessed indirectly using reference.
2) Structs can implement interfaces but cannot inherit from structs or classes, .
3) Structs cannot have destructors.

we can say ......
A C# struct is much more like a C struct than a C++ struct.

Hope it make this concept pretty clear!

Thursday, July 7, 2011

get last inserted id from database table in Java, .NET , PHP

When we tried to retrieve a new record ID immediately after insertion,We did face bit trouble in getting that.

Different languages have different syntax/process of doing this.

Here is, How did I manage to get this done, in required projects:
For Java & PHP , we are using MySql dtabase, while in .NET we have used SQL server.

Java



//DBHelper , written for Database handling
DBHelper dbHelper = new DBHelper();
       Connection con = null;
       
String querySave = "";

       querySave = "INSERT INTO `DATABASE_NAME`.`TABLE_NAME` (`FIELD`) VALUES ( '"
               + VALUE_TO_BE_INSERTED + "');";
       Statement stmt = null;
       ResultSet rs = null;
       try {
//con is connection to database
           this.con = dbHelper.openDB(); //Here dbHelper is an instance of class,
           stmt = con.createStatement();
           int insertedRow = stmt.executeUpdate(querySave,
                   Statement.RETURN_GENERATED_KEYS);
           rs = stmt.getGeneratedKeys();
           int key = 0;
           if (rs.next()) {
               // Retrieve the auto generated key(s).
               key = rs.getInt(1);
               System.out.println("last inserted key is : " + key);

           }
catch (SQLException e) {
           e.printStackTrace();
       }
finally {
           dbHelper.closeDB();
           if (stmt != null) {
               stmt.close();
               stmt = null;
           }
           if (rs != null) {
               rs = null;
           }
           if (this.con != null) {
               this.con = null;
           }
       }


.NET



//dbManager - an object of one of the class from DATA Access Layer
  string sql = "INSERT INTO tgc_user_profile(firstName,emailId, password) VALUES(@firstName,@emailId,@password);" + "SELECT uid FROM tgc_user_profile WHERE uid = @@IDENTITY";

           try
           {
               dbManager.OpenConnection();

               dbManager.AddParameter("@firstName", name);
               dbManager.AddParameter("@emailId", email);
               dbManager.AddParameter("@password", password);

                ID = (int)dbManager.ExecuteScalar(sql, CommandType.Text);
               
       
           }

           catch (Exception ex)
           {
             
           }

           finally
           {
               dbManager.CloseConnection();
           }


PHP




$fName=mysql_real_escape_string($fName);
$email=mysql_real_escape_string($email);
$password=mysql_real_escape_string($password);
//mysql_real_escape_string to avoid sql injection attacks ,as we are using dynamic SQL query
$query_save = "INSERT INTO tgc_user_profile(firstName,emailId, password)
               VALUES ('".$fName."', '" .$email."', '" .$password ."')";
                             
             $_result = mysql_query($query_save);
            $ID = mysql_insert_id();


Hope this helps :)

Your valuable comments are appreciated !

Monday, July 4, 2011

ADO.NET : Preventing SQL injection attacks

Use Sqlparameter data-related class to help in preventing SQL injection attacks.

We should avoid Dynamic SQL like this

string strQry = "SELECT Count(*) FROM Users WHERE UserName='" +
txtUser.Text + "' AND Password='" + txtPassword.Text + "'";

because if user enter Username name value likely ' Or 1=1 -- then it return true what ever the value we have in password.

Sunday, July 3, 2011

Detect Client Operating System using javascript

Add this javascript code snippet:

<script>

alert(window.navigator.appVersion);

</script>

Tuesday, June 28, 2011

My amazing app on App store : iFindMyWine

One of my amazing app, Which I have developed , during my association with Ebizon Netinfo.Application owner is InfiniteSky Development, LLC.

I loved to develop ,design this iPhone app and helping in writing the web service in C#.NET.. SQL server ... Enjoyed it a lot !!!!!!!

http://itunes.apple.com/us/app/ifindmywine/id441508094?mt=8


Idea & description:

At the press of a button, it will find any retail outlet that offers wine, beer or liquor in your area, no matter where you are in Canada.

Find All Store Types - iFindMyWine is not limited to finding only liquor stores or wineries. Find any type of licenced liquor store in your area.

Receive News and Updates - One of the most important and unique features of iFindMyWine is its ability to broadcast special messages issued by specialty wine stores or wineries to notify users of new arrivals, availability of a rare vintage or monthly specials and promotional offers.

Get Clear Directions - Get clear maps of the area where you are and clear step by step instructions on how to get to your destination.

Look for a different store type quickly and easily from anywhere within the application.

You can not only look for what's available in your immediate surrounding, but you can also choose to search by province or by city, anywhere in Canada.

iFindMyWine will use the GPS capabilities built into your SmartPhone and will display all stores starting with the ones that are closest to your location and going to the farthest ones.

If you have selected "Stores Near Me" from the main menu, then the list of stores will automatically indicate with a colour dot, to the left of each listing, whether each store is currently open or closed, or even whether it will be closing in the next 30 minutes.

Once you have identified which wine or liquor store meets your criteria, get the complete details including complete address and phone number, map and directions and even store business hours.

Click on the store's phone number and your SmartPhone will automatically dial the number and put you in contact with the store directly so that you can find out if they have the particular vintage that you are looking for.


That's AMAZING!!!!!!!!!

Thursday, June 2, 2011

XMLParsers : SAX & DOM Parser

XML Parsing can be broken down into two logical components: a parser and a scanner.

The scanner reads the text and classifies it as "tokens". A token is a catagory that is recognized by the parser.

e.g. a scanner for the Java programming language might return the tokens that include: identifier, integer, for (a reserved word).

Before we begin, I wanted to make sure everyone is aware of the most important difference between XML parsers: whether the parser is a SAX or a DOM parser.


SAX vs. DOM

A SAX parser is one where your code is notified as the parser walks through the XML tree, and you are responsible for keeping track of state and constructing any objects you might want to keep track of the data as the parser marches through.

A DOM parser reads the entire document and builds up an in-memory representation that you can query for different elements. Often, you can even construct XPath queries to pull out particular pieces.

An important point, relative to SAX, is that the parser calls the scanner. As the parser processes the tokens returned by the scanner it performs operations, like building a syntax tree.

In the case of SAX, the scanner (the SAXParser object) calls the parser. This makes parsing with SAX needlessly awkward and complicates the architecture of the software. For this reason, the DOMParser is frequently used for parsing complicated XML documents.

The SAXParser does have two notable advantages over the DOMParser: the SAXParser is faster and it uses less memory. While the SAXParser is difficult to use for processing complex XML documents, perhaps it is appropriate for processing simple XML documents.....

in iPhone : NSXMLParser is a SAX parser included by default with the iPhone SDK. It’s written in Objective-C and is quite straightforward to use, but perhaps not quite as easy as the DOM model.

Tuesday, May 17, 2011

Installing Ruby, Rubygems, Rails on Mac OS X 10.5 (Leopard)

let’s get started. Unlike previous versions of Mac OS X, Leopard has everything you’ll need to compile Ruby. You don’t need to install any anything else. Take these commands and type or paste them into Terminal:


Paths
Don’t skip this step!

The path is actually an environment variable, set by a special file that’s automatically executed when you open a new Terminal window.

We need to make sure that our path is set to look for files in /usr/local (the place where we’ll be installing the tools) before looking anywhere else. This is important.

To see if the path has been set properly, we can check the contents of the .profile file (the special file hidden in our home folder) for a PATH line using a text editor(I am using TextWrangler ...).

edit ~/.profile
This will open the file if it already exists, or open a blank file if it doesn’t. Add the following line at the very end of the file:

export PATH="/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH"
Now save and close the file.

It doesn’t matter how many other lines there are in the file, or what they say or do. Just make sure that this line comes last and you should be fine.

To make sure the changes are picked up correctly, we now need to execute the file with the following command:

. ~/.profile
It’s likely there will be no response from the shell here, just the prompt, but that’s OK, the changes have been picked up and we’re ready to move on.

You can also close your Terminal and open a new one instead if you’d like.

Now :
Go to root and move to path
/usr/local/bin

Download

We’re going to create a folder to contain the files we’re about to download and compile. If you want, you can delete this folder when you’re done, but keeping it around makes it easier to re-install (or uninstall) these apps later.

Make the new folder:

mkdir ~/src cd ~/src

Download Ruby and Rubygems:

curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p174.tar.gz curl -O http://files.rubyforge.vm.bytemark.co.uk/rubygems/rubygems-1.3.5.tgz

Compile and Install

First, Ruby:

tar xzvf ruby-1.8.7-p174.tar.gz cd ruby-1.8.7-p174 ./configure --enable-shared --enable-pthread CFLAGS=-D_XOPEN_SOURCE=1 make sudo make install cd ..

To verify that Ruby is installed and in your path, just type:

which ruby

You should see:

/usr/local/bin/ruby

If you do, this means you now have a super-fast, 64-bit version of Ruby ready to go. If you saw something different, you haven’t set your path correctly. Go back and try again.

Compile and install RubyGems:

tar xzvf rubygems-1.3.5.tgz cd rubygems-1.3.5 sudo /usr/local/bin/ruby setup.rb cd ..

Install Rails:

sudo gem install rails

sudo gem install rails

To start with, gem might complain that bundler requires a higher version. Something like this might happen, when you run “sudo gem install rails”:

ERROR:  Error installing bundler:
bundler requires RubyGems version >= 1.3.6
ERROR: Error installing bundler: bundler requires RubyGems version >= 1.3.6


If you run into that, you need to ask gem to update itself:

sudo gem update --system

Then rails’ installation should work.

If you use MySQL, you can now install the MySQL gem. You’ll need to know the location of your MySQL installation, which is typically/usr/local/mysql. Install the gem like this:

sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql

Congratulations, you now have a custom-built Ruby, RubyGems, and Rails configuration.





Sunday, March 27, 2011

apple script to delete selected line numbers from text editor

I was having a huge sql script, From which I need to extract a small portion..... Cut / Paste seems to be a tough task this time... then I tried to write a small but powerful script & YES! this worked and made this task very easy & quick.... :)

tell application "TextWrangler"
tell window 1
set a to 1
set b to 4330
select (lines a through b)
delete the selection
end tell
end tell

Wednesday, February 23, 2011

iPhone : Resizing image and maintain aspect ratio

Issue : While scaling an image to fit to an image view [CGRect ....],Image was distorting.
Reason: Image stretches/compress itself to fit to specified area and usually get distorted.
So in order to maintain the actual aspect ratio of the image We can use this:

In Header file, Declare a method:

-(UIImage *)resizeImage:(UIImage *)image withWidth:(int) width withHeight:(int) height;

In (implementation).m file :
We need to define radians macro,this will be used in function definition declared above.

static inline double radians (double degrees) {return degrees * M_PI/180;}

Function definition:

-(UIImage *)resizeImage:(UIImage *)image withWidth:(int) width withHeight:(int) height {

CGImageRef imageRef = [image CGImage];
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
CGColorSpaceRef colorSpaceInfo = CGColorSpaceCreateDeviceRGB();

if (alphaInfo == kCGImageAlphaNone)
alphaInfo = kCGImageAlphaNoneSkipLast;

CGContextRef bitmap;

if (image.imageOrientation == UIImageOrientationUp | image.imageOrientation == UIImageOrientationDown) {
bitmap = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, alphaInfo);

} else {
bitmap = CGBitmapContextCreate(NULL, height, width, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, alphaInfo);

}

if (image.imageOrientation == UIImageOrientationLeft) {
NSLog(@"image orientation left");
CGContextRotateCTM (bitmap, radians(90));
CGContextTranslateCTM (bitmap, 0, -height);

} else if (image.imageOrientation == UIImageOrientationRight) {
NSLog(@"image orientation right");
CGContextRotateCTM (bitmap, radians(-90));
CGContextTranslateCTM (bitmap, -width, 0);

} else if (image.imageOrientation == UIImageOrientationUp) {
NSLog(@"image orientation up");

} else if (image.imageOrientation == UIImageOrientationDown) {
NSLog(@"image orientation down");
CGContextTranslateCTM (bitmap, width,height);
CGContextRotateCTM (bitmap, radians(-180.));

}

CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage *result = [UIImage imageWithCGImage:ref];

CGContextRelease(bitmap);
CGImageRelease(ref);

return result;
}

Tuesday, February 15, 2011

iPhone : Add vibration to your iPhone App code

Add the folowing framework :
AudioToolbox.framework

Import:
#import <AudioToolbox/AudioServices.h>

Now use this line of code to make iPhone vibrate:
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

Monday, February 7, 2011

textFieldShouldBeginEditing called twice in iOS4

UITextField textFieldShouldBeginEditing called twice in iOS4
When you tap UITextField, you get two textFieldShouldBeginEditing calls. This looks like a bug in initial iOS4 release.

Saturday, January 29, 2011

iPhone : Trimming space ,tabs ,newline from NSString

This will remove white space from both ends of a string:

NSString *newString = [oldString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];

The whitespaceCharacterSet consists of spaces and tabs.

If you want to also remove newlines from the string, use the whitespaceAndNewlineCharacterSet:

NSString *newString = [oldString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];

Friday, January 28, 2011

how to set the title as left alignment in the UIButton in iPhone ?

Set the contentHorizontalAlignment:

btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

You might also want to adjust the content left inset otherwise the
text will touch the left border:

btn.contentEdgeInsets = UIEdgeInsetsMake(0, 2, 0, 0);

URL , URI & URN

A URI identifies a resource either by location or name. More often than not, most of us use URIs that defines a location to a resource. However, a URI does not have to specify the location of a specific representation.
For Example: URI for home image, http://www.cs.org/Icons/home. Note the absence of a file extension. The URI for the home image is still universally unique, but it does not specify the specific representation of the image (either a GIF, PNG, or JPG). The selection of the representation can be determined by the web server through HTTP content negotiation.

A URL is a URI but a URI is not a URL. Schemes in the URL (locator) and URN (name) categories form subsets of URI, and also (generally) disjoint sets.

A URL is a specialization of URI that defines the network location of a specific representation for a given resource. Taking the same example, there are actually 2 representations available for the home resource:

http://www.cs.org/Icons/home.gif
http://www.cs.org/Icons/home.png

These URIs also define the file extension that indicates what content type is available at the URL.

A Uniform Resource Name (URN) is a Uniform Resource Identifier (URI) that uses the urn scheme, and does not imply availability of the identified resource. Both URNs (names) and URLs (locators) are URIs, and a particular URI may be a name and a locator at the same time.
'URN' ::= "urn:" 'NID' ":" 'NSS'
where is the Namespace Identifier, and is the Namespace Specific String. Phrases enclosed in quotes are REQUIRED. The leading "urn:" sequence is case-insensitive. The Namespace ID determines the syntactic interpretation of the Namespace Specific String.
e.g. : urn:issn:0167-6423
The URN for the "Science of Computer Programming" journal, identified by its serial number.

A Uniform Resource Name (URN) functions like a person's name, while a Uniform Resource Locator (URL) resembles that person's street address. In other words: the URN defines an item's identity, while the URL provides a method for finding it.