Monday, September 14, 2009

Simple xslt example

In this post i'll show how 2 make a simple xsl transform.
In addition i'll show how to use this xsl elements:

1. XsltArgumentList - pass arguments to the xslt
2. Encoding - declare the outgoing xml encoding
3. xsl:value-of - take the value(inner text) of node
4. xsl:copy-of - copy the inner xml of node
5. xsl:for-each - loop through same nodes
6. xsl:sort - sort nodes by specified node

and in the end of the post there is a c# thread safety class to make xsl transforms

so, this is the origin xml file(Person.xml):

<hPerson>
<Header>

<FirstName>Yosi</FirstName>
<LastName>Havia</LastName>
<Age>30</Age>
<Education>BA</Education>
</Header>
<hChildren>
<hChild>
<hName>Carol</hName>
<hAge>13</hAge>
</hChild>
<hChild>
<hName>Angela</hName>
<hAge>15</hAge>
</hChild>
<hChild>
<hName>Benjamin</hName>
<hAge>17</hAge>
</hChild>
</hChildren>
</hPerson>


and this is the xslt file(Person.xslt):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" omit-xml- declaration="yes"/>
<xsl:param name="Gender"></xsl:param>
<xsl:template match="/">
<Person>
<Gender>
<xsl:choose>
<xsl:when test="$Gender='1'">
Male
</xsl:when>
<xsl:otherwise>
Female
</xsl:otherwise>
</xsl:choose>
</Gender>
<xsl:copy-of select="/hPerson/Header"/>
<Data>
<Children>
<xsl:for-each select="/hPerson/hChildren/hChild">
<xsl:sort select="hName" />
<Child>
<FirstName>
<xsl:value-of select="hName"/>
</FirstName>
<Age>
<xsl:value-of select="hAge"/>
</Age>
</Child>
</xsl:for-each>
</Children>
</Data>
</Person>
</xsl:template>
</xsl:stylesheet>

the output xml look like this:

<?xml version="1.0" encoding="UTF-8"?>
<Person>
<Gender>
Male
</Gender>
<Header>
<FirstName>Yosi</FirstName>
<LastName>Havia</LastName>
<Age>30</Age>
<Education>BA</Education>
</Header>
<Data>
<Children>
<Child>
<FirstName>Angela</FirstName>
<Age>15</Age>
</Child>
<Child>
<FirstName>Benjamin</FirstName>
<Age>17</Age>
</Child>
<Child>
<FirstName>Carol</FirstName>
<Age>13</Age>
</Child>
</Children>
</Data>
</Person>

this is a thread safety c# class to make xsl transforms

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace XSLT
{
class XsltObj
{
protected static XslCompiledTransform _oXslTransform;
protected static object _oSyncXsl = new object();
public string FormatXmlWrapper(string sEncoding, XsltArgumentList
oXsltArgumentList,XmlDocument oOriginXmlDoc, string sXslPath)
{
string sRetVal = null;
if (_oXslTransform == null)
{
LoadXslWrapper(sXslPath, ref _oXslTransform, ref _oSyncXsl);
}
//@@@ make the transform
try
{
sRetVal = TransformData(sEncoding, _oXslTransform, oOriginXmlDoc,
oXsltArgumentList);
}
catch (Exception ex)
{
throw ex;
}
return sRetVal;
}
protected void LoadXslWrapper(string sXslPath,
ref XslCompiledTransform oXslTransform, ref object oSyncXsl)
{
lock (oSyncXsl)
{
if (oXslTransform == null)
{
XslCompiledTransform oTempXslTransform =
new XslCompiledTransform();
//@@@ get the xml path from configuration
LoadXsl(sXslPath, ref oTempXslTransform);
oXslTransform = oTempXslTransform;
}
}
}
protected void LoadXsl(string sXslPath, ref XslCompiledTransform
oXslCompiledTransform)
{
//@@@ load the xsl document(only once)
XmlDocument xslDocument = new XmlDocument();
XmlUrlResolver urlResolver = new XmlUrlResolver();
urlResolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
xslDocument.XmlResolver = urlResolver;
try
{
//@@@ load the xsl document
xslDocument.Load(sXslPath);
XPathNavigator oXPathNavigator = xslDocument.CreateNavigator();
oXslCompiledTransform.Load(oXPathNavigator,
XsltSettings.TrustedXslt, urlResolver);
}
catch (Exception ex)
{
throw ex;
}
}
protected string TransformData(string sEncoding, XslCompiledTransform
oXslTransform, XmlDocument xmlDocument, XsltArgumentList argumentList)
{
StringBuilder sb = new StringBuilder();
string sDeclaration;
//@@@ decide the xml declaration up to the Encoding
if (string.IsNullOrEmpty(sEncoding))
sDeclaration = "version=\"1.0\"";
else
sDeclaration = "version=\"1.0\" encoding=\"" + sEncoding + "\"";
//@@@ make the xsl Transform
using (XmlWriter output = XmlWriter.Create(sb))
{
output.WriteProcessingInstruction("xml", sDeclaration);
XPathNavigator oXPathNavigator = xmlDocument.CreateNavigator();
oXslTransform.Transform(oXPathNavigator, argumentList, output);
return sb.ToString();
}
}
}
}

to activate this object use this code:

static void Main(string[] args)
{
XsltObj oXsltObj = new XsltObj();
XsltArgumentList oXsltArgumentList = GetXsltArguments();
XmlDocument oXmlDocument = new XmlDocument();
string sXmlPath = @"Person.xml";
string sXslPath = @"Person.xslt";
oXmlDocument.Load(sXmlPath);
string sXml = oXsltObj.FormatXmlWrapper("UTF-8", oXsltArgumentList,
oXmlDocument, sXslPath);
}
protected static XsltArgumentList GetXsltArguments()
{
//@@@ create the arguments for the xsl
XsltArgumentList list = new XsltArgumentList();
list.AddParam("Gender", string.Empty, "1");
return list;
}

Wednesday, August 19, 2009

force download of remote file

Many times we want 2 enable 2 users to download files from our web site
just put this function in the Page_Load function and then the users will be enable to download remote files from any web site (note that the function parameter is a virtual path!):

private void forceDownloadRemoteFile(string sFileVirtualPath)
{
string sFileName = System.IO.Path.GetFileName(sFileVirtualPath);
WebClient oWebClient = new WebClient();
MemoryStream oMemoryStream;
try
{
byte[] bytes = oWebClient.DownloadData(sFileVirtualPath);
oMemoryStream = new MemoryStream(bytes);
}
finally
{
oWebClient.Dispose();
}
BinaryReader oBinaryReader = new BinaryReader(oMemoryStream);
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("content-disposition",
string.Format("attachment;filename={0}", sFileName));
Response.BinaryWrite(oBinaryReader.ReadBytes((int)oMemoryStream.Length));

oBinaryReader.Close();

Response.Flush();
Response.End();
}

To execute this function u can use this code:

protected void Page_Load(object sender, EventArgs e)
{
string sFileVirtualPath = @"http://localhost/TryWebSite/TextFile.txt";
forceDownloadRemoteFile(sFileVirtualPath);
}

Saturday, August 8, 2009

How to transform between object and xml in c#

Hi,
Many times we need 2 make transforms object to xml and transform xml to object.
there is a very simple way in XmlSerializer class, we just have to call serialize or Deserialize function and we can get what want. I'll explain it by example:


let's say that we have RootData class:

public class RootData
{
public HeaderElement Header;
public List SubjectsList;
}
public class HeaderElement
{
public int DataType;
}
public class Subject
{
public string SubjectName;
public int SubjectID;
public int SubjectType;
}

and we need to make transforms with this xml:

<?xml version="1.0" encoding="utf-8"?>
<RootData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Header>
<DataType>1</DataType>
</Header>
<SubjectsList>
<Subject>
<SubjectName>Name1</SubjectName>
<SubjectID>1</SubjectID>
<SubjectType>1</SubjectType>
</Subject>
<Subject>
<SubjectName>Name2</SubjectName>
<SubjectID>2</SubjectID>
<SubjectType>2</SubjectType>
</Subject>
<Subject>
<SubjectName>Name3</SubjectName>
<SubjectID>3</SubjectID>
<SubjectType>3</SubjectType>
</Subject>
</SubjectsList>
</RootData>


The function 2 make transform from object to xml is:

public string SerializeObject(Type oType, object oRootData)
{
//@@@ Create xml from the object
MemoryStream oMemoryStream = null;
XmlTextWriter oXmlTextWriter = null;
string sXml = null;
try
{
oMemoryStream = new MemoryStream();
XmlSerializer oXmlSerializer = new XmlSerializer(oType);
oXmlTextWriter = new XmlTextWriter(oMemoryStream, Encoding.UTF8);
oXmlSerializer.Serialize(oXmlTextWriter, oRootData);
oMemoryStream = (MemoryStream)oXmlTextWriter.BaseStream;
UTF8Encoding oUTF8Encoding = new UTF8Encoding();
sXml = oUTF8Encoding.GetString(oMemoryStream.ToArray());
}
catch (Exception)
{
throw;
}
finally
{
if (oMemoryStream != null)
oMemoryStream.Close();
if (oXmlTextWriter != null)
oXmlTextWriter.Close();
}
return sXml;
}

The function 2 make transform from xml to object is:

public object DeserializeObject(Type oType, string sXml)
{
//@@@ Create object from the xml
MemoryStream oMemoryStream = null;
object oRootData = null;
try
{
XmlSerializer oXmlSerializer = new XmlSerializer(oType);
UTF8Encoding oUTF8Encoding = new UTF8Encoding();
Byte[] Bytes = oUTF8Encoding.GetBytes(sXml);
oMemoryStream = new MemoryStream(Bytes);
oRootData = oXmlSerializer.Deserialize(oMemoryStream);
}
catch (Exception)
{
throw;
}
finally
{
if (oMemoryStream != null)
oMemoryStream.Close();
}
return oRootData;
}

Before u run this example, u can fill your object with this function:

public RootData CreateData()
{
RootData oRootData = new RootData();
HeaderElement oHeaderElement = new HeaderElement();
oHeaderElement.DataType = 1;
oRootData.Header = oHeaderElement;

Subject oSubject1 = new Subject();
oSubject1.SubjectID = 1;
oSubject1.SubjectName = "Name1";
oSubject1.SubjectType = 1;

Subject oSubject2 = new Subject();
oSubject2.SubjectID = 2;
oSubject2.SubjectName = "Name2";
oSubject2.SubjectType = 2;

Subject oSubject3 = new Subject();
oSubject3.SubjectID = 3;
oSubject3.SubjectName = "Name3";
oSubject3.SubjectType = 3;

List Subjects = new List();
Subjects.Add(oSubject1);
Subjects.Add(oSubject2);
Subjects.Add(oSubject3);

oRootData.SubjectsList = Subjects;
return oRootData;
}

And run this code to execute the transform:

RootData oRootData = CreateData();
string sXml = SerializeObject(typeof(RootData), oRootData);
oRootData = (RootData)DeserializeObject(typeof(RootData), sXml);


In this case when every data member trnsform 2 xml node we dont have to change or add nothing in the class, but there is a few useful attributes that we can use (just add it above the data member class):

  • [XmlElement("<Xml Node Name>")] - by default, the XmlSerializer uses the data member name as the xml node name, if u want 2 change it - use this attribute

  • [XmlElement(("<Xml Node Name>"), IsNullable = false)] - says that if the data member value is null it will not appear in the transformed xml

  • [XmlAttribute] - use it when u want that the data member output will be xml attribute and not xml node

Saturday, July 25, 2009

How to identify user's country by ip

In a 4 steps u can identify the user's country
u will discover that it is a very easy assignment

step 1:
-------
Download the txt file from here, that represent the ip ranges of each country. when u save this file change his extension to csv.

step 2:
-------
Import the csv file into your db and create table with the name [ip-to-country].

step 3:
-------
By taking the user's IP with Request.UserHostAddress convert this string to uint by this function:

public uint IPAddressToLongBackwards(string IPAddr)
{
System.Net.IPAddress oIP = System.Net.IPAddress.Parse(IPAddr);
byte[] byteIP = oIP.GetAddressBytes();

uint ip = (uint)byteIP[0] << 24;
ip += (uint)byteIP[1] << 16;
ip += (uint)byteIP[2] << 8;
ip += (uint)byteIP[3];

return ip;
}


step 4:
-------
with this ip address (as uint) go to our [ip-to-country] table and select the country by this sql query(@ip is the uint ip address):

SELECT countryCode2
from [ip-to-country]
where ipFrom <= @ip
and ipTo >= @ip

Sunday, May 24, 2009

ContainsKey problem

Hi,
In case that u have generic Dictionary with non primitive key - ContainsKey function will return u a bad answer because this function compare objects by refrence an NOT by value!
so, if u have same key values in the Dictionary and in your test object u will get negative answer.
the solution is 2 override Equals and GetHashCode functions:


//@@@ I have Dictionary with Key_Event5 object as the key
Dictionary<Key_Event5, Event5_Employment> dictEmployment;
//@@@ 4 support ContainsKey function compare by value, i'll implement Key_Event5 on this way:
public class Key_Event5
{
public int iFormID { get; set; }
public int iEmploymentCode { get; set; }
public Key_Event5(int iFormID, int iEmploymentCode)
{
this.iFormID = iFormID;
this.iEmploymentCode = iEmploymentCode;
}

public override bool Equals(object obj)
{
Key_Event5 oKey_Event5 = obj as Key_Event5;
if (oKey_Event5 == null)
return false;
//@@@ Compare by iFormID and iEmploymentCode
return Equals(iFormID, oKey_Event5.iFormID)
&& Equals(iEmploymentCode, oKey_Event5.iEmploymentCode);

}
public override int GetHashCode()
{
return iFormID.GetHashCode() ^ iEmploymentCode.GetHashCode();
}

}
//@@@ And now this line will work
dictEmployment.ContainsKey(oKey_Event5)

Simple XPath Examples

Hi,
In this post i'll show some simple(but useful) XPath Examples
let's say that i have this xml file named 'Persons.xml':


<?xml version='1.0'?>

<Persons>

<Person Height="180">

<FullName>Yosi Havia</FullName>

<Age>18</Age>

</Person>

<Person Height="177">

<FullName>Yosi Cohen</FullName>

<Age>22</Age>

</Person>

<Person Height="169">

<FullName>Itay Cohen</FullName>

<Age>32</Age>

</Person>

</Persons>


so, let's talk code lines:


//@@@ Select all the persons in 18 age
XmlNodeList oXmlNodeList =
XmlPersons.SelectNodes("/Persons/Person[Age = '" + 18 + "']");


//@@@ Select all the persons with age greater than 17
XmlNodeList oXmlNodeList =
XmlPersons.SelectNodes("/Persons/Person[Age > '" + 17 + "']");


//@@@ Select all the persons that contains Yosi in their names
XmlNodeList oXmlNodeList =
XmlPersons.SelectNodes("/Persons/Person/FullName[contains(.,'" + "Yosi" + "')]");


//@@@ Select all the persons with 180 height(attribute)
XmlNodeList oXmlNodeList =
XmlPersons.SelectNodes("/Persons/Person[@Height = '" + "180" + "']");

Saturday, May 9, 2009

How to merge 2 XmlDocuments

Hi,
In this post i'll show u how 2 merge 2 xml documents
let's say that i have 2 xml documents,

Persons.xml

<?xml version='1.0'?>

<Persons>

<Person Height="180">

<FullName>Yosi Havia</FullName>

<Age>18</Age>

</Person>

<Person Height="177">

<FullName>Yosi Cohen</FullName>

<Age>22</Age>

</Person>

<Person Height="169">

<FullName>Itay Cohen</FullName>

<Age>32</Age>

</Person>

</Persons>



and Persons2.xml

<?xml version='1.0'?>

<Persons>

<Person Height="175">

<FullName>Yosi Havia</FullName>

<Age>15</Age>

</Person>

</Persons>



What i want 2 do in this example is 2 take the node with the full name 'Yosi Havia' from Persons2.xml file and replace the original node with the same full name in Persons.xml file.
this code lines make this assigment(with help of my last post Simple XPath Examples ):

XmlDocument XmlPersons1 = new XmlDocument();
XmlPersons1.Load(@"Persons.xml");

XmlDocument XmlPersons2 = new XmlDocument();
XmlPersons2.Load(@"Persons2.xml");

XmlNode oXmlNewData = XmlPersons2.SelectSingleNode("/Persons/Person[FullName = '" + "Yosi Havia" + "']");
XmlNode targetNode = XmlPersons1.SelectSingleNode("/Persons/Person[FullName = '" + "Yosi Havia" + "']");
//@@@ Add the node from XmlPersons2.xml to XmlPersons.xml
XmlNode sourceNode = XmlPersons1.ImportNode(oXmlNewData, true);
//@@@ Replace the original node
XmlPersons1.DocumentElement.ReplaceChild(sourceNode, targetNode);

and u can c the result here:

<?xml version="1.0"?>

<Persons>

<Person Height="175">

<FullName>Yosi Havia</FullName>

<Age>15</Age>

</Person>

<Person Height="177">

<FullName>Yosi Cohen</FullName>

<Age>22</Age>

</Person>

<Person Height="169">

<FullName>Itay Cohen</FullName>

<Age>32</Age>

</Person>

</Persons>

Wednesday, May 6, 2009

Performence check in c# with Stopwatch

Hi,
System.Diagnostics has a very nice object called Stopwatch
i show here my very easy and simple example 4 making performence check:

Stopwatch oStopwatch = new Stopwatch();
oStopwatch.Start();
//@@@ Start of code to make the performence check
Thread.Sleep(3000);
//@@@ End of code to make the performence check
oStopwatch.Stop();
TimeSpan oTimeSpan = oStopwatch.Elapsed;
Console.WriteLine(oTimeSpan.ToString());


the output of this code was:

00:00:02.9994520

Friday, April 24, 2009

Don't use XmlDocument use XmlTextReader instead

Hi,
I had an assignment to read a 200 MB xml file
i dont think that XmlDocument can help me here...
so i found the XmlTextReader object that made a great job
and from this moment i always use XmlTextReader to read
xml file content, so here is my example:

lets say that i want to read this Test.xml file:


<?xml version="1.0" encoding="utf-8" ?>

<RootNode>

<Child>

<Item Att="1">A</Item>

<Item Att="2">B</Item>

</Child>

<Child>

<Item Att="3">C</Item>

<Item Att="4">D</Item>

</Child>

</RootNode>



and this function read all the attributes and content
of the Item node in the xml:


public void ReadXml()
{
int iCodepage = 862;
string sAttribute, sNodeValue;
string sFilePath = @"Test.xml";
StreamReader oFileStream = null;
XmlTextReader reader = null;
//@@@ Check if the file exists
if (!File.Exists(sFilePath))
return;

//@@@ Get the file as XmlTextReader
oFileStream =
new StreamReader(sFilePath, Encoding.GetEncoding(iCodepage));
reader = new XmlTextReader(oFileStream);

//@@@ Loop through all the file
while (reader.Read())
{
//@@@ If we in Item node
if (reader.Name.Equals("Item") &&
(reader.NodeType == XmlNodeType.Element))
{
//@@@ Get the Attribute (Att) value
reader.MoveToAttribute("Att");
sAttribute = reader.Value;
Console.WriteLine(sAttribute);
//@@@ Get the node value
reader.MoveToElement();
sNodeValue = reader.ReadInnerXml();
Console.WriteLine(sNodeValue);
}
}
}

Tuesday, April 21, 2009

The perfect c# singleton

Hi,
after several tries i got the perfect thread safety c# singleton

public class DbProxy
{
private static DbProxy _oInstance = null;
private static readonly object padlock = new object();

// @@@ public "consructor"
public static DbProxy Instance
{
get
{
if (DbProxy._oInstance == null)
{
lock (padlock)
{
if (DbProxy._oInstance == null)
{
DbProxy newDB = new DbProxy();
System.Threading.Thread.MemoryBarrier();
DbProxy._oInstance = newDB;
}
}
}
return DbProxy._oInstance;
}
}
// @@@ private constructor
private DbProxy()
{

}
}


Monday, April 13, 2009

Output Cache by the book

Hi,
i found the best way to implement Output Cache
we have only 2 steps to make it:

step 1
------
define in the Web.config some different cache profiles that u need:

<system.web>

<caching>

<outputCacheSettings>

<outputCacheProfiles>

<add name="profile1" duration="100" varyByParam="param1" />

<add name="profile2" duration="100" varyByParam="None" />

</outputCacheProfiles>

</outputCacheSettings>

</caching>

</system.web>


step 2
------
define in your pages the profile that u want to use:

<%@ OutputCache CacheProfile="profile1" %>


now, if we want to check if it works
all we have to is to make aspx page, and to play with his links
and check if the DateTime changed or not
TEST.aspx

<%@ OutputCache CacheProfile="profile1" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<body>

<form id="form1" runat="server">

<%= DateTime.Now.ToString() %><br />

<a href="?param1=1">1</a><br />

<a href="?param1=2">2</a><br />

<a href="?param1=3">3</a><br />

</form>

</body>

</html>


Another small tip:
for disable the OutputCache(in the development environment for example) add location="None" in the appropriate profile in the web.config in this way:

<add name="profile1" duration="100" varyByParam="param1" location="None" />

Saturday, April 11, 2009

A new startup - create a permanent breakpoint

Hi,
with this line u can create a permanent breakpoint in c# applications:
System.Diagnostics.Debugger.Break();

recomanded and very useful

Wednesday, April 8, 2009

Send array of objects form client to server

Hi,
with this code u can send array of object form client to server in c#
u have to copy the client and server code from this post
and use this 2 dependencies:
1. JSON Code(Take js file)
2. Serialize Code(Take dll file)

THE SERVER CODE:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Newtonsoft.Json;
using System.Collections.Generic;

public partial class tbl1 : System.Web.UI.Page
{
public string tempPerson;
public string temp_arr;
public List person_arr = new List< person >();
protected void Page_Load(object sender, EventArgs e)
{
Person person = new Person();
person.name = string.Empty;
person.age = 0;
string json1 = JavaScriptConvert.SerializeObject(person);
tempPerson = json1;
string json = JavaScriptConvert.SerializeObject(person_arr);
temp_arr = json;
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
person_arr = JavaScriptConvert.DeserializeObject< List< person > >
(hiData.Value);
}
}
public class Person
{
public string name;
public int age;
}



THE CLIENT CODE:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Arr.aspx.cs" Inherits="tbl1" %>
<script src="json2.js" type="text/javascript"></script>
<script type="text/javascript">
var arr = <%=temp_arr%>;
var p1 = <%=tempPerson%>;
var hiDataID = '<%=hiData.ClientID%>';
function add_to_arr(name, age)
{
var tempP = clone(p1);
tempP.name = name;
tempP.age = age;
arr[arr.length] = tempP;
}
function add2Items()
{
add_to_arr("name1", 1);
add_to_arr("name2", 2);
var g = JSON.stringify(arr);
document.getElementById(hiDataID).value = g;
}
function clone(obj)
{
return JSON.parse(JSON.stringify(obj));
}
</script>
<form id="form1" runat="server">
<div>
<input onclick="add2Items()" type="button" value="Create Array">
<input id="hiData" type="hidden" runat="server">
</div>
<asp:linkbutton id="LinkButton1" onclick="LinkButton1_Click" runat="server">Send To Server</asp:linkbutton>
</form>

Monday, March 23, 2009

HOW TO: override __doPostBack function

hi,
this function let u override the doPostBack function
it is ueful when u want to make some action before submit

THE FUNCTION CODE:

var __oldDoPostBack = __doPostBack; // replace __doPostBack with another function
__doPostBack = AlwaysFireBeforeFormSubmit;
function AlwaysFireBeforeFormSubmit (eventTarget, eventArgument)
{
var question = "";
if(eventTarget == "btn_save")
{ // if save was pushed-there is nothing to confirm
__oldDoPostBack (eventTarget, eventArgument);
return;
}
if(statusWasChanged == "false")
{ // if nothing was changed-there is nothing to confirm
__oldDoPostBack (eventTarget, eventArgument);
return;
} else if(confirm("Discard your changes?"))
__oldDoPostBack (eventTarget, eventArgument);
}

My new site

hi,
i just publish a new site:
www.what-is-my-ip-online.com
it lets u:
- find your ip address
- find your user agent
- find yor screen resolution
- find your browser type
i'll be happy to hear any comments/suggestions from u
have a nice week