5. <script src="http://yui.yahooapis.com/3.0.0/build/yui/
yui-min.js"></script>
YUI().use('dd-drag', function(Y) {
var dd = new Y.DD.Drag({
//Selector of the node to make draggable
node: '#demo'
});
});
http://www.flickr.com/photos/funadium/2311851858/
Saturday, November 21, 2009
7. Change always comes bearing gi@s
‐ Price Pritche*
Lighter Easier
• Finer grained modules,
sub‐modules
• Lazy‐loading
• Emphasis on code reuse
- common base, plugins,
extensions
Saturday, November 21, 2009
8. Change always comes bearing gi@s
‐ Price Pritche*
Lighter Easier
• Finer grained modules, • Sandboxed development
sub‐modules
• Consistent API
• Lazy‐loading
• Convenience
• Emphasis on code reuse - each, bind, nodelist, queue,
- common base, plugins, chainability, general sugar
extensions
Saturday, November 21, 2009
9. Change always comes bearing gi@s
‐ Price Pritche*
Lighter Easier
• Finer grained modules, • Sandboxed development
sub‐modules
• Consistent API
• Lazy‐loading
• Convenience
• Emphasis on code reuse - each, bind, nodelist, queue,
- common base, plugins, chainability, general sugar
extensions
Saturday, November 21, 2009
10. All in a day’s work
(but taking less than a day, hopefully)
Saturday, November 21, 2009
11. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
Saturday, November 21, 2009
12. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
node event
dom selector
Saturday, November 21, 2009
13. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
node event
dom selector
YUI().use("imageloader",
function(Y){
// magic!
}
);
Saturday, November 21, 2009
14. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
add phase
node event
dom selector
YUI().use("imageloader",
use phase
function(Y){
// magic!
}
);
Saturday, November 21, 2009
15. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
add phase
node event oop
dom selector imageloader
YUI().use("imageloader",
use phase
function(Y){
// magic!
}
);
Saturday, November 21, 2009
16. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
add phase
node event oop
dom selector imageloader
YUI().use("imageloader",
use phase
function(Y){
// magic!
}
oopevent
node
imageloader
);
Saturday, November 21, 2009
17. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
add phase
node event oop
dom selector imageloader
YUI().use("imageloader", YUI().use("anim-base",
use phase
function(Y){ function(Y){
// magic! // magic!
} }
oopevent
node
imageloader
); );
Saturday, November 21, 2009
18. All in a day’s work
(but taking less than a day, hopefully)
yui-min.js
event- attribute- base-
add phase
node event oop
custom base base
anim-
dom selector imageloader
base
YUI().use("imageloader", YUI().use("anim-base",
use phase
function(Y){ function(Y){
// magic! // magic!
} }
base-
attribute- anim-
event- event
oopevent
node
imageloader oop dom node
selector
base
); ); base
custom base
Saturday, November 21, 2009
19. Playing in your own sandbox Easie
(but invite others too) r
yui
...
add
node
use phase
Saturday, November 21, 2009
20. Playing in your own sandbox Easie
(but invite others too) r
yui
...
add
node
<script src="http://
yui.yahooapis.com/3.4/build/yui/yui-
min.js">
<script>
use phase
YUI().use("overlay", function(Y){
Y.on("click", function(){
new Y.Overlay({ … }).render();
}, "#button" );
});
</script>
Saturday, November 21, 2009
21. Playing in your own sandbox Easie
(but invite others too) r
yui
...
add
node
<script src="http:// <script src="http://
yui.yahooapis.com/3.4/build/yui/yui- yui.yahooapis.com/3.0/build/overlay/
min.js"> overlay-min.js">
<script> <script>
use phase
YUI().use("overlay", function(Y){ YUI().use("overlay", function(Y){
Y.on("click", function(){ new Y.Overlay({ … }).render();
new Y.Overlay({ … }).render();
}, "#button" ); });
</script>
});
</script>
Saturday, November 21, 2009
22. Playing in your own sandbox Easie
(but invite others too) r
yui
...
add
node
<script src="http:// <script src="http://
yui.yahooapis.com/3.4/build/yui/yui- yui.yahooapis.com/3.0/build/overlay/
min.js"> overlay-min.js">
<script> <script>
use phase
YUI().use("overlay", function(Y){ YUI().use("overlay", function(Y){
Y.on("click", function(){ new Y.Overlay({ … }).render();
new Y.Overlay({ … }).render();
}, "#button" ); });
</script>
});
</script>
Saturday, November 21, 2009
25. Everything where you want them Easie
(a.k.a. event façades) r
nt
Eve
YUI2 YUI3
var Dom = YAHOO.util.Dom;
var Event = YAHOO.util.Event;
var linkNode = Dom.get("id");
Event.addListener( linkNode, "click",
function(e) {
var target = Event.getTarget(e);
if( Dom.hasClass(
target, "selector"
)) {
Event.preventDefault(e);
}
});
Saturday, November 21, 2009
26. Everything where you want them Easie
(a.k.a. event façades) r
nt
Eve
YUI2 YUI3
var Dom = YAHOO.util.Dom; linkNode.on("click", function(e) {
var Event = YAHOO.util.Event;
if(!e.target.hasClass("selector")){
var linkNode = Dom.get("id"); e.preventDefault();
}
Event.addListener( linkNode, "click",
function(e) { });
var target = Event.getTarget(e);
if( Dom.hasClass(
target, "selector"
)) {
Event.preventDefault(e);
}
});
Saturday, November 21, 2009
27. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
ON
ON
Default Behavior
After
After
After
Saturday, November 21, 2009
28. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After
After
Saturday, November 21, 2009
29. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After
After
Saturday, November 21, 2009
30. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON e.stopImmediatePropagation()
Default Behavior
After
After
After
Saturday, November 21, 2009
31. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON e.stopImmediatePropagation()
Default Behavior
After
After
After
Saturday, November 21, 2009
32. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON e.preventDefault()
Default Behavior
After
After
After
Saturday, November 21, 2009
33. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON e.preventDefault()
Default Behavior
After
After
After
Saturday, November 21, 2009
34. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After e.preventDefault()
After
Saturday, November 21, 2009
35. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After e.preventDefault()
After
Saturday, November 21, 2009
36. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After e.stopImmediatePropagation()
After
Saturday, November 21, 2009
37. One moment in Jme Easie
(regarding on and aNer moments) r
nt
Eve
this.fire("select");
ON
ON
Default Behavior
After
After e.stopImmediatePropagation()
After
Saturday, November 21, 2009
39. Too many events spoil the page Easie
(a.k.a. event delegaOon) r
nt
Eve
HTML JS
<div id=”menu”>
<ul>
<li class=”menuitem”>
<em>Open file...</em>
</li>
<li class=”menuitem”>
<em>Save file...</em>
</li>
<li class=”menuitem”>
<em>Close file</em>
</li>
<li class=”menuitem stop”>
<em>Quit</em>
</li>
</ul>
</div>
Saturday, November 21, 2009
40. Too many events spoil the page Easie
(a.k.a. event delegaOon) r
nt
Eve
HTML JS
<div id=”menu”> var menuDiv = Y.one(“#menu”);
<ul>
menuDiv.delegate("click", function(e){
<li class=”menuitem”>
<em>Open file...</em>
</li>
<li class=”menuitem”>
<em>Save file...</em>
</li>
}, "li.menuitem");
<li class=”menuitem”>
<em>Close file</em>
</li>
<li class=”menuitem stop”>
<em>Quit</em>
</li>
</ul>
</div>
Saturday, November 21, 2009
41. Too many events spoil the page Easie
(a.k.a. event delegaOon) r
nt
Eve
HTML JS
<div id=”menu”> var menuDiv = Y.one(“#menu”);
<ul>
menuDiv.delegate("click", function(e){
<li class=”menuitem”>
<em>Open file...</em> Y.log( this.get(‘innerHTML’) );
</li> // <em>Quit</em>, etc
<li class=”menuitem”> // this == e.currentTarget
<em>Save file...</em> // e.container == menuDiv
</li>
}, "li.menuitem");
<li class=”menuitem”>
<em>Close file</em>
</li>
<li class=”menuitem stop”>
<em>Quit</em>
</li>
</ul>
</div>
Saturday, November 21, 2009
42. Too many events spoil the page Easie
(a.k.a. event delegaOon) r
nt
Eve
HTML JS
<div id=”menu”> var menuDiv = Y.one(“#menu”);
<ul>
menuDiv.delegate("click", function(e){
<li class=”menuitem”>
<em>Open file...</em> Y.log( this.get(‘innerHTML’) );
</li> // <em>Quit</em>, etc
<li class=”menuitem”> // this == e.currentTarget
<em>Save file...</em> // e.container == menuDiv
</li>
}, "li.menuitem");
<li class=”menuitem”>
<em>Close file</em>
</li> // but maybe we want to stop
Y.one(“li.stop”).on(“click”,
<li class=”menuitem stop”> function(e){
<em>Quit</em> e.stopPropagation();
</li> }
);
</ul>
</div>
Saturday, November 21, 2009
43. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
44. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
45. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
46. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
47. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON e.stopPropagation() Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
48. NoJficaJon flow: Bubbling Easie
(Ony bubbles) r
nt
Eve
Menu
MenuItem
ON ON
ON e.stopPropagation() Def. Behavior
Def. Behavior After
After After
After
After
Saturday, November 21, 2009
49. Working with HTML Elements Easie
(selectors, sugar, chaining, oh my) r
e
Nod
YUI2 YUI3
Saturday, November 21, 2009
50. Working with HTML Elements Easie
(selectors, sugar, chaining, oh my) r
e
Nod
YUI2 YUI3
var Dom = YAHOO.util.Dom;
var Event = YAOO.util.Event;
var elms = Dom.getElementsByClassName(
"task", "li", "actions");
for (var i = 0; i < elms.length; i++) {
var elm = elms[i];
if(Dom.hasClass(elm, "selected")){
Dom.addClass(elm, "current");
Event.on(elm, "click", handler);
}
}
Saturday, November 21, 2009
51. Working with HTML Elements Easie
(selectors, sugar, chaining, oh my) r
e
Nod
YUI2 YUI3
var Dom = YAHOO.util.Dom; var elm = Y.Node.get(
var Event = YAOO.util.Event; ".actions li.task.selected"
);
var elms = Dom.getElementsByClassName(
"task", "li", "actions"); elm.addClass("current");
elm.on("click", handler);
for (var i = 0; i < elms.length; i++) {
var elm = elms[i];
if(Dom.hasClass(elm, "selected")){
Dom.addClass(elm, "current");
Event.on(elm, "click", handler);
}
}
Saturday, November 21, 2009
52. Working with HTML Elements Easie
(selectors, sugar, chaining, oh my) r
e
Nod
YUI2 YUI3
var Dom = YAHOO.util.Dom; var elm = Y.Node.get(
var Event = YAOO.util.Event; ".actions li.task.selected"
);
var elms = Dom.getElementsByClassName(
"task", "li", "actions"); elm.addClass("current");
elm.on("click", handler);
for (var i = 0; i < elms.length; i++) {
var elm = elms[i]; // want something shorter?
Y.Node.get(…).addClass("current").on(
if(Dom.hasClass(elm, "selected")){ "click",handler);
Dom.addClass(elm, "current");
Event.on(elm, "click", handler);
}
}
Saturday, November 21, 2009
53. HTML Elements made easier Easie
(HTMLElement API improved) r
e
Nod
Supports Normalizes Enhances
Bulk operaOons
Saturday, November 21, 2009
54. HTML Elements made easier Easie
(HTMLElement API improved) r
e
Nod
Supports Normalizes Enhances
node.appendChild(new)
node.cloneNode(node)
node.scrollIntoView()
node.get("parentNode")
node.set("innerHTML",
"Hello world!")
Bulk operaOons
Saturday, November 21, 2009
55. HTML Elements made easier Easie
(HTMLElement API improved) r
e
Nod
Supports Normalizes Enhances
node.appendChild(new) node.getAttribute("href")
node.cloneNode(node) node.contains(node)
node.scrollIntoView() node.getText()
node.get("parentNode") node.getStyle("paddingTop")
node.set("innerHTML", node.previous()
"Hello world!")
Bulk operaOons
Saturday, November 21, 2009
56. HTML Elements made easier Easie
(HTMLElement API improved) r
e
Nod
Supports Normalizes Enhances
node.appendChild(new) node.getAttribute("href") node.addClass("selectable")
node.cloneNode(node) node.contains(node) node.toggleClass("enabled")
node.scrollIntoView() node.getText() node.getXY()
node.get("parentNode") node.getStyle("paddingTop") node.get("region")
node.set("innerHTML", node.previous()
"Hello world!")
Bulk operaOons
Saturday, November 21, 2009
57. HTML Elements made easier Easie
(HTMLElement API improved) r
e
Nod
Supports Normalizes Enhances
node.appendChild(new) node.getAttribute("href") node.addClass("selectable")
node.cloneNode(node) node.contains(node) node.toggleClass("enabled")
node.scrollIntoView() node.getText() node.getXY()
node.get("parentNode") node.getStyle("paddingTop") node.get("region")
node.set("innerHTML", node.previous()
"Hello world!")
Bulk operaOons
var items = Y.Node.all(".actions li"); nodeList.filter(‘a[href]’);
items.addClass("disabled"); nodeList.odd();
items.set("title", "Item Disabled"); nodeList.even();
items.each(function(node) {
node.addClass("disabled);
node.set("title", "Item Disabled");
});
Saturday, November 21, 2009
58. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon
Node removal
Node ancestry
Saturday, November 21, 2009
59. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon Node removal
var fieldset =
document.createElement("fieldset"); Node ancestry
var input =
document.createElement("input");
input.type = "checkbox";
input.name = "myCheckBox";
...
fieldset.appendChild("input");
form.appendChild(fieldset);
Saturday, November 21, 2009
60. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon Node removal
var fieldset =
document.createElement("fieldset"); Node ancestry
var input =
document.createElement("input");
input.type = "checkbox";
input.name = "myCheckBox";
...
fieldset.appendChild("input");
form.appendChild(fieldset);
var html = '<fieldset><input
type="checkbox" ... ></fieldset>';
// create the node and append
var node = Y.node.create( html );
form.appendChild( node );
// or do it right away
form.append( html );
Saturday, November 21, 2009
61. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon Node removal
var fieldset = var parent = node.parentNode;
document.createElement("fieldset"); parent.removeChild( node );
var input =
document.createElement("input");
input.type = "checkbox";
input.name = "myCheckBox";
... Node ancestry
fieldset.appendChild("input");
form.appendChild(fieldset);
var html = '<fieldset><input
type="checkbox" ... ></fieldset>';
// create the node and append
var node = Y.node.create( html );
form.appendChild( node );
// or do it right away
form.append( html );
Saturday, November 21, 2009
62. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon Node removal
var fieldset = var parent = node.parentNode;
document.createElement("fieldset"); parent.removeChild( node );
var input =
document.createElement("input"); node.remove();
input.type = "checkbox";
input.name = "myCheckBox";
... Node ancestry
fieldset.appendChild("input");
form.appendChild(fieldset);
var html = '<fieldset><input
type="checkbox" ... ></fieldset>';
// create the node and append
var node = Y.node.create( html );
form.appendChild( node );
// or do it right away
form.append( html );
Saturday, November 21, 2009
63. CreaJon, removal, and ancestry Easie
(a couple of last points) r
e
Nod
Node creaOon Node removal
var fieldset = var parent = node.parentNode;
document.createElement("fieldset"); parent.removeChild( node );
var input =
document.createElement("input"); node.remove();
input.type = "checkbox";
input.name = "myCheckBox";
... Node ancestry
fieldset.appendChild("input");
form.appendChild(fieldset);
var root = li.ancestor('.root');
var html = '<fieldset><input
<ul class="root">
type="checkbox" ... ></fieldset>';
<li>One</li>
<li>Two</li>
// create the node and append
<li>
var node = Y.node.create( html );
<ul>
form.appendChild( node );
<li>Sub One</li>
<li>Sub Two</li>
// or do it right away
</ul>
form.append( html );
</li>
</ul>
Saturday, November 21, 2009
64. Sugar is sweet Easie
(and so are you) r
Saturday, November 21, 2009
65. Sugar is sweet Easie
(and so are you) r
Y.log Y.Object oop
Y.clone
Y.later Y.mix
Y.aggregate
Y.cached Y.merge
Y.augment
Y.UA Y.each
Y.extend
Y.Lang Y.bind
Y.Array ++
Saturday, November 21, 2009
67. Photo slideshow
(because pictures are pre*eh)
Saturday, November 21, 2009
68. Photo slideshow
(because pictures are pre*eh)
http://whimsical.nu/hack/openhacksea.php
Saturday, November 21, 2009
69. Photo slideshow
(because pictures are pre*eh)
Saturday, November 21, 2009
70. Photo slideshow
(because pictures are pre*eh)
The HTML
Datasource
Animation
Saturday, November 21, 2009
71. Photo slideshow
(because pictures are pre*eh)
<div id="show"><div id="current">
The HTML <?php echo $show ?>
</div></div>
Datasource <div id="imageDump" style="display: none;">
<?= $dump ?>
</div>
Animation
Saturday, November 21, 2009
72. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource
Animation
});
Saturday, November 21, 2009
73. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource
Animation
});
Saturday, November 21, 2009
74. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource var myDataSource = new Y.DataSource.Get({
source:"flickrcall.php?tag=openhacksea",
Animation scriptCallbackParam:'jsoncallback'
});
});
Saturday, November 21, 2009
75. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource var myDataSource = new Y.DataSource.Get({
source:"flickrcall.php?tag=openhacksea",
Animation scriptCallbackParam:'jsoncallback'
});
var myCallback = {
success: function(e){
// magic!
// (add stuff to a custom PhotoReel obj)
Y.later( 5000, myPhotoReel,
myPhotoReel.advance, Array( Y ), true );
}};
});
Saturday, November 21, 2009
76. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource var myDataSource = new Y.DataSource.Get({
source:"flickrcall.php?tag=openhacksea",
Animation scriptCallbackParam:'jsoncallback'
});
var myCallback = {
success: function(e){
// magic!
// (add stuff to a custom PhotoReel obj)
Y.later( 5000, myPhotoReel,
myPhotoReel.advance, Array( Y ), true );
}};
myDataSource.plug(Y.Plugin.DataSourceJSONSchema, {
schema: {
resultListLocator: "photos.photo",
resultFields: ["id", "owner", "secret", "server",
"farm", "title","ownername"]
}
});
});
Saturday, November 21, 2009
77. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource
Animation
});
Saturday, November 21, 2009
78. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource
Y.on( 'domready', function(e){
Animation myDataSource.sendRequest("", myCallback);
});
});
Saturday, November 21, 2009
79. Photo slideshow
(because pictures are pre*eh)
YUI().use("datasource","node","substitute","anim",
The HTML function(Y){ ...
Datasource
Animation
});
Saturday, November 21, 2009
86. Making life easier
(for you and for me and the enOre human race)
Saturday, November 21, 2009
87. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
Saturday, November 21, 2009
88. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
Saturday, November 21, 2009
89. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
YUI API DocumentaJon
h*p://developer.yahoo.com/yui/3/api/
Saturday, November 21, 2009
90. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
YUI API DocumentaJon
h*p://developer.yahoo.com/yui/3/api/
Saturday, November 21, 2009
91. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
YUI API DocumentaJon
h*p://developer.yahoo.com/yui/3/api/
YUI3 Gallery
h*p://yuilibrary.com/gallery/
Saturday, November 21, 2009
92. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
YUI API DocumentaJon
h*p://developer.yahoo.com/yui/3/api/
YUI3 Gallery
h*p://yuilibrary.com/gallery/
Saturday, November 21, 2009
93. Making life easier
(for you and for me and the enOre human race)
Tutorials, samples, and guides
h*p://developer.yahoo.com/yui/3/
YUI API DocumentaJon
h*p://developer.yahoo.com/yui/3/api/
YUI3 Gallery
h*p://yuilibrary.com/gallery/
YUI Forum
h*p://yuilibrary.com/forum/
Saturday, November 21, 2009
94. Go forth and hack!
Or, do you have any
quesOons?
http://whimsical.nu/hack/openhacksea.php
Angela Sabas
Frontend Engineer, Yahoo!
amari@yahoo-inc.com
http://whimsical.nu
@angelamaria
http://www.flickr.com/photos/bzedan/2905906576/
Saturday, November 21, 2009