Archives

Archives / 2005 / December
  • IE7 Standalone Launch Script


    UPDATES
    8/31/2006 - Version 1.6 works with IE7 RC1. Grab it here.
    7/26/2006 - Version 1.5 works with IE7 Beta 3, but requires a few more files so I've bundled it into a zip file for distribution. Grab it here.
    6/29/2006 - This isn't working with IE7 Beta 3 yet. I'll have to test it out more and probably release a new version.
    2/8/2006 - Version 1.4 temporarily updates the IE version to work with conditional statements (<!--[if lt IE 7.0]>) based on a recommendation by Thomas Meinike. 3/21/2006 - This build has been tested with the IE7 B2 Preview released on 3/20/2006. It works, in that it allowed me to browse sites in IE7 without messing up IE6 or my default browser association. However, I noticed high CPU usage while browsing and had to close IE7 using the task manager when I was through - it didn't respond to that little red X thing. I believe these are minor inconveniences compared to running a separate virtual machine just to check how a site looks. Obviously, this build of IE7 just came out yesterday so I haven't put this through rigorous testing.
    2/2/2006 - Version 1.3 works with IE7 Beta 2 Preview.

    Read more...

  • Farewell to IE Mac and a checkup on my IE recommendations from June 2004

    I'm glad to see IE5 for Mac being mercy killed. It was a decent browser when it was released, but was condemned to a hideous undead state when development pretty much halted back in 2001. There never was an IE6 for Mac, and Mac IE5 is a pain to support. This may cause some short term problems for Mac users who use (poorly written) sites that are IE specific, but Mac IE5 is not a modern browser and it's time for us to move on. Did we plan to keep using IE5 forever?

    Read more...

  • [OT] GMail Mobile is finally here

    I've been waiting for this one for a while - GMail finally has a mobile version at http://m.gmail.com. I've occasionally used Pocket Gmail, but Gmail Mobile is a lot smoother. Just in time for vacation, too.

    Snip from the product announcement :

    Gmail Mobile

    Gmail Mobile
    Now you can access your Gmail account from your mobile phone or device. Just point your phone's web browser to http://m.gmail.com. Your Gmail account stays synched, whether you access it from the web or the mobile interface. It's easy to use and it's free (but yes, your wireless plan could still charge you).

    It also has these cool features:
    • Automatically optimizes the interface for the phone you're using
    • Opens the attachments you receive in messages, including photos, Microsoft Word documents and .pdf files
    • Lets you reply by call to people whose phone numbers are in your Gmail Contacts list

    Learn more

     

    Read more...

  • [code] MapPoint - CSS Uploads with Zip and Chunking

    The Microsoft MapPoint Web Service allow for uploading location data in XML following the Access 2003 XML format. The Customer Data Service limits uploads to 1MB chunks, but it allows the XML to be zip compressed. That's nice because zipping XML can cut the file size by up to 90%.

    I didn't find any good sample code for zipped, chunked uploads from an XML string, despite some concerted googling. The MapPoint SDK sample code fulfils the technical requirements without being at all useful in real life - it shows how to upload a file. If you were going to upload a file, you might as well use the MapPoint CDS website.

    In my case, I got a serializable object from a webservice, serialized it to XML, transformed it with XSLT to Access 2003 XML, zipped it, and did a chunked upload to the MapPoint CDS webservice. I'm not going to go through the process of transforming XML - there are plenty of good references for that. I'm goint to assume you've got an XML string in Access 2003 XML format and you're ready to upload it. This code requires a WebReference to the MapPoint CSS webservice. This is .NET 1.1 code so I'm using SharpZipLib for zip compression; if you're running on .NET 2.0 you've got native zip compression so you can eliminate that dependency.

    using System;
    using System.Configuration;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;

    using Mappoint;
    using MappointCSS;
    using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
    using ICSharpCode.SharpZipLib.Zip;

    namespace MappointUploader
    {
        
    public class UploadWorker
        {
            
    private bool WriteLocalFiles;

            
    public UploadWorker()
            {
            }

            
    public void Process()
            {
                outputConsole("Starting process.");
                outputConsole("Connecting to CRM Webservice.");
                WriteLocalFiles = (ConfigurationSettings.AppSettings["WriteLocalFiles"] == 
    bool.TrueString);

                
    string uploadXML = string.Empty;
                
                
    //TODO: Set uploadXML to an XML string in Access 2003 XML format.
                // In my case, I'm calling a webservice and transforming the output with an in-memory XSL transform.

                //Write file for debugging / production support
                
    writeToFile(uploadXML, @"XML\TransformOutput.xml");  
                
                
    //Load string into byte array and compress using "upload.xml" as the document name inside the zip
                
    byte[] uploadBytes = System.Text.Encoding.UTF8.GetBytes(uploadXML);
                outputConsole("Compressing XML (" + uploadBytes.Length + " bytes uncompressed).");
                uploadBytes = compress(uploadBytes,"upload.xml");
                outputConsole("Completed compressing XML (" + uploadBytes.Length + " bytes compressed).");

                
    //Connect to Mappoint Customer Data Service for upload
                
    UploadSpecification uploadSpec = new UploadSpecification();
                System.Net.NetworkCredential credentials = 
    new System.Net.NetworkCredential( 
                    ConfigurationSettings.AppSettings["CSSUser"],
                    ConfigurationSettings.AppSettings["CSSPass"], "PARTNERS");

                CustomerDataService cds = 
    new CustomerDataService();
                cds.Credentials = credentials;
                cds.PreAuthenticate = 
    true;

                UploadSpecification spec = 
    new UploadSpecification();
                spec.DataSourceName = ConfigurationSettings.AppSettings["Mappoint.DataSourceName"];
                spec.EntityTypeName = ConfigurationSettings.AppSettings["Mappoint.EntityTypeName"];
                
    if(ConfigurationSettings.AppSettings["Environment"] == "Service")
                {
                    spec.Environment = LocationDataEnvironment.Service;
                }
                
    else
                
    {
                    spec.Environment = LocationDataEnvironment.Staging;
                }
                spec.MaximumGeocodingLevel = GeocodingLevel.Street;
                spec.RejectAmbiguousGeocodes = 
    false;

                
    string jobID = cds.StartUpload(spec);
                outputConsole("Connecting to Mappoint CDS (" + spec.Environment + " environment, Job ID " + jobID + ").");

                writeToFile(uploadBytes, @"XML\TransformOutput.xml.zip");

                
    int byteCount = uploadBytes.Length;
                
    long bytesUploaded = 0;
                
    int chunkSize = 1000000;
                
    byte[] chunk;

                
    while(bytesUploaded < byteCount)
                {
                    
    if(byteCount-bytesUploaded > chunkSize)
                    {
                        chunk = 
    new byte[chunkSize];
                    }
                    
    else
                    
    {
                        chunk = 
    new byte[byteCount-bytesUploaded];
                    }
                    
                    Array.Copy(uploadBytes, bytesUploaded, chunk, 0, chunk.Length);
                    bytesUploaded = cds.UploadData(jobID, chunk, bytesUploaded);
                    outputConsole("Uploaded " + bytesUploaded + " bytes.");
                }

                cds.FinishUpload(jobID, bytesUploaded);
                outputConsole("Upload complete.");
            }

            
    private void writeToFile(string input, string filename)
            {
                
    byte[] buffer = System.Text.UTF8Encoding.UTF8.GetBytes(input);
                writeToFile(buffer, filename);
            }

            
    private void writeToFile(byte[] buffer, string filename)
            {
                
    if(WriteLocalFiles)
                {
                    
    using (FileStream fs = new FileStream(filename,FileMode.Create))
                    {
                        fs.Write(buffer,0,buffer.Length);
                    }
                }
            }

            
    private byte[] compress(byte[] buffer, string entryFileName)
            {
                MemoryStream memory = 
    new MemoryStream();
                ZipOutputStream stream = 
    new ZipOutputStream(memory);
                stream.IsStreamOwner = 
    false;
                stream.SetLevel(5);
                ZipEntry entry = 
    new ZipEntry(entryFileName);
                entry.DateTime    = DateTime.Now;
                entry.Size        = buffer.Length;
                ICSharpCode.SharpZipLib.Checksums.Crc32 crc = 
    new ICSharpCode.SharpZipLib.Checksums.Crc32();
                crc.Reset();
                crc.Update(buffer);
                entry.Crc = crc.Value;

                stream.PutNextEntry(entry);
                stream.Write(buffer, 0, buffer.Length);
                stream.Finish();
                stream.Close();
                
    return memory.ToArray();
            }

            
    private void outputConsole(string message)
            {
                
    string output = string.Format"{0} : {1}", DateTime.Now.ToLongTimeString(), message);
                
    using (StreamWriter sw = File.AppendText("RunStatus.log"))
                {
                    sw.WriteLine(output);
                }
                Console.WriteLine(output);
            }
        }
    }

    Now, about that Access 2003 XML data format. It's finicky, since it includes XSD which describes the data format of all columns, and CDS rejects the upload if it doesn't match. One trick is to model it in a simple Access table and export as XML (with XSD), then use that in your XSL template or XML source. Get something really simple working and add a field at a time if necessary.

    Remember that MapPoint requires a few fields in your upload data. - EntityID, Latitude, and Longitude. The EntityID must be a unique integer. Since my datasource used a GUID identifier, I manufactured a unique int ID in the XSLT:

    ...
    <EntityID>
        <xsl:number 
    value="position()" format="1" />
    <
    /EntityID>
    ...

    The Latitude and Longitude are required double (SQL float) columns; if a value is present then MapPoint will not geocode the position and will use the provided Lat / Long values. Even if you're not planning on overriding geocoding, though, these columns must be present. Robert McGovern's MapPoint article on DevEx provides a valid sample XML file with EntityID, Latitude, and Longitude that you can buld on, and there's more info on MSDN - Mappoint Data Source Format.

    Read more...

  • The software market doesn't reward security, it just punishes perceived insecurity

    Random thought: The market hasn't rewarded Microsoft's recent security initiatives (W2K3, XPSP2 etc.). Microsoft pumped a ton of development (read money) into their recent security efforts, which dramatically reduced their attack surfaces. That's a good long term move, but I don't think it paid off in immediate sales. I can say from my personal experience that administrators talk about the improved security they're getting when they install W2K3 for other reasons, but no one moves to W2K3 to get secure.

    The market doesn't reward security. It may punish insecurity, but doesn't seem to reward secure OS's or software with increased sales. Despite the fact that W2K3 is much more secure than W2K, it doesn't look like the investment directly paid off in sales revenue.

    Read more...

  • [tip] localhost vs. (local) in SQL Server connection strings

    Sample code with SQL Server connection strings often use localhost and (local) interchangeably. They're different.

    Server=(local);Database=DotNetNuke;Trusted_Connection=True
    Uses named pipes

    Server=localhost;Database=DotNetNuke;Trusted_Connection=True
    Uses a TCP port negotiated on port 1434 udp, which defaults to 1433

    There are many differences between TCP and Named Pipe connection, but if you're on localhost you're mostly concerned with simple access.

    • The default ASPNET account generally has an easier time with TCP, since the  ASPNET user doesn't have access to named pipes by default (http://support.microsoft.com/Default.aspx?id=315159).
    • If you're using impersonation, Named Pipes is usually simpler. If you're using impersonation with no username specified, you're running under the IIS Authenticating user. This defaults to IUSR_MACHINENAME if you're allowing annonymous access, which generally has access to the IPC$ share required for named pipe communications.  

    As mentioned in a comment on Peter Van Ooijen's blog a while ago, the easiest setup is to avoid either local or localhost and just use the machine name (e.g.  Server=COMPY386;Database=DotNetNuke;Trusted_Connection=True). Note that this will use TCP/IP rather than named pipes. This isn't always practical in a group development situation where each developer is running a SQL Server instance since each machine will have a unique name.

    Info on troubleshooting SQL Server 2000 connectivity here.
    Also check out this great info on ASPNET connectivity to SQL Server by RupW in the GDN message boards.

    Read more...