Google Maps v3 marker.set_map deprecated
After the 8.8 earthquake outside of Chile this past weekend, I posted my Quake Tracker to twitter/facebook so people could easily visualize where the quake occurred. Granted, there is a lot of work that I still want to do with the mashup, but it at least works, or so I thought.
I noticed that new selections weren't actually loading earthquakes, and I decided to wait until today to see what was going on. After stepping through the code a few times, I found that the function
marker.set_map()
is now deprecated. It has been deprecated and replaced by
marker.setMap()
It's a little annoying that the API has deprecated a function in the same version that I was using for the quake tracker.
Basics: Posting data to a remote server via .NET
Class for Remote Posting:
public class RemotePost
{
#region Fields and Properties
private string _url;
private string _postData;
private byte[] _data;
/// <summary>
/// URL to which the Post is sent
/// </summary>
public string Url
{
get
{
if (!_url.StartsWith("http://"))
return String.Format("{0}{1}", "http://", _url);
else
return _url;
}
set
{
_url = value;
}
}
/// <summary>
/// The Method to Use. Can also change to "GET"
/// </summary>
private string Method
{
get
{
return "POST";
}
}
/// <summary>
/// A string of data you want to post to a URL
/// </summary>
public string PostData
{
get
{
return _postData;
}
set
{
_postData = value;
}
}
/// <summary>
/// Pulls the string of PostData
/// </summary>
public byte[] Data
{
get
{
if (_data != null)
return _data;
else
return ASCIIEncoding.Default.GetBytes(PostData);
}
set
{
_data = value;
}
}
#endregion
/// <summary>
/// Posts to remote URL, and returns the response
/// </summary>
/// <returns></returns>
public string Post()
{
if (string.IsNullOrEmpty(Url) | string.IsNullOrEmpty(PostData))
return "Error with URL or Post Data, try again";
HttpWebRequest req =
(HttpWebRequest)WebRequest.Create(Url);
req.Method = Method;
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = Data.Length;
Stream newStream = req.GetRequestStream();
// send!
newStream.Write(Data, 0, Data.Length);
newStream.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader reader =
new StreamReader(resp.GetResponseStream(), enc);
string response = reader.ReadToEnd();
return response;
}
}
Usage:
RemotePost app2 = new RemotePost();
app2.PostData = "var1=encodeme&var2=encodemetoo";
app2.Url = "http://www.example.com/ProcessingPage.aspx";
txtServerResponse.Text = app2.Post();
The comments and code are pretty self-explanatory. Have fun!
Explaining advanced features of C# 3.0
C# 3.0 Func delegates and Expressions
In this post, I'll attempt to clarify the meaning of Func delegates and Expressions.
These are very useful additions to C# 3.0, but it seems to be rarely blogged about.
// Note: I assume you have a general understanding of delegates and anonymous methods
Microsoft's definitions:
Func
// Encapsulates a method that has no parameters and returns // a value of the type specified by the TResult parameter. public delegate TResult Func<TResult>() public delegate TResult Func<TParam0, TResult>(TParam0 arg0) public delegate TResult Func<TParam0, TParam1, TResult>(TParam0 arg0, TParam1 arg1) // etc. up to 3 Generic Input parameters and a Generic Result parameter
Expression
// Represents a strongly typed lambda expression as a data structure // in the form of an expression tree. This class cannot be inherited. public sealed class Expression<TDelegate> : LambdaExpression // Describes a lambda expression. public class LambdaExpression : Expression // Provides the base class from which the classes that represent expression // tree nodes are derived. It also contains static (Shared in Visual Basic) // factory methods to create the various node types. This is an abstract class. public abstract class Expression
// NOTE : Expression<TDelegate> is not an override of Expression, they are completely independent classes
Quick Rundown
Func<TResult>
The Func delegates are simply Generic delegates introduced to make our lives easier. You specify your return type, or the types of your input parameters and your return type.
For instance, assume you have an object called Product, with a method whose signature is:
public bool AddComponent(Component c) { /* logic */ }
You could use the Func delegate in a number of ways on the product object:
// our objects
Product product = new Product();
// Examples
Func<bool> addComponent1 = product.AddComponent( new Component() );
Func<bool> addComponent2 = delegate() { return product.AddComponent( new Component() ); };
Func<bool> addComponent3 = () => product.AddComponent( new Component() );
if(addComponent1()) { /* Do stuff */ }
if(addComponent2()) { /* Do stuff */ }
if(addComponent3()) { /* Do stuff */ }
The above example is the common explanation of Func delegates. However, to a beginner, this may seem like a ridiculous way to rename a method. The point being, it can be difficult to understand why you'd generalize
product.AddComponent( new Component() );
as 'addComponent1' when you could just as easily write out
if(product.AddComponent( new Component() ) ) { /* Do stuff */ }
Another, more useful example of a real-world application:
Product product = new Product();
Func<bool> addAllProducts = () =>
{
if (product.AddComponent(new Component { Name = "Component1" })
&& product.AddComponent(new Component { Name = "Component2" })
&& product.AddComponent(new Component { Name = "Component3" }))
{ return true; }
else { return false; }
};
bool wasSuccessful = addAllProducts(); // wasSuccessful is true if AddComponent succeeds every time.
// NOTE: Here, I've used object instantiation for the Component object, this is another feature of C# 3.0
Expression<TDelegate>
Of particular note is the difference between Func<TResult> and Expression<TDelegate>. A Func<TResult> is code (a delegate) that is compiled at runtime, while an Expression<TDelegate> is a data representation (as an Expression Tree) of that delegate. This means you can act upon any part of an Expression<TDelegate> as if it were a data structure (similar to getting a count of objects in a list or accessing a dictionary value via dictionary key).
You've probably read that paragraph and said "...what?" If so, I don't blame you.
Take, for instance, the example given at MSDN:
System.Linq.Expressions.Expression<Func<int, bool>> expr = (i) => i < 5;
This doesn't give us much to go by. However, when you think about expr as a data structure, you're basically instantiating this data structure with 'i => i < 5;'. Now, you can pass this expression tree around your application and you're free to access any part of the expression tree as if it is its own separate entity; you can't do this with a delegate alone. A fairly good example is available at MSDN.
To better clarify, let's look at the parts of this expression tree:
- Expression
- Parameter
- Body
- --Operation
- --Constant
/* Expression */ (i) => i < 5; /* Parameter */ (i) /* Body */ i < 5; /* Operation NodeType */ < /* Constant */ 5
I know breaking it down into these parts seems very simplistic, but the point is that you can't do this with a delegate. If you passed a delegate to a method, that's it. You can't figure out what the first parameter was declared as, or the operation being performed (less than, greater than, etc). You'd have no way of finding what constant was supplied.
To compile the above Expression tree, you could do the following:
bool oneIsLess = expr.Compile()(1); /* result: true */
Why is this important? You can easily access the parts of the expression as described by the MSDN article:
Expression<Func<int, bool>> exprTree = num => num < 5;
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
// This code produces the following output:
// Decomposed expression: num => num LessThan 5
Using the Expression Tree Visitor from MSDN, you can access the parts of a number of Expression Trees.
Practical Applications
Because this post is already very long, instead of going in-depth into practical applications now, I'll save that for a future post.
Instead, I'd like to direct you to the project and usage of Expression trees that made me delve further into the topic: Fluent NHibernate. I had previously thought that Expression Trees and Lamda Expressions were geared more toward LINQ providers and less important for daily development. However, if you were to download the source for Fluent NHibernate, you'd see another cool usage of Expression Trees: static reflection.
James Gregory, the principal developer of Fluent NHibernate wrote a nice introduction to static reflection, in which he illustrates the following usage:
/* Copyright James Gregory, Creative Commons:Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales */
public PropertyInfo GetProperty<TEntity>(Expression<Func<TEntity, object>> expression) { /* Do stuff */ }
GetProperty<Customer>(customer => customer.Name); // usage
As you can see, instead of retrieving the PropertyInfo of the Customer object's Name property by hard-coding a "Name" string, you're now free to refactor your code properly. In which case, if you were to change your 'Name' property, your tests or build process would fail, whereas the hard-coded string "Name" would be overlooked.
I encourage you to download the source code for Fluent NHibernate and take a look at how static reflection is being used.
Further Reading
http://www.lostechies.com/blogs/gabrielschenker/archive/2009/02/03/dynamic-reflection-versus-static-reflection.aspx
http://www.codeproject.com/Articles/36262/Getting-Fun-with-Net-Static-Reflection.aspx
http://ayende.com/Blog/archive/2005/10/29/StaticReflection.aspx
http://apobekiaris.blogspot.com/2009/06/more-static-reflection.html
Example Console Application
static void Main(string[] args)
{
List<int> numbers = new List<int>();
Random r = new Random();
for (int i = 0; i < 15; i++)
{
numbers.Add(r.Next(0,50));
}
// Expression trees can be used to perform an action on objects
Expression<Func<List<int>,int, bool>> isAvailable = (x,num) => x.Contains(num);
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Is {0} available? {1}", i, isAvailable.Compile()(numbers, i));
}
Product product = new Product();
Func<bool> addAllProducts = () =>
{
if (product.AddComponent(new Component { Name = "Component1" })
&& product.AddComponent(new Component { Name = "Component2" })
// && product.AddComponent(new Component { Name = "Component2" }) /* fails */
&& product.AddComponent(new Component { Name = "Component3" }))
{ return true; }
else { return false; }
};
bool wasSuccessful = addAllProducts();
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
ParameterExpression param = (ParameterExpression)expr.Parameters[0];
BinaryExpression operation = (BinaryExpression)expr.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
}
}
public class Product
{
public IList<Component> Components { get; private set; }
public bool AddComponent(Component c)
{
if (Components.Contains(c))
return false;
else
{
Components.Add(c);
return true;
}
}
public Product()
{
Components = new List<Component>();
}
}
public class Component
{
public string Name { get; set; }
public override bool Equals(object obj)
{
if(!(obj is Component)) { return false; }
return this.Name.Equals(((Component)obj).Name);
}
}
Google Chrome Extension: New Tab Redirect! STEP BY STEP
Background
(see http://code.google.com/chrome/extensions/overview.html for a thorough background of Chrome Extension development)
A Google Chrome Extension is a mini web application which runs in its own process and can perform actions at a browser-level or page-level.
An extension consists (or may consist) of a number of parts:
- manifest.json
- Web files (html, js, css, images)
- NPAPI Plugins
- background.html (the long-running process)
All of these files are bundled into a package with a .crx file extension. When uploading your extension to the Google Chrome Extensions Gallery, you only zip up the files your extension needs and Google will package it properly for you.
The manifest.json file is a file which specifies properties of your extension in JavaScript Object Notation (aka JSON). For a quick intro to JSON, check out http://www.learn-ajax-tutorial.com/Json.cfm
The Manifest File
manifest.json:
{
"name": "New Tab Redirect!",
"description": "Sets a user-specified URL to load in new tabs.",
"version": "0.0.1.109",
"background_page": "background.html",
"options_page":"options.html",
"chrome_url_overrides": {
"newtab": "redirect.html"
},
"permissions": ["tabs"],
"icons": {
"128": "icon128.png",
"19":"icon19.png"
}
}
(end manifest.json)
The name, description, version, background_page, and options_page key/value pairs are pretty self-explanatory.
The "chrome_url_overrides" section is interesting. As you can see, the value for this entry is itself an object. This object allows me to override "newtab" with my own page, "redirect.html". Currently, the chromium team will only allow you to override newtab, however, I anticipate they'll allow you to override other pages in the future. For a list of url constants used within Chrome, check out the url_constants.cc file in the source code repository. Possible future overrides would be anything that is listed near the end of that file as 'const char kChromeUI*Host[]'
Back to the file. "permissions" takes an array of requested permissions. New Tab Redirect! requires permissions to update tabs. This is because we're not only redirecting to html web-hosted sites; New Tab Redirect allows you to set web pages, local files, or inherent Chrome pages.
"icons" specifies the location of the icons your extension will use. These icons will be displayed in the Gallery and in the Extensions page within Google Chrome.
Remember: You must change your version number when updating your publicly hosted extension, or else Chrome won't find a new version and your users will not be updated.
The Background Page
background.html
<html>
<head>
<script type="text/javascript">
String.prototype.startsWith = function(str){
return (this.indexOf(str) === 0);
}
var url = null;
var newTabId = undefined;
var protocol = undefined;
var allowedProtocols = ["http://","https://","about:","file://",
"file:\\", "file:///", "chrome://","chrome-internal://"];
function setUrl(url) {
if(protocolPasses(url)
&& url.length > { /* 8 is arbitrary */
this.url = url;
} else {
protocol = 'http://'; /* force http */
var right = url.split('://')
if(right != undefined && right != null && right.length > 1) {
this.url = protocol + right[1];
} else {
/* this will redirect to http:// if url is empty */
this.url = protocol + url; }
}
localStorage["url"] = this.url;
function protocolPasses(url) {
if(typeof(url) == 'undefined' || url == null) { return false; }
if (url.startsWith(allowedProtocols[3])
&& !url.startsWith(allowedProtocols[5])) {
url.replace(allowedProtocols[3], allowedProtocols[5]);
} else if (url.startsWith(allowedProtocols[4])) {
url.replace(allowedProtocols[4], allowedProtocols[5]);
}
for(var p in allowedProtocols) {
if(url.startsWith(allowedProtocols[p])) { return true;}
}
return false;
}
}
function init() {
url = localStorage["url"] || "http://www.facebook.com";
}
function r(tabId) {
chrome.tabs.update(tabId, {"url":this.url});
}
chrome.tabs.onUpdated.addListener(function(tabId,info,tab) {
if (info.status === 'loading')
console.log('Loading url ... ' + tab.url)
if(info.status === 'complete')
console.log('Finished loading url ... ' + tab.url)
});
chrome.tabs.onCreated.addListener(function(tab) {
newTabId = tab.id
});
</script>
</head>
<body onload="init()"></body>
</html>
(end background.html)
This page is pretty self-explanatory for the most part. The background page is your long-running process, and is usually used to house any variables that are shared between pages. However, this isn't a necessity of Chrome Extension architecture. Every page in an extension can interact with any other page through chrome.extension.getViews() or chrome.extension.getBackgroundPage() . Because of the nature of New Tab Redirect, I've used a background page.
One thing of note is the initialization of the extension. Since the operation is fairly simple, allowing a user to specify a url and then redirecting to that url, the only thing I need to worry about immediately is the url. This is stored using HTML 5's local storage. If the url doesn't exit, I set it to facebook.
The setUrl function is located in the Background page and is called from options.html. It is located here so the options page isn't trying to set the url variable that is maintained by the background page. This function checks my array of allowed protocols and validates the url with some simple rules.
r(tabId) is the function which actually updates the tab when the protocol isn't an http or https protocol. The function name is short because the the code in redirect.html should be as concise as possible. This function calls the chrome.tabs.update method (one culprit behind the tabs permission requirement)
That tabId is provided via the redirect.html, which gets the currently created tab's id. However, again note that this processing only occurs when the url is local.
Options
Because the options page is simple html and styles, I'll only include the JavaScript which sets the url.
options.js
String.prototype.startsWith = function(str) {
return (this.indexOf(str)===0);
}
var chromePages = {
Extensions : "chrome://extensions/",
History : "chrome://history/",
Downloads : "chrome://downloads/",
NewTab : "chrome-internal://newtab/"
}
var aboutPages = ["about:blank","about:version", "about:plugins","about:cache",
"about:memory","about:histograms","about:dns",
"chrome://extensions/","chrome://history/",
"chrome://downloads/","chrome-internal://newtab/"];
var popularPages = {
"Facebook":"www.facebook.com",
"MySpace":"www.myspace.com",
"Twitter":"www.twitter.com",
"Digg":"www.digg.com",
"Delicious":"www.delicious.com",
"Slashdot":"www.slashdot.org"
};
// save options to localStorage.
function save_options() {
var url = $('#custom-url').val();
if(url == ""){
url = aboutPages[0];
}
if( $.inArray(String(url), aboutPages) || isValidURL(url)) {
save(true,url);
} else {
save(false,url);
}
}
function save(good,url) {
if(good) {
chrome.extension.getBackgroundPage().setUrl(url);
$('#status').text("Options Saved.");
} else {
$('#status').text( url + " is invalid. Try again (http:// is required)");
}
$('#status').css("display", "block");
setTimeout(function(){
$('#status').slideUp("fast").css("display", "none");
}, 1050);
}
// Restores select box state to saved value from localStorage.
function restore_options() {
var url = chrome.extension.getBackgroundPage().url || "http://www.facebook.com/";
$('#custom-url').val(url);
}
function isValidURL(url) {
var urlRegxp = /^(http:\/\/www.|https:\/\/www.|ftp:\/\/www.|www.){1}([\w]+)(.[\w]+){1,2}$/;
if (urlRegxp.test(url) != true) {
return false;
} else {
return true;
}
}
function saveQuickLink(url){
var uurl = unescape(url);
$('#custom-url').val(uurl);
save(true,uurl);
return false;
}
$(document).ready(function(){
restore_options();
$.each(chromePages, function(k,v) {
var anchor = "<a href=\"javascript:saveQuickLink('"+v+"');\">"+k+"</a>";
$('#chromes').append("<li>" + anchor + "</li>");
});
$.each(aboutPages, function() {
if(this.startsWith("about:")) { /* quick fix to handle chrome pages elsewhere */
var anchor = "<a href=\"javascript:saveQuickLink('"+this+"');\">"+this+"</a>";
$('#abouts').append("<li>" + anchor + "</li>");
}
});
$.each(popularPages, function(k,v) {
var anchor = "<a href=\"javascript:saveQuickLink('"+v+"');\">"+k+"</a>";
$('#popular').append("<li>" + anchor + "</li>");
});
});
(end options.js)
As you can see, I've included jQuery for dom manipulation. I decided to do this because jQuery is so small and because the Options page can be whatever size you'd like (keeping in mind user experience, of course). This saved me some time from writing out a little bit of javascript.
Of note here is how I build the lists of Chrome pages, About pages, and Popular pages. This isn't included in the options.html file, which only has placeholders for the unordered lists. This allows me to go in and provide a page name and url for chromePages and popularPages, or just the url for aboutPages. If I want to add anything in the future, I'll just add a key/value pair (or url) to one of these objects. If I want to remove, likewise, I only touch the respective object.
Quick links (one from an above-mentioned object) are saved automatically, bypassing the url checking regex. However, you'll notice in the save_options function that I check first to see if the url is in the list of about pages, this is because a user will most likely enter about:memory or any valid url, and whould be less likely to enter chrome-internal://newtab/. In the future, I will probably add checks on all objects before checking a valid url, but this kind of thing happens in incremental development.
As you can see, if the user gets to save the url, the function setUrl from the background page is called via chrome.extension.getBackgroundPage().setUrl(url); Following good user interface techniques, we have to let the user know what happened, which is what the next line and the rest of the function accomplishes.
Note: The new tab url is chrome-internal:// instead of chrome://. Why is this, do you think? Don't think too hard, though. It's simple: redirect.html is now chrome://newtab/, because I've told chrome to override the newtab with my own file. You can test it out by typing chrome://newtab into Google Chrome. Try chrome-internal://newtab and see what happens? This can only be called internally, hence the name, and must be called from within an extension via chrome.tabs.update. If you don't use this internal url, when you set the url to chrome://newtab and hit CTRL+T or click the '+' tab, your tab will keep trying to call itself, and eventually stop, after doing nothing meaningful.
Redirect.html
Finally, the beast that does it all.
redirect.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Windows (vers 14 February 2006), see www.w3.org">
<title>
Redirecting...
</title>
<script type="text/javascript">
var wid, tid;
function r() {
var url = localStorage["url"] || "";
if (url.toLowerCase().indexOf("http:") === 0 ||
url.toLowerCase().indexOf("https:") === 0) {
document.location.href = url;
return;
} else {
chrome.windows.getCurrent(function(w) {
wid = w.id;
chrome.tabs.getSelected(wid, function(t) {
tid = t.id;
});
});
chrome.extension.getBackgroundPage().r(tid);
}
}
</script>
</head>
<body onload="setTimeout('r()',100);r();return false;">
Redirecting...<br>
<em>If your page doesn't load within 5 seconds,
<a href="javascript:r()">click here</a></em>
</body>
</html>
(end redirect.html)
Note: I have run the redirect.html file through HTML Tidy and a JavaScript formatter at http://jsbeautifier.org/, but this file should be as compact as possible. If you were to download New Tab Redirect and look at the source code, you'd see this code is all on one line. I'm writing this for your enjoyment, though, and one-liners aren't fun to look at.
The only thing special about this file is the the onload function. You'll notice how it runs r after 100 ms, then runs it again. There is quite an odd situation here: Chrome either has to initialize localStorage, doesn't allow us to get the current window and tab id immediately, or the processing required to do so takes longer than 100ms. You could, honestly, run the redirect function through a loop until it redirects (considering the document.location.href will immediately redirect the browser tab. If the url specified by the user is local, the function gets the current window, and from that the id of the current tab, and passes that to the background page's function.
I've been asked by a user or two to remove the redirect message, but I'll keep it for now. I consider a message necessary if, for some reason, a future release of Chrome breaks the extension.
The current source code for New Tab Redirect can be accessed via your Chrome Extensions directory after installing the extension, and is availing at the New Tab Redirect Project Page on Google Code.
If you have any questions or comments about this extension, please contact me.
Quickly create a Dictionary using Linq to Objects
When working with collections or lists, sometimes you just need to get a simple dictionary.
There are a number of ways to do this, but the ToDictionary method seems promising.
For isntance:
IList<Person> people = new List<Person>();
people.Add(new Person
{
FirstName = "Jim",
LastName="Schubert",
Age=29,
Phone="123-333-4444"
});
people.Add(new Person
{
FirstName = "Joe",
LastName="Schubert",
Age=25,
Phone="800-999-1111"
});
Dictionary<int,string> names = people.ToDictionary(k => k.Age, v => v.FirstName);
There may not be many uses for this type of syntax, but simple transformations like this make Linq fun.
Select Actions, Chrome Extension
Another extension for Google Chrome, Select Actions adds popup menu functionality to selected text.
To use, highlight some text and the menu will display for 3 seconds. Options allow you to post the selected text to Twitter and Facebook, or share the current page as a Note on Facebook.
You can also use Google services to: define words, translate words, map an address, add an event to your calendar, search on blogs and search on the web.
This is a work in progress, however.
TODO:
- Add an options page
- Allow users to add/edit/remove links
- Allow users to specify the display length (3 seconds is arbitrary)
- Allow users to customize color scheme
- Allow users to choose whether to display icons (possibly supplying their own)
Any questions or comments are welcome.
