Google html5 Tutorial

110
Introduction to HTML 5 Brad Neuberg Developer Programs, Google Wednesday, October 7, 2009

description

THE Tutorial OF HTML5 BY GOOGLE

Transcript of Google html5 Tutorial

Page 1: Google html5 Tutorial

Introduction to HTML 5Brad NeubergDeveloper Programs, Google

Wednesday, October 7, 2009

Page 2: Google html5 Tutorial

The Web Platform is AcceleratingU

ser E

xper

ienc

e

native web

1990 -- 2008 Q408 Q109 Q209 ...

iPhone 2.2:Nov 22, 2008canvasapp cachedatabaseSVG

Safari 4.0b:Feb 29, 2009canvasvideoapp cachedatabaseworkersSVG

HTML

DOMCSS

XHR

Opera Labs:Mar 26, 2009canvasvideogeolocationSVG

Android 1.5:Apr 13, 2009canvasgeolocationapp cachedatabaseworkers

Firefox 3.5b4:Apr 27, 2009canvasvideogeolocationapp cachedatabaseworkersSVG

Chrome 2.0:May 21, 2009canvasvideogeolocationapp cachedatabaseworkersSVG

Wednesday, October 7, 2009

Page 3: Google html5 Tutorial

And It’s Solving Key Developer ChallengesU

ser E

xper

ienc

e

native web

HTML

DOMCSS

XHR

SpeedLocationGraphics Storage

1990 -- 2008 Q408 Q109 Q209 ...

Wednesday, October 7, 2009

Page 4: Google html5 Tutorial

More Developers

0

75

150

225

300

Mon

thly

Con

tribu

tors

to O

SS

Bro

wse

rs

2002 2003 2004 2005 2006 2007 2008 2009

webkitfirefox 2.0-3.0firefox 3.1+chrome

Wednesday, October 7, 2009

Page 5: Google html5 Tutorial

More Users

50

150

250

350

450

OS

S B

row

ser U

sers

(M)

2005 2006 2007 2008 2009

Wednesday, October 7, 2009

Page 6: Google html5 Tutorial

More Speed

0

20

40

60

80

Sun

Spi

der R

uns

Per

Min

ute

2001 2003 2005 2007 Q108 Q208 Q308 Q408 Q109

100x improvementin JavaScript performance

Wednesday, October 7, 2009

Page 7: Google html5 Tutorial

5>4A More Powerful Web

Wednesday, October 7, 2009

Page 8: Google html5 Tutorial

Cautionary Tales of Latent Lemonade

xhr(1999)

xml (1998)

css(1996)

AJAX (2004)

Wednesday, October 7, 2009

Page 9: Google html5 Tutorial

HTML 5: A Chance to Do Things Differently

Wednesday, October 7, 2009

Page 10: Google html5 Tutorial

canvas/SVG video geolocation app cache &database

web workers

Wednesday, October 7, 2009

Page 11: Google html5 Tutorial

00

width

heig

ht

Y

x

y

X

Until Recently, You Couldn’t Draw on the Web

Wednesday, October 7, 2009

Page 12: Google html5 Tutorial

And Graphics Weren’t Very Interactive

javascript:onClick(Draw());

Wednesday, October 7, 2009

Page 13: Google html5 Tutorial

The Usual Options Do This...

VMLFlash

Silverlight

Wednesday, October 7, 2009

Page 14: Google html5 Tutorial

... But canvas and SVG Are Intrinsic to the WebTr

ansp

aren

t Sta

ck

DOM

Document Object Model (DOM) SpecificationOriginal: http://www.w3.org/TR/REC-DOM-Level-1/Latest: http://www.w3.org/TR/DOM-Level-3-Core/Contributors: Netscape, Sun, Microsoft, W3C, IBM, Novell, JavaSoft, SoftQuad Inc., Inso EPS, Texcel Research, Arbortext

Hypertext Markup Language (HTML)Original: http://tools.ietf.org/html/rfc1866 Latest: http://www.w3.org/TR/html5/Contributors: T. Berners-Lee, D. Connolly, L. Masinter, MIT, W3C, AT&T, IBM, Microsoft, Netscape, Novell, SoftQuad, Spyglass, Adobe, Lotus, CWI, Reuters, JavaSoft, HP, GRIF, Sun, Opera, Mozilla, Google, Apple

Hypertext Transfer Protocol (HTTP)Original: http://tools.ietf.org/html/rfc1945Latest: http://tools.ietf.org/html/rfc2616Contributors: UC Urvine, Compaq, MIT, Xerox, Microsoft, W3C, T. Berners-Lee, R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P. Leach

HTTP

HTML

Wednesday, October 7, 2009

Page 15: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

Wednesday, October 7, 2009

Page 16: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect

Wednesday, October 7, 2009

Page 17: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0"

Wednesday, October 7, 2009

Page 18: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100"

Wednesday, October 7, 2009

Page 19: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red"

Wednesday, October 7, 2009

Page 20: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red" stroke-width="5px"

Wednesday, October 7, 2009

Page 21: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red" stroke-width="5px" rx="8" ry="8"

Wednesday, October 7, 2009

Page 22: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red" stroke-width="5px" rx="8" ry="8" id="myRect" class="chart" />

Wednesday, October 7, 2009

Page 23: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red" stroke-width="5px" rx="8" ry="8" id="myRect" class="chart" />

Wednesday, October 7, 2009

Page 24: Google html5 Tutorial

Scalable Vector Graphics (SVG)

• HTML-like tags for drawing

15

<!DOCTYPE html><html><body><svg width="200" height="200">

</svg></body></html>

<rect x="0" y="0" width="100" height="100" fill="blue" stroke="red" stroke-width="5px" rx="8" ry="8" id="myRect" class="chart" />

Wednesday, October 7, 2009

Page 25: Google html5 Tutorial

Scalable Vector Graphics (SVG)

16

Wednesday, October 7, 2009

Page 26: Google html5 Tutorial

Scalable Vector Graphics (SVG)

16

var rect = document.getElementById('myRect');

Wednesday, October 7, 2009

Page 27: Google html5 Tutorial

Scalable Vector Graphics (SVG)

16

var rect = document.getElementById('myRect');rect.style.fill = 'green';

Wednesday, October 7, 2009

Page 28: Google html5 Tutorial

Scalable Vector Graphics (SVG)

16

var rect = document.getElementById('myRect');rect.style.fill = 'green';rect.onclick = function() { alert('hello'); }

Wednesday, October 7, 2009

Page 29: Google html5 Tutorial

Scalable Vector Graphics

17

Wednesday, October 7, 2009

Page 30: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

Wednesday, October 7, 2009

Page 31: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

Wednesday, October 7, 2009

Page 32: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');

Wednesday, October 7, 2009

Page 33: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

Wednesday, October 7, 2009

Page 34: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(200,0,0)";

Wednesday, October 7, 2009

Page 35: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(200,0,0)";ctx.fillRect (10, 10, 55, 50);

Wednesday, October 7, 2009

Page 36: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(200,0,0)";ctx.fillRect (10, 10, 55, 50);

ctx.fillStyle = "rgba(0, 0, 200, 0.5)";

Wednesday, October 7, 2009

Page 37: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(200,0,0)";ctx.fillRect (10, 10, 55, 50);

ctx.fillStyle = "rgba(0, 0, 200, 0.5)";ctx.fillRect (30, 30, 55, 50);

Wednesday, October 7, 2009

Page 38: Google html5 Tutorial

Canvas API

• JavaScript API ("Scriptable Image Tag")

18

<canvas id="myCanvas" width="150" height="150"></canvas>

var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgb(200,0,0)";ctx.fillRect (10, 10, 55, 50);

ctx.fillStyle = "rgba(0, 0, 200, 0.5)";ctx.fillRect (30, 30, 55, 50);

Wednesday, October 7, 2009

Page 40: Google html5 Tutorial

When Canvas or SVG?

20

Wednesday, October 7, 2009

Page 41: Google html5 Tutorial

When Canvas or SVG?

SVG -> High level–Import/Export–Easy UIs–Interactive–Medium Animation–Tree of objects

20

Wednesday, October 7, 2009

Page 42: Google html5 Tutorial

When Canvas or SVG?

SVG -> High level–Import/Export–Easy UIs–Interactive–Medium Animation–Tree of objects

20

Canvas -> Low level–No mouse interaction–High Animation–JS Centric–More Bookkeeping–Pixels

Wednesday, October 7, 2009

Page 43: Google html5 Tutorial

Chrome Firefox Safari Opera

canvas/SVG

video

geolocation

app cache

database

workers

HTML 5 Support

Wednesday, October 7, 2009

Page 44: Google html5 Tutorial

http://tinyurl.com/mbw73x

Wednesday, October 7, 2009

Page 45: Google html5 Tutorial

http://tinyurl.com/mbw73x

Wednesday, October 7, 2009

Page 46: Google html5 Tutorial

Wednesday, October 7, 2009

Page 47: Google html5 Tutorial

videocanvas/SVG geolocation app cache &database

web workers

Wednesday, October 7, 2009

Page 48: Google html5 Tutorial

Video is Complicated, and Outside Your Control

Wednesday, October 7, 2009

Page 49: Google html5 Tutorial

// HTML 5 makes <video> as easy as <img>

Wednesday, October 7, 2009

Page 50: Google html5 Tutorial

Embedding Video

27

Wednesday, October 7, 2009

Page 51: Google html5 Tutorial

Embedding Video

27

<video src="http://example.com/myMovie.ogg" controls>

Wednesday, October 7, 2009

Page 52: Google html5 Tutorial

Embedding Video

27

<video src="http://example.com/myMovie.ogg" controls> Your browser does not support the video element.

Wednesday, October 7, 2009

Page 53: Google html5 Tutorial

Embedding Video

27

<video src="http://example.com/myMovie.ogg" controls> Your browser does not support the video element. </video>

Wednesday, October 7, 2009

Page 54: Google html5 Tutorial

Multiple Files & Scripting

28

<video controls> <source src="foo.ogg" type="video/ogg"> <source src="foo.mp4"> Your browser does not support the video element. </video>

Wednesday, October 7, 2009

Page 55: Google html5 Tutorial

Multiple Files & Scripting

28

<video controls> <source src="foo.ogg" type="video/ogg"> <source src="foo.mp4"> Your browser does not support the video element. </video>

var v = document.getElementsByTagName("video")[0]; v.play();

Wednesday, October 7, 2009

Page 56: Google html5 Tutorial

<video> demos

• Basic Player (FF 3.5)

• YouTube (Safari 4) - View Source

Wednesday, October 7, 2009

Page 57: Google html5 Tutorial

Chrome Firefox Safari Opera

canvas/SVG

video

geolocation

app cache

database

workers

HTML 5 Support

Wednesday, October 7, 2009

Page 58: Google html5 Tutorial

geolocationcanvas/SVG video app cache &database

web workers

Wednesday, October 7, 2009

Page 59: Google html5 Tutorial

Life’s Better with Location

CRM Social Ads GamesPhotos

75 ft

20 ft

500 ft1.1 mi

2.1 mi

Places

2.8 mi

Wednesday, October 7, 2009

Page 60: Google html5 Tutorial

...And Browsers Are Now Location-Enabled

Wednesday, October 7, 2009

Page 61: Google html5 Tutorial

// the geolocation api brings browser-based location to your apps

Wednesday, October 7, 2009

Page 62: Google html5 Tutorial

Geolocation Sample

35

Wednesday, October 7, 2009

Page 63: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition(

Wednesday, October 7, 2009

Page 64: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) {

Wednesday, October 7, 2009

Page 65: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) { var lat = position.coords.latitude;

Wednesday, October 7, 2009

Page 66: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) { var lat = position.coords.latitude; var lon = position.coords.longitude;

Wednesday, October 7, 2009

Page 67: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) { var lat = position.coords.latitude; var lon = position.coords.longitude; showLocation(lat, lon);

Wednesday, October 7, 2009

Page 68: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) { var lat = position.coords.latitude; var lon = position.coords.longitude; showLocation(lat, lon); }

Wednesday, October 7, 2009

Page 69: Google html5 Tutorial

Geolocation Sample

35

navigator.geolocation.getCurrentPosition( function(position) { var lat = position.coords.latitude; var lon = position.coords.longitude; showLocation(lat, lon); });

Wednesday, October 7, 2009

Page 70: Google html5 Tutorial

geolocation demos

• Google Maps (FF 3.5)

Wednesday, October 7, 2009

Page 71: Google html5 Tutorial

Chrome Firefox Safari Opera

canvas/SVG

video

geolocation

app cache

database

workers

HTML 5 Support

(iPhone)

Wednesday, October 7, 2009

Page 72: Google html5 Tutorial

app cache &database

canvas/SVG video geolocation web workers

Wednesday, October 7, 2009

Page 73: Google html5 Tutorial

Web Apps Need to Work Everywhere

Wednesday, October 7, 2009

Page 74: Google html5 Tutorial

// database and app cache store user data and app resources locally

Wednesday, October 7, 2009

Page 75: Google html5 Tutorial

app cache & database demos

• Sticky Notes Demo (Safari 4)

Wednesday, October 7, 2009

Page 76: Google html5 Tutorial

App Cache

• List resources that you want to take offline

42

CACHE MANIFEST/static/stickies.html/media/deleteButton.png/media/deleteButtonPressed.png/css/stickies.css/js/stickies.js

Wednesday, October 7, 2009

Page 77: Google html5 Tutorial

App Cache

• List resources that you want to take offline

42

CACHE MANIFEST/static/stickies.html/media/deleteButton.png/media/deleteButtonPressed.png/css/stickies.css/js/stickies.js

<body manifest="./cache.manifest"></body>

Wednesday, October 7, 2009

Page 78: Google html5 Tutorial

DatabaseWednesday, October 7, 2009

Page 79: Google html5 Tutorial

Database

44

Wednesday, October 7, 2009

Page 80: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0",

Wednesday, October 7, 2009

Page 81: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB",

Wednesday, October 7, 2009

Page 82: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

Wednesday, October 7, 2009

Page 83: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) {

Wednesday, October 7, 2009

Page 84: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction(

Wednesday, October 7, 2009

Page 85: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) {

Wednesday, October 7, 2009

Page 86: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql(

Wednesday, October 7, 2009

Page 87: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes "

Wednesday, October 7, 2009

Page 88: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) "

Wednesday, October 7, 2009

Page 89: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) " + "VALUES (?, ?, ?, ?, ?, ?)",

Wednesday, October 7, 2009

Page 90: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) " + "VALUES (?, ?, ?, ?, ?, ?)", [id, text, timestamp, left, top, zIndex]);

Wednesday, October 7, 2009

Page 91: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) " + "VALUES (?, ?, ?, ?, ?, ?)", [id, text, timestamp, left, top, zIndex]); }

Wednesday, October 7, 2009

Page 92: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) " + "VALUES (?, ?, ?, ?, ?, ?)", [id, text, timestamp, left, top, zIndex]); } );

Wednesday, October 7, 2009

Page 93: Google html5 Tutorial

Database

44

var db = window.openDatabase("NoteTest", "1.0", "Example DB", 200000);

function saveMe(id, text, timestamp, left, top, zIndex) { db.transaction( function (tx) { tx.executeSql( "INSERT INTO WebKitStickyNotes " + "(id, note, timestamp, left, top, zindex) " + "VALUES (?, ?, ?, ?, ?, ?)", [id, text, timestamp, left, top, zIndex]); } );}

Wednesday, October 7, 2009

Page 94: Google html5 Tutorial

Chrome Firefox Safari Opera

canvas/SVG

video

geolocation

app cache

database

workers

HTML 5 Support

(mobile)

(mobile)

(iPhone)

Wednesday, October 7, 2009

Page 95: Google html5 Tutorial

web workerscanvas/SVG video geolocation app cache &database

Wednesday, October 7, 2009

Page 96: Google html5 Tutorial

A More Powerful Web == More Powerful Apps

Wednesday, October 7, 2009

Page 97: Google html5 Tutorial

But More Power == More Responsibility

I will not hose the browser with JavaScript

I will not hose the browser with JavaScript

I will not hose the browser with JavaScript

I will not hose the browser with JavaScript

I will not hose the browser with JavaScript

I will not hose the browser with JavaScript

Wednesday, October 7, 2009

Page 98: Google html5 Tutorial

// web workers defines an API for running background scripts

Wednesday, October 7, 2009

Page 100: Google html5 Tutorial

Web Workers

51

Wednesday, October 7, 2009

Page 101: Google html5 Tutorial

Web Workers

51

<script>

Wednesday, October 7, 2009

Page 102: Google html5 Tutorial

Web Workers

51

<script> var worker = new Worker('worker.js');

Wednesday, October 7, 2009

Page 103: Google html5 Tutorial

Web Workers

51

<script> var worker = new Worker('worker.js'); worker.onmessage = function (event) {

Wednesday, October 7, 2009

Page 104: Google html5 Tutorial

Web Workers

51

<script> var worker = new Worker('worker.js'); worker.onmessage = function (event) { console.log('Results: ' + event.data);

Wednesday, October 7, 2009

Page 105: Google html5 Tutorial

Web Workers

51

<script> var worker = new Worker('worker.js'); worker.onmessage = function (event) { console.log('Results: ' + event.data); };

Wednesday, October 7, 2009

Page 106: Google html5 Tutorial

Web Workers

51

<script> var worker = new Worker('worker.js'); worker.onmessage = function (event) { console.log('Results: ' + event.data); };</script>

Wednesday, October 7, 2009

Page 107: Google html5 Tutorial

worker.js

52

function findPrimes() { // ... prime algorithm here postMessage(nextPrime);}

findPrimes();

Wednesday, October 7, 2009

Page 108: Google html5 Tutorial

Chrome Firefox Safari Opera

canvas/SVG

video

geolocation

app cache

database

workers

HTML5 Support

(iPhone)

(mobile)

(mobile)

(mobile)

Wednesday, October 7, 2009

Page 109: Google html5 Tutorial

Download Slides

• http://codinginparadise.org/presentations/intro_html5.pdf

54

Wednesday, October 7, 2009

Page 110: Google html5 Tutorial

Introduction to HTML 5Brad NeubergDeveloper Programs, Google

Wednesday, October 7, 2009