The reason the code in theleft column is a mistake is that there is no guarantee that you are runningon Internet Explorer 4 or later if document.all is defined, there is noguarantee that you are running on Netscape Navigator 4 if document.layersis defined, and there is no guarantee that you are running on Netscape6, Mozilla or another DOM1-compliant browser if document.getElementByIdis defined.New browsers (such as Operaand iCAT) appear all the time. Browsers not made by Netscape or Microsoftmay feature a hybrid DOM that is a mix of Navigator's and Internet Explorer'stwo DOMs. For example, a non-Netscape, non-Microsoft browser DOM mightsupport both document.layers and document.all, yet not supportall of the other features of either browser. If you wrote code that testedfor the existence of document.all and then (if document.all was defined) used many IE features besides document.all, that code would failwith errors on any browser which supported document.all but not other IEfeatures. Similarly, if you wrote code that tested for the existence ofdocument.layers and then (if document.layers was defined) used manyNavigator 4 features besides document.layers, that code would failwith errors on any browser which supported document.layers but not otherNavigator 4 features.
New versions of existingbrowsers also appear all the time. Although Netscape 6 and Mozilla hasfull support of DOM1 features such as document.getElementById its not theonly browser that has support of this feature. IE 5 has also implementeddocument.getElementById, yet it lacks support of many other W3C DOM features.By detecting this particular method you know that the browser supportsgetElementById of the document object, but you dont know if you are runningNetscape 6, Mozilla or IE5.
The moral of the story: Ifyou detect a particular object, all you've done is detect that particularobject. You don't know for sure which browser you're running on. All youknow after detecting a particular object is that the particular objectexists on the current client.
navigator.appVersionQUIRKS OF INTERNET EXPLORERHere are two Internet Explorerquirks of the navigator.appVersion property to be aware of:
- When you check the 'navigator.appVersion'property on Internet Explorer 3.0, you'll notice on the Windows side thatInternet Explorer 3.0 says it's Navigator 2.0, and thus the 'navigator.appVersion'property returns a '2.' On the Macintosh, Internet Explorer 3.0 says it'sNavigator 3.0, and 'navigator.appVersion' will return a '3'.
- When you check the 'navigator.appVersion'property on Internet Explorer 5.0, it returns 4.
As a result, when using thebelow sample code, you should not take the values of the variables is_majorand is_minorat face value. They are simply the appVersion numbers reported by the client,which may or may not be accurate. For reliable client version detection,use the boolean variables such as is_nav6up,is_nav4,is_ie5up,is_ie4,etc.navigator.userAgentQUIRKS OF THE AMERICA ONLINE 4.0 CLIENTAOL userAgent strings aresupposed to always include the string 'AOL #.#', where the pound signsstand for the version number such as 3.0 or 4.0. This is in fact true forthe user agent string reported in the HTTP header; it will always contain'AOL #.#'.
However, the navigator.userAgentstring that is reported by JavaScript has a bug in AOL 4.0 where 'AOL #.#'will not be inserted into the reported user agent string when:
- It is the first browser windowopened during the AOL session.
- The embedded browser is MSIE3.x.
Thus, client-side JavaScriptcode which attempts to detect the AOL client by looking for the string'AOL #.#' in the navigator.userAgent string is not 100% reliable. Thereis currently no known workaround to detect the AOL client with 100% reliabilityin client-side JavaScript, so the recommended workaround when AOL clientdetection is necessary is to use server-side detection of the HTTP useragent string.
navigator.userAgent QUIRKSOF NETSCAPE 6You should be aware thatNetscape 6, even though its called six, in the userAgent string has versionnumber 5. So when you are detecting this browser you should check for (is_major 5) and NOT (is_major 6)
JAVASCRIPTCODE TO DETECT BROWSER VENDOR, VERSION, AND OPERATING SYSTEMHere is the JavaScript codenecessary to detect browser vendor, version number, and operating system.This code creates a group of variables which indicate the browser's vendor,version number, JavaScript version, and operating system.
This code is believed tobe compatible with all versions of all JavaScript-capable browsers on allplatforms. It has been tested on the following operating systems and browserversions:
- Windows NT: Navigator4, Navigator 3, and Navigator 2; Internet Explorer 5; Internet Explorer3; Opera 3
- Windows 98: Netscape 6;Navigator4.76; Internet Explorer 4; Internet Explorer 5; Internet Explorer 5.5;Opera 5; HotJava 3
- Macintosh: Navigator 4, InternetExplorer 3.01, Internet Explorer 4.02
- RedHat Linux 6.2: Navigator4.6; Netscape 6
- SunOS5: Navigator 3
PROFILEOF YOUR BROWSERHere are the results ofrunning that JavaScript code on the browser you are using. The below texthas been dynamically generated after checking your browser vendor, version,and operating system from JavaScript.
Basic Data

Version Number
Browser Version
JavaScript Version
OS
SO WHY DIDN'T WE MAKETHIS CODE OBJECT ORIENTED?You're probably wonderingwhy we created a bunch of variables with similar names instead of doingsomething more elegant like this:
The answer is simple: thiscode is far more elegant, providing encapsulation of the variables withan enclosing 'is' object, but it breaks on Internet Explorer 3 for theMacintosh. If you create an 'is' object on IE3 for the Mac, the first timethe page is loaded, the code will work fine, however any reloads of thepage will cause the browser to crash. To get around this on IE3 for theMac, we don't create an 'is' object; instead, we create bunch of booleanvariables which have similar names. This is ugly, but it's the price wepay for working around this bug of JScript for the Macintosh in IE3.
Another possible workaroundis to use the object oriented code on all other browsers but wrap it ina check which avoids executing the object oriented code on IE3 for theMac. This preserves the object oriented design of the code but requiresan extra boolean check like if (!isIE3Mac &&is_nav4up) each time youreference the isobject. As this extra boolean check is inconvenient, we've resigned ourselvesto the simple non-object oriented version above. However, if you preferthe object oriented approach, we provide a objectoriented client sniffer with a safety check for the Mac. Finally, ifyou don't need to support IE3 for the Mac, you can use that objectoriented code and omit the Mac safety check.
- OTHER CLIENT SNIFFING RESOURCES
- BrowserSpy
- userAgentStrings on Browsers Based on Mozilla and Applications That Embed GeckoLayout Engine
- ADDITIONAL READING
- JavaScriptKnown Bug List
SampleCode Area
Articles
JavaScriptCourse
OtherJavaScript Resources
JavaScriptDocumentation
What'sNew in JavaScript for Navigator 4.0
JavaScriptScripting Tools
- VIEW SOURCE ARTICLES
- BeyondData Basics: Writing JavaScript Database Applications, Part 1
BeyondData Basics: Writing JavaScript Database Applications, Part 2
JavaScriptDate Object Techniques
ScriptingLayer Effects and Transitions
Detectinga JavaScript Client
BringingImages to Life with JavaScript
Members Resources
For the latest technicalinformation on Sun-Netscape Alliance products, go to:http://developer.iplanet.com
For more Internet development resources, tryNetscape TechSearch.
Copyright © 1999-2001Netscape Communications Corporation.
This week we set up a CI/CD pipeline for one of our UWP apps that needs to be sideloaded because we don't publish it through the Microsoft Store. This article was super useful in getting me started. Microsoft has made things quite easy with Azure DevOps, but there were a few things that took us a little bit of time to figure out.
A little bit of context
We have an enterprise UWP application that we publish via an http server. We also have a custom auto-update mechanism that updates the apps whenever an update is available. You can learn more about the auto-updater here.
So what we needed, is a build pipeline that builds the app for both x64 and x86 and generate an index.html page, appinstaller file and the msixbundle files for both the app and its dependencies.
The plan
- Setup a build pipeline to generate update package and increase version
- Set up a release pipeline to upload the update package via FTP
- Celebrate
This article provides most of the information needed. But I have a few notes:
1.1 Use self hosted agents
Unfortunately, it seems like Microsoft hosted agents are not powerful enough to build release modes of moderate to big UWP applications. Because in release mode, it has to compile the app natively and so uses the native compilation toolchain. In our experience, the native compilation toolchain requires at least 8 GB of RAM to work properly. For our app, the Microsft hosted agents had a build success rate of less than 50%. They fail because of memory usage issues.
Besides, hosted agents are much faster. Microsoft hosted agents would take about 45 minutes to build our app, our own hosted agents usually take about 10 minutes. This is partly because they use incremental build, instead of a clean build every time they need to build the app.
So you have to use your own hosted agents. You use your own machines or virtual machines to build the application. Adding an agent to a pool is very easy:
- Go to project settings > Agent Pools
- Click on 'Default' or create another pool
- Click on 'New Agent' and follow the instructions
Now you will need to tell the build pipeline to use your self-hosted agents.You can specify the pool name very easily in yaml:

You might also want to use the 64 bit compiler, for that add this xml snippet a PropertyGroup in your project's csproj file:
1.2 Use Nuget version 4.x
For some reason, not specifying Nuget version leads to the failure of the build.
1.3 Using Extension SDKs with a build pipeline
An Extension SDK is similar in concept to a regular assembly reference, but is instead a rich collection of files to cover various configurations and design time scenarios.
If you're using an SDK reference, for example if you use SQLite for UWP, you must include the SDK with the source code and tell MSBuild to use the local version before searching for the SDK in the global folder. This article explains the steps, but here is a summary:
- Create a folder beside your solution file and call it
SDKs. - Copy UAP folder from
C:Program Files (x86)Microsoft SDKs into the SDKs folder beside your solution file. - Add this snippet to the
.csproj file:
1.4 Versioning the packages
Usually the version of the package is stored inside Package.appxmanifest and auto-incremented by Visual Studio. But this requires you to commit the changes to make sure you don't reuse versions.
I am not comfortable with build pipelines committing changes to source code. Fortunately there are a few extensions for Azure DevOps that can help with this. The one I decided to use is Version Number counter. This article does a great job of explaining how you can use it.
What we can do is have a PowerShell script update the app manifest file:
For that you need to define a variable called appVersion with the initial version in this format: 1.0.0. Because UWP package version format is like 1.0.0.0, you have to concatenate another '0' at the end of appVersion.

If you're a desktop developer, you might not like PowerShell or bash scripts. But they are very powerful and flexible for automation scenarios.
1.5 Use templates
Sometimes you have multiple configurations and environments you want to build for. We wanted to be able to build for both Production and Staging environments. Each of which have different build configuration (Release, Debug, Staging...), supported different build platforms (x86, x64, ARM), had different auto-update URLs, etc..
Azure DevOps yaml files support templates. You define a base template and put all of the common steps and jobs there, then you define a bunch of parameters for the template so that the pipelines that inherit from the base template can configure these parameters.
The code
Template.yaml

Staging.yml
Production.yml
The release pipeline is very easy, since all of the hard work is done in the build pipeline. The only thing you have to do is:
Get the build artifacts from the build pipeline. You can do that by clicking 'Artifacts' part. Select 'Build' from 'Source Type' and select the appropriate build pipeline.
Upload the index.html, {ProjectName}.appinstaller and the package folder to the update website via FTP. Azure DevOps has a built-in task for FTP upload.
The title pretty much says it all.
Update 04/25/2020:
You can use the Code Signing Task for signing your WUP app easily and securely.
Please enable JavaScript to view the comments powered by Disqus.comments powered by Youtube Apk Version 1.3.11
Disqus
