Ссылки о веб-разработке за май 2009

Совсем забыл подитожить с круглыми краями.

Начало истории, продолжение и для тех кто не читает сообщество резюмирую тут.

Проблема ИЕ8 решена, спасибо [info]strixdzen за наводку. Решение как и ожидалось основано на :before и :after.

Итого:
— Лиса safari и chrome решают эту задачу с помошью css.
— Opera 9.5+ умеет в качестве фона показывать svg.
— ИЕ 6, 7 - expressions с добавлением 4-х дивов и их позиционированием по углам.
— ИЕ 8 :before и :after, одна картинка прям в content и еще одна в фон, итого четыре угла.

В результате если вас устраивают браузеры ИЕ 6+, FF 3+, Opera 9.5+, Safari 3+, Crome, то скруглить уголки на однотонном фоне можно добавлением одного класса или двух классов.

Наши css для ИЕ и остальных браузеров.

Решение на продакшене, пока нареканий нет.

Как заметил [info]harisov блок следует назвать g-round, меня это немного смущает, но думаю я доверюсь его опыту.

P.S. Всем спасибо, задача решена, до следующего раза.

Microsoft Silverlight vs Google Wave: Why Karma Matters (Sridhar/Zoho Blogs)

Web Storage Portability Layer: A Common API for Web Storage

As discussed in our Google Code Blog post on HTML5 for Gmail Mobile, Google's new version of Gmail for iPhone and Android-powered devices uses the Web Storage Portability Layer (WSPL) to let the same database code run on browsers that provide either Gears or HTML5 structured storage facilities. The WSPL consists of a collection of classes that provide asynchronous transactional access to both Gears and HTML5 databases and can be found on Project Hosting on Google Code.

There are five basic classes:

google.wspl.Statement - A parametrizable SQL statement class

google.wspl.Transaction - Used to execute one or more Statements with ACID properties

google.wspl.ResultSet - Arrays of JavaScript hash objects, where the hash key is the table column name

google.wspl.Database - A connection to the backing database, also provides transaction support

google.wspl.DatabaseFactory - Creates the appropriate HTML5 or Gears database implementation


Also included in the distribution is a simple note-taking application with a persistent database cache built using the WSPL library. This application (along with Gmail mobile for iPhone and Android-powered devices) is an example of the cache pattern for building offline web applications. In the cache pattern, we insert a browser-local cache into the web application to break the synchronous link between user actions in the browser and server-generated responses. Instead, as shown below, we have two data flows. First, entirely local to the device, contents flow from the cache to the UI while changes made by the user update the cache. In the second flow, the cache asynchronously forwards user changes to the web server and receives updates in response.

By using this architectural pattern, a web application can made tolerant of a flaky (or even absent) network connection!

We'll be available at the Developer Sandbox at Google I/O to discuss the cache pattern, HTML5 development and the WSPL library. Check it out! If you have questions or comments, please visit our discussion list.

By Robert Kroeger, Software Engineer - Mobile Team

Support for Mercurial Now Available for All Projects Hosted on Google Code

You may recall that we recently asked for help from some early testers of Mercurial on Project Hosting on Google Code. As of today, all of our Project Hosting users can make use of this added functionality. For full details, check out the Google Code Blog. Better still, if you happen to be joining us at Google I/O, stop by the Mercurial on Big Table Tech Talk to learn more.

By Leslie Hawthorn, Open Source Team

The Git Parable

DOM Core tests on desktop and mobile

Last week I’ve done the DOM Core tests in new browsers: IE8 final (in both IE8 and IE7 mode), Firefox 3.5b4, Safari 4.0, Chrome 1 and 2, and Opera 10a. I found no surprises.

After that I decided to continue with mobile browsers, of which I have 15 lying around on my desk. Unfortunately I could not test IE Mobile (old) because it supports only inline event handlers, Skyfire because it does not allow you to remove alerts, and the Opera runtime in the Vodafone widget manager for terrifyingly complicated reasons I still have to describe properly.

Still I managed to test the other twelve and found a few surprises.

On the Anonymity of Home/Work Location Pairs

On the Anonymity of Home/Work Location Pairs. Most people can be uniquely identified by the rough location of their home combined with the rough location of their work. US Census data shows that 5% of people can be uniquely identified by this combination even at just census tract level (1,500 people).

JS-Placemaker - geolocate texts in JavaScript

JS-Placemaker—geolocate texts in JavaScript. Chris Heilmann exposed Placemaker to JavaScript (JSONP) using a YQL execute table. Try his examples—I’m impressed that “My name is Jack London, I live in Ontario” returns just Ontario, demonstrating that Placemaker’s NLP is pretty well tuned.

Flickr Shapefiles Public Dataset 1.0

Flickr Shapefiles Public Dataset 1.0. Another awesome Geo dataset from the Yahoo! stable—this time it’s Flickr releasing shapefiles (geometrical shapes) for hundreds of thousands of places around the world, under the CC0 license which makes them essentially public domain. The shapes themselves have been crowdsourced from geocoded photos uploaded to Flickr, where users can “correct” the textual location assigned to each photo. Combine this with the GeoPlanet WOE data and you get a huge, free dataset describing the human geography of the world.

ECMAScript 5 Strict Mode, JSON, and More

Previously I analyzed ECMAScript 5's Object and Property system. This is a huge new aspect of the language and deserved its special consideration.

There are a number of other new features and APIs that need attention, as well. The largest of which are Strict Mode and native JSON support.

Strict Mode

Strict Mode is a new feature in ECMAScript 5 that allows you to place a program, or a function, in a "strict" operating context. This strict context prevents certain actions from being taken and throws more exceptions (generally providing the user with more information and a tapered-down coding experience).

Since ECMAScript 5 is backwards-compatible with ECMAScript 3, all of the "features" that were in ECMAScript 3 that were "deprecated" are just disabled (or throw errors) in strict mode, instead.

Strict mode helps out in a couple ways:

Most of the information about strict mode can be found in the ES5 specification [PDF] on page #223.

It should be noted that ECMAScript 5's strict mode is different from the strict mode available in Firefox (which can be turned on by going to about:config and enabled javascript.options.strict). ES5's strict mode complains about a completely different set of potential errors (whereas Firefox's existing strict mode tries to enforce some good practices, only).

How do you enable strict mode?

Simple. Toss this at the top of a program to enable it for the whole script:

"use strict";

Or place it within a function to turn on strict mode only within that context.

function imStrict(){
  "use strict";
  // ... your code ...
}

Note the syntax that's used to enable strict mode (I love this!). It's simply a string in a single statement that happens to contain the contents "use strict". No new syntax is introduced in order to enable strict mode. This is huge. This means that you can turn strict mode on in your scripts - today - and it'll have, at worst, no side effect in old browsers.

As you may note from the examples here and in the previous post there are virtually no new syntax additions or changes to the language in ECMAScript 5. This means that you can write your ES5 scripts in a manner that will be able to gracefully degrade for older useragents - something that wasn't possible with ECMAScript 4. The way in which strict mode is enabled is a great illustration of that point in practice.

A neat aspect of being able to define strict mode within a function is that you can now define complete JavaScript libraries in a strict manner without affecting outside code.

// Non-strict code...

(function(){
  "use strict";
 
  // Define your library strictly...
})();

// Non-strict code...
 

A number of libraries already use the above technique (wrapping the whole library with an anonymous self-executing function) and they will be able to take advantage of strict mode very easily.

So what changes when you put a script into strict mode? A number of things.

Variables and Properties

An attempt to assign foo = "bar"; where 'foo' hasn't been defined will fail. Previously it would assign the value to the foo property of the global object (e.g. window.foo), now it just throws an exception. This is definitely going to catch some annoying bugs.

Any attempts to write to a property whose writable attribute is set to false, delete a property whose configurable attribute is set to false, or add a property to an object whose extensible attribute is set to false will result in an error (these attributes were discussed previously). Traditionally no error will be thrown when any of these actions are attempted, it will just fail silently.

Deleting a variable, a function, or an argument will result in an error.

var foo = "test";
function test(){}

delete foo; // Error
delete test; // Error

function test2(arg) {
    delete arg; // Error
}

Defining a property more than once in an object literal will cause an exception to be thrown

// Error
{ foo: true, foo: false }

eval

Virtually any attempt to use the name 'eval' is prohibited - as is the ability to assign the eval function to a variable or a property of an object.

// All generate errors...
obj.eval = ...
obj.foo = eval;
var eval = ...;
for ( var eval in ... ) {}
function eval(){}
function test(eval){}
function(eval){}
new Function("eval")

Additionally, attempts to introduce new variables through an eval will be blocked.

eval("var a = false;");
print( typeof a ); // undefined
 

Functions

Attempting to overwrite the arguments object will result in an error:
arguments = [...]; // not allowed

Defining identically-named arguments will result in an error function( foo, foo ) {}.

Access to arguments.caller and arguments.callee now throw an exception. Thus any anonymous functions that you want to reference will need to be named, like so:

setTimeout(function later(){
  // do stuff...
  setTimeout( later, 1000 );
}, 1000 );

The arguments and caller properties of other functions no longer exist - and the ability to define them is prohibited.

function test(){
  function inner(){
    // Don't exist, either
    test.arguments = ...; // Error
    inner.caller = ...; // Error
  }
}

Finally, a long-standing (and very annoying) bug has been resolved: Cases where null or undefined is coerced into becoming the global object. Strict mode now prevents this from happening and throws an exception instead.

(function(){ ... }).call( null ); // Exception
 

with(){}

with(){} statements are dead when strict mode is enabled - in fact it even appears as a syntax error. While the feature was certainly mis-understood and possibly mis-used I'm not convinced that it's enough to be stricken from the record.

The changes made in ECMAScript 5 strict mode are certainly varied (ranging from imposing stylistic preferences, like removing with statements, to fixing legitimately bad language bugs, like the ability to redefine properties in object literals). It'll be interesting to see how people begin to adopt these points and how it'll change JavaScript development.

All that being said, I'm fairly certain that jQuery is ES5-Strict compatible right now. Once an implementation of the language is made available (so that that premise may be tested) I'll happily switch jQuery over to working exclusively in strict mode.

JSON

The second major feature of the language is the addition of native JSON support to the language.

I've been championing this move for a long time and I'm glad to see it finally arrive in a specification.

In the meantime PLEASE start migrating your JSON-using applications over to Crockford's json2.js. It is fully compatible with the ECMAScript 5 specification and gracefully degrades if a native (faster!) implementation exists.

In fact, I just landed a change in jQuery yesterday that utilizes the JSON.parse method if it exists, now that it has been completely specified.

There are two primary methods for handling JSON: JSON.parse (which converts a JSON string into a JavaScript object) and JSON.stringify (which convert a JavaScript object into a serialized string).

JSON.parse( text )

Converts a serialized JSON string into a JavaScript object.

var obj = JSON.parse('{"name":"John"}');
// Prints 'John'
print( obj.name );

JSON.parse( text, translate )

Use a translation function to convert values or remove them entirely.

function translate(key, value) {
  if ( key === "name" ) {
    return value + " Resig";
  }
}

var obj = JSON.parse('{"name":"John","last":"Resig"}', translate);
// Prints 'John Resig'
print( obj.name );

// Undefined
print( obj.last );

JSON.stringify( obj )

Convert an object into a serialized JSON string.

var str = JSON.stringify({ name: "John" });
// Prints {"name":"John"}
print( str );

JSON.stringify( obj, ["white", "list"])

Serialize only a specific white list of properties.

var list = ["name"];
var str = JSON.stringify({name: "John", last: "Resig"}, list);
// Prints {"name":"John"}
print( str );

JSON.stringify( obj, translate )

Serializes the object using a translation function.

function translate(key, value) {
  if ( key === "name" ) {
    return value + " Resig";
  }
}

var str = JSON.stringify({"name":"John","last":"Resig"}, translate);
// Prints {"name":"John Resig"}
print( str );

JSON.stringify( obj, null, 2 )

Adds the specified number of spaces to the output, printing it evenly.

var str = JSON.stringify({ name: "John" }, null, 2);
// Prints:
// {
//   "name": "John"
// }
print( str );

JSON.stringify( obj, null, "\t" )

Uses the specified string to do the spacing.

var str = JSON.stringify({ name: "John" }, null, "\t");
// Prints:
// {\n\t"name": "John"\n}
print( str );

Additionally, a few new generic methods have been added to some of the base objects but, frankly, they aren't that interesting. The results from String, Boolean, and Number are just equivalent to calling .valueOf() and the result from Date is equivalent to calling .toISOString()

// Yawn...
String.prototype.toJSON
Boolean.prototype.toJSON
Number.prototype.toJSON
Date.prototype.toJSON

.bind()

A welcomed addition to the language is a built-in .bind() method for enforcing the context of a function (virtually identical to Prototype's .bind implementation).

Function.prototype.bind(thisArg, arg1, arg2....)

Enforces the 'this' of the specified function to a specific object - and passing in any specified arguments.

var obj = {
  method: function(name){
    this.name = name;
  }
};

setTimeout( obj.method.bind(obj, "John"), 100 );

Considering how long this function (and its equivalents) have been around it's a welcome addition to the language.

Date

Dates are now capable of both parsing and outputting ISO-formatted dates. Thank goodness, about time. rimshot

The Date constructor now attempts to parse the date as if it was ISO-formatted, first, then moves on to the other inputs that it accepts.

Additionally, date objects now have a new .toISOString() method that outputs the date in an ISO format.

var date = new Date("2009-05-21T16:06:05.000Z");

// Prints 2009-05-21T16:06:05.000Z
print( date.toISOString() );

.trim()

A native, built-in, .trim() is now included for strings. Works identically to all the other trim methods out there - with the potential to possibly work faster.

Steven Levithan has discussed the trim method in great depth.

Array

The JavaScript Array Extras that've been around for, what seems like, forever are finally formally specified. This includes the following methods: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce, and reduceRight.

Additionally a new Array.isArray method is included, providing functionality very similar to the following:

Array.isArray = function( array ) {
  return Object.prototype.toString.call( array ) === "[object Array]";
};

Altogether I think ECMAScript 5 makes for an interesting package. It isn't the massive leap that ECMAScript 4 promised but it is a series of respectable improvements that reduces the number of obvious bugs while making the language safer and faster. I'm looking forward to when some implementations start to go public.

AWS Import/Export: Ship Us That Disk!

AWS Import/Export: Ship Us That Disk!. Andrew Tanenbaum said “Never underestimate the bandwidth of a station wagon full of tapes hurtling down the highway”, and now you can ship your storage device direct to Amazon and have them load the data in to an S3 bucket for you.

ECMAScript 5 Objects and Properties

ECMAScript 5 is on its way. Rising from the ashes of ECMAScript 4, which got scaled way back and became ECMAScript 3.1, which was then re-named ECMAScript 5 (more details)- comes a new layer of functionality built on top of our lovable ECMAScript 3.

Update: I've posted more details on ECMAScript 5 Strict Mode, JSON, and More.

There are a few new APIs included in the specification but the most interesting functionality comes into play in the Object/Property code. This new code gives you the ability to dramatically affect how users will be able to interact with your objects, allowing you to provide getters and setters, prevent enumeration, manipulation, or deletion, and even prevent the addition of new properties. In short: You will be able to replicate and expand upon the existing JavaScript-based APIs (such as the DOM) using nothing but JavaScript itself.

Perhaps best of all, though: These features are due to arrive in all major browsers. All the major browser vendors worked on this specification and have agreed to implement it in their respective engines. The exact timeframe isn't clear yet, but it's going to be sooner, rather than later.

There doesn't appear to exist a full implementation of ES5 at this point, but there are a few in the works. In the meantime you can read the ECMAScript 5 specification (PDF - I discuss pages 107-109 in this post) or watch the recent talk by some of the ECMAScript guys at Google.

Note: I've provided a couple simple, example, implementations for these methods to illustrate how they might operate. Almost all of them require other, new, methods to work correctly - and they are not implemented to match the specification 100% (for example there is no error checking).

Objects

A new feature of ECMAScript 5 is that the extensibility of objects can now be toggled. Turning off extensibility can prevent new properties from getting added to an object.

ES5 provides two methods for manipulating and verifying the extensibility of objects.

Object.preventExtensions( obj )
Object.isExtensible( obj )

preventExtensions locks down an object and prevents and future property additions from occurring. isExtensible is a way to determine the current extensibility of an object.

Example Usage:

var obj = {};

obj.name = "John";
print( obj.name );
// John

print( Object.isExtensible( obj ) );
// true

Object.preventExtensions( obj );

obj.url = "http://ejohn.org/"; // Exception in strict mode

print( Object.isExtensible( obj ) );
// false
 

Properties and Descriptors

Properties have been completely overhauled. No longer are they the simple value associated with an object - you now have complete control over how they can behave. With this power, though, comes increased complexity.

Object properties are broken down into two portions.

For the actual "meat" of a property there are two possibilities: A Value (a "Data" property - this is the traditional value that we know and love from ECMAScript 3) or a Getter and Setter (an "Accessor" property - we know this from some modern browsers, like Gecko and WebKit).

Additionally, properties can be...

Altogether these various attributes make up a property descriptor. For example, a simple descriptor might look something like the following:

{
  value: "test",
  writable: true,
  enumerable: true,
  configurable: true
}

The three attributes (writable, enumerable, and configurable) are all optional and all default to true. Thus, the only property that you'll need to provide will be, either, value or get and set.

You can use the new Object.getOwnPropertyDescriptor method to get at this information for an existing property on an object.

Object.getOwnPropertyDescriptor( obj, prop )

This method allows you to access the descriptor of a property. This method is the only way to get at this information (it is, otherwise, not available to the user - these don't exist as visible properties on the property, they're stored internally in the ECMAScript engine).

Example Usage:

var obj = { foo: "test" };

print(JSON.stringify(
  Object.getOwnPropertyDescriptor( obj, "foo" )
));
// {"value": "test", "writable": true,
//  "enumerable": true, "configurable": true}
 

Object.defineProperty( obj, prop, desc )

This method allows you to define a new property on an object (or change the descriptor of an existing property). This method accepts a property descriptor and uses it to initialize (or update) a property.

Example Usage:

var obj = {};

Object.defineProperty( obj, "value", {
  value: true,
  writable: false,
  enumerable: true,
  configurable: true
});

(function(){
  var name = "John";
 
  Object.defineProperty( obj, "name", {
    get: function(){ return name; },
    set: function(value){ name = value; }
  });
})();

print( obj.value )
// true

print( obj.name );
// John

obj.name = "Ted";
print( obj.name );
// Ted

for ( var prop in obj ) {
  print( prop );
}
// value
// name

obj.value = false; // Exception if in strict mode

Object.defineProperty( obj, "value", {
  writable: true,
  configurable: false
});

obj.value = false;
print( obj.value );
// false

delete obj.value; // Exception
 

Object.defineProperty is a core method of the new version of ECMAScript. Virtually all the other major features rely upon this method existing.

Object.defineProperties( obj, props )

A means of defining a number of properties simultaneously (instead of individually).

Example Implementation:

Object.defineProperties = function( obj, props ) {
  for ( var prop in props ) {
    Object.defineProperty( obj, prop, props[prop] );
  }
};

Example Usage:

var obj = {};

Object.defineProperties(obj, {
  "value": {
    value: true,
    writable: false
  },
  "name": {
    value: "John",
    writable: false
  }
});

Property descriptors (and their associated methods) is probably the most important new feature of ECMAScript 5. It gives developers the ability to have fine-grained control of their objects, prevent undesired tinkering, and maintaining a unified web-compatible API.

New Features

Building on top of these new additions some interesting new features have been introduced into the language.

The following two methods are very useful for collecting arrays of all the properties on an object.

Object.keys( obj )

Returns an array of strings representing all the enumerable property names of the object. This is identical to the method included in Prototype.js.

Example Implementation:

Object.keys = function( obj ) {
  var array = new Array();
  for ( var prop in obj ) {
    if ( obj.hasOwnProperty( prop ) ) {
      array.push( prop );
    }
  }
  return array;
};

Example Usage:

var obj = { name: "John", url: "http://ejohn.org/" };

print( Object.keys(obj).join(", ") );
// name, url
 

Object.getOwnPropertyNames( obj )

Nearly identical to Object.keys but returns all property names of the object (not just the enumerable ones).

An implementation isn't possible with regular ECMAScript since non-enumerable properties can't be enumerated. The output and usage is otherwise identical to Object.keys.

Object.create( proto, props )

Creates a new object whose prototype is equal to the value of proto and whose properties are set via Object.defineProperties( props ).

A simple implementation would look like this (requires the new Object.defineProperties method).

Example Implementation: (by Ben Newman)

Object.create = function( proto, props ) {
  var ctor = function( ps ) {
    if ( ps )
      Object.defineProperties( this, ps );
  };
  ctor.prototype = proto;
  return new ctor( props );
};

Other implementation:

Object.create = function( proto, props ) {
  var obj = new Object();
  obj.__proto__ = proto;

  if ( typeof props !== "undefined" ) {
    Object.defineProperties( obj, props );
  }
 
  return obj;
};

Note: The above code makes use of the Mozilla-specific __proto__ property. This property gives you access to the internal prototype of an object - and allows you to set its value, as well. The ES5 method Object.getPrototypeOf allows you to access this value but not set its value - thus the above method cannot be implement in a generic, spec-compatible, manner.

I discussed Object.getPrototypeOf previously so I won't bother discussing it again here.

Example Usage:

function User(){}
User.prototype.name = "Anonymous";
User.prototype.url = "http://google.com/";

var john = Object.create(new User(), {
  name: { value: "John", writable: false },
  url: { value: "http://google.com/" }
});

print( john.name );
// John

john.name = "Ted"; // Exception if in strict mode
 

Object.seal( obj )
Object.isSealed( obj )

Sealing an object prevents other code from deleting, or changing the descriptors of, any of the object's properties - and from adding new properties.

Example Implementation:

Object.seal = function( obj ) {
  var props = Object.getOwnPropertyNames( obj );
 
  for ( var i = 0; i < props.length; i++ ) {
    var desc = Object.getOwnPropertyDescriptor( obj, props[i] );
   
    desc.configurable = false;
    Object.defineProperty( obj, props[i], desc );
  }
 
  return Object.preventExtensions( obj );
};

You would seal an object if you want its existing properties to stay intact, without allowing for new additions, but while still allowing the user to write to or edit the properties.

Object.freeze( obj )
Object.isFrozen( obj )

Freezing an object is nearly identical to sealing it but with the addition of making the properties un-editable.

Example Implementation:

Object.freeze = function( obj ) {
  var props = Object.getOwnPropertyNames( obj );
 
  for ( var i = 0; i < props.length; i++ ) {
    var desc = Object.getOwnPropertyDescriptor( obj, props[i] );
   
    if ( "value" in desc ) {
      desc.writable = false;
    }
   
    desc.configurable = false;
    Object.defineProperty( obj, props[i], desc );
  }
 
  return Object.preventExtensions( obj );
};

Freezing an object is the ultimate form of lock-down. Once an object has been frozen it cannot be unfrozen - nor can it be tampered in any manner. This is the best way to make sure that your objects will stay exactly as you left them, indefinitely.

All together these changes are very exciting, they provide you with an unprecedented level of control over the objects that you produce. The best aspect, though, is that you will be able to use these features to build larger and more complex features in pure ECMAScript (such as building new DOM modules, or moving more browser APIs into pure-JavaScript). And since all the browsers are on board this is absolutely something that we can look forward to.

Yahoo! Placemaker

Yahoo! Placemaker. Really exciting new API from Yahoo!—Placemaker accepts a block of text (or a URL to HTML or RSS) and extracts and returns geographical locations mentioned in the text. I just ran my djng blog entry through it and it pulled out “Prague” as the only location mentioned. This should be really useful for adding geodata to existing textual content.

the day supporting document.onload became a bug

Like many things on the web, the load event seems simple. It originates from the web's stone age - supported by Netscape 2 in 1996 and fired billions and billions of times since. It's probably the most widely used event for web scripting. Can it have secrets or quirks after so many years?

You might think you could write a one-sentence spec for it, along the lines of "when the document is done loading, dispatch a load event to any listeners created from BODY onload attributes, window.onload property or addEventListener('load') calls" - and implement it interoperably in a few hours on top of an otherwise solid DOM/JS core.

Simplicity is deception. Actually, the cool thing about the load event is that it seems so simple but is so weird.

Discovering what I didn't know about the load event started at the white "please wait" box that covers the contents on grainger.com (this site is now patched in browser.js)



I noticed that they did something like
document.onload=function(){
// code that shows the "please wait" box, an obvious mistake
}
.
.
<body onload="">


Aha: if you assign a listener for the document's load event but afterwards have an empty onload attribute on body, document.onload will be removed when the browser sees onload="". Right? I wrote a test case confirming that assumption and moved on to the next bug.

However, colleague Ola was also looking at the bug and could prove that the onload="" was a red herring. Removing it made no difference. Assigning anything to document.onload was a no-op in all other browsers. What?? How come we never noticed that?

So, we got a developer to remove document.onload support. I wanted it fixed by just ignoring assignments to document.onload, but being a thorough person Daniel made sure document would no longer be an event target for the load event.

To my consolation I wasn't the only person saying that must be wrong! This fix makes document.addEventListener('load'...) a no-op too. We're absolutely sure document.addEventListener('load'...) must keep working. The DOM Events spec doesn't say much about the load event, but it sort of implies sending it to the document. Besides, not sending load events to document anymore broke opera:config and dozens of browser.js patches.

Then we wrote another test case or two.

And it's true. No browser (except Opera) sends load events to "document"! They all skip document and go straight for window. BODY onload="" creates listeners on window, not on body. Even though event.target is the document, the event itself avoids the document like it had swine flu or something.

I assume it's been like that since 1996 and we never thought of testing that in other browsers before. Wow.

So, early afternoon on May 12th 2009, our support for document.onload turned from a feature into a bug. Good bye to the possibility of capturing all load events inside a document with a capturing listener (won't work with window.addEventListener because Mozilla turned out to be a chicken and not a dinosaur). Edit: luckily I was wrong here, see comments.

Actually it feels a bit .. evil .. to suddenly turn around and kill an old feature that's been with us for years, just because it's required for web compatibility. Oh well. At least I can confirm that you learn something old every day..

A note on testing methodology

In his recent Feature testing CSS properties entry, Juriy Zaytsev (Kangax) discusses the possibility of detecting CSS support by means of JavaScript. Although he rightly points out that this method has its drawbacks, as far as I’m concerned he doesn’t go far enough.

This sort of testing should not be used at all. Ever. The methodology is plain wrong. Browser compatibility tests are to be done by hand. Any automated system is useless, because it will give false information.

aws - simple access to Amazon EC2 and S3

aws—simple access to Amazon EC2 and S3. The best command line client I’ve found for EC2 and S3. “aws put --progress my-bucket-name/large-file.tar.gz large-file.tar.gz” is particularly useful for uploading large files to S3. Written in Perl (with no dependencies), shelling out to curl to do the heavy lifting.

Facebook Launches OpenID Support - Users Can Now Login With Gmail Accounts

resty

resty. 58 lines of bash provides a better command-line interface to RESTful APIs, using curl under the hood. This should save me from running “man curl” several times a week.

python-daemon

python-daemon (via). A library for correctly creating Unix daemon processes in Python, implementing the proposed PEP 3143 API.

крик души

когда уже в багзилле будет поддержка openid?! Надоело регистрироваться на каждом сайте разработчика. Давайте проголосуем за этот запрос, что ли: «Support OpenID as a an account source and login verification method»

и опять программистское

После того, как полгода не касался Джавы, думаешь: ну ладно, ну подумаешь, все не так противно, как ты помнишь... и с размаху рожей в строчку типа:

SomethingDataModel somethingDataModel = new SomethingDataModel();

Мда.

Google and JanRain Release Support for the OpenID User Interface Extension

This morning, Google released an upgrade to their OpenID Provider to support the draft OpenID User Interface Extension along with JanRain who added support for it to their Relying Party service RPX. This means that Google users signing into sites like UserVoice (choose “Google” to see it in action) now have a much better user experience; one much closer to that of Facebook Connect. Google also allows users to choose to share their profile information with Relying Parties via OpenID Attribute Exchange and the Google Data APIs via OAuth.

The OpenID User Interface Extension is one of the main pieces of work that has come from the OpenID Design Summit hosted by Facebook earlier this year. The extension replaces the traditional OpenID sign in flow of being redirected from the Relying Party to the OpenID Provider with a popup window which shows the URL bar on top of the Relying Party itself.

The Google Code Blog writes about their implementation in more detail:

The new popup style UI, which implements the OpenID User Interface Extension Specification, is designed to streamline the federated login experience for users. Specifically, it’s designed to ensure that the context of the Relying Party website is always available and visible, even in the extreme case where a confused user closes the Google approval window. JanRain, a provider of OpenID solutions, is an early adopter of the new API, and already offers it as part of their RPX product. As demonstrated by UserVoice using JanRain’s RPX, the initial step on the sign-in page of the Relying Party website is identical to that of the “full page” version, and does not require any changes in the Relying Party UI.


Once the user selects to sign in using his or her Google Account, the Google approval page is displayed. However, it does not replace the Relying Party’s page in the main browser window. Instead it is displayed as a popup window on top of it. We have updated our Open Source project to include a complete Relying Party example, providing code for both the back-end (in Java) and front-end (javascript) components.


Once the user approves the request, the popup page closes, and the user is signed in to the Relying Party website.

User experience continues to be one of our key priorities for the community and foundation this year, and progress like seeing Google and JanRain ship the first implementation of the OpenID popup flow is demonstrating that we’ve been able to seize the momentum coming into this year and make real progress in a short period of time.

We’re looking forward to discussing this and other initiatives at the Internet Identity Workshop this coming Monday.

Do not remove the outline from links and form controls

An addition to my post Don’t forget keyboard navigation is that you should never use the outline CSS property to remove the indicator that most browsers display when a focusable element receives keyboard focus.

I’ve seen quite a few tips on how to remove the focus indicator by using outline:none or outline:0. Please do not do this, unless you replace the outline with something else that makes it easy to see which element has keyboard focus. Removing the visual indicator of keyboard focus will give people who rely on keyboard navigation a really hard time navigating and using your site.

Another, even worse, way of removing the focus indicator is to use a JavaScript onfocus event to remove focus as soon as a link or other element receives focus, making it impossible to use the page without a mouse. Never, ever do this.

Further reading:

This post is a Quick Tip. Background info is available in Quick Tips for web developers and web designers.

Posted in , , .

Interview with Ian Hickson, editor of the HTML 5 specification

Interview with Ian Hickson, editor of the HTML 5 specification. By Bruce Lawson of the Web Standards Project. Worth reading.

Разработка / 10 приемов, разрушающих хрупкую красоту кода

Статья публикуется специально для Хабрахабра.

Из-за какого-то непонятного ограничение на объем статьи — приводится в сокращении.

Полная версия статьи — у меня на сайте.


Для меня программирование — это не только технология, но и, во многом — искусство. И, поэтому, большое значение имеет красота кода.

Последние несколько лет я собирал приемы программирования, разрушающие в программном коде его утонченную красоту:


  1. Объявление всех переменных в начале программы;
  2. Возврат результата функции через ее параметр;
  3. Отсутствие локальных функций;
  4. Отсутствие else if;
  5. Использование параллельных массивов;
  6. Хранение размера массива в отдельной переменной;
  7. Доступ к свойствам объекта через obj.getProperty() и obj.setProperty(value);
  8. Использование рекурсии для вычисления факториалов и Чисел Фибоначчи;
  9. Отсутствие именованных параметров функции;
  10. Невозможность объявления объектов «на лету».


Наверняка, в некоторых местах вы будете со мной несогласны — ведь чувство красоты у всех разное.

Объявление всех переменных в начале программы



В двух словах:


Переменные должны объявляться в начале логического блока, в котором они используются, а НЕ в начале функции или программы.




Читать дальше →

Google to support Microformats and RDFa to produce "Rich snippets" Howto: http://bit.ly/R7K8x Interview w creators: http://bit.ly/2IUth

Просто цитатка

In 1980, computer engineering was based on starting with clearly-defined things (primitives or small programs) and using them to build larger things that ended up being clearly-defined. Composition of these fragments was the name of the game.

However, nowadays, a real engineer is given a big software library, with a 300-page manual that’s full of errors. He’s also given a robot, whose exact behavior is extremely hard to characterize (what happens when a wheel slips?). The engineer must learn to perform scientific experiments to find out how the software and hardware actually work, at least enough to accomplish the job at hand. Gerry pointed out that we may not like it this way (”because we’re old fogies”), but that’s the way it is, and M.I.T. has to take that into account.
Выделение моё.

PS: via LTU, тема про то, почему MIT перешёл на Python в курсе SICP.

аддоны для оперы

читатели блога наверняка давно заметили, что одна из самых популярных тем здесь — юзерскрипты. (Кстати, называть их гризманки-скриптами неграмотно.) К сожалению, интерфейсная поддержка этой мощной функциональности в опере хромает: всего-то можно указать папку с ними и переопределить её для отдельных сайтов. Конечно, это не мешает решать те же самые задачи, но так они занимают немного больше времени, чем в том же гризманки.

поскольку у нас пока ещё нет возможности писать под оперу такие же аддоны, как под фф, с проблемой юзерскриптов поделать ничего нельзя. Хотя постойте! Можно делать под оперу виджеты, а для них ещё год назад заявляли поддержку File I/O. Значит, можно сделать виджет, который даст удобный интерфейс управления скриптами! И не только ими, можно много чего навертеть, почти как для фф…

да, действительно можно. И оно даже будет работать. Но как тег video и 3d canvas. То есть, только в экспериментальном билде : (

[whatwg] Annotating structured data that HTML has no semantics for

[whatwg] Annotating structured data that HTML has no semantics for. Hixie’s proposal for microdata, a simplified RDFa to be included in the HTML5 spec which allows self-contained communities to invent their own microformat-style spec and use it to add structured semantics to their markup. Whether or not you like the proposal itself the explanation is a fascinating read.

ссылка: разработчики библиотек о html5

InfoQ провёл виртуальный «открытый стол» с разработчиками популярных javascript-библиотек на тему перспективности для них новых возможностей html5. Участвуют:

особенно интересно, что говорится не столько о тонких технических подробностях, сколько о глобальных подходах, об общем ви́дении

via Andrew Dupont

stet - Trac

как не качать deb-пакеты дважды

быстрый рецепт

когда вышел Ubunty 9.04 Jaunty Jackalope, я немедленно скачал torrent официального DVD и положил в папочку. А памятуя прошлые обновления, когда новые версии пакетов тянулись с официальных серверов в час по чайной ложке, решил в этот раз использовать пакеты с диска. Но мне вовсе не хотелось вначале записывать образ на болванку, а потом слушать урчание привода, который всяко медленнее винчестера. Казалось бы, что может быть проще — примонтировать iso в файловую систему и указать инсталлятору на неё. Но не тут-то было!

во время предыдущего обновления я безуспешно пытался проделать эту операцию. Однако в этот раз я решил пойти до конца. Вначале создал каталог /media/ubuntu. Работать с iso-образами я предпочитаю через гуй простенькой программки gmount-iso, но того же можно добиться и через /etc/fstab:

/media/l-large/ubuntu-9.04-dvd-i386.iso /media/ubuntu udf,iso9660 noauto,loop

вручную вставить диск в инсталлятор невозможно, о чём предупреждает man apt-cdrom, поэтому положимся на него:

sudo apt-cdrom -d /media/ubuntu add

он зачем-то отмонтирует диск и попросит «вставить» его снова, но это не создаёт особых трудностей : )

после этих операций в /etc/apt/sources.list появилась запись:

deb cdrom:[Ubuntu 9.04 _Jaunty Jackalope_ - Release i386 (20090421.3)]/ jaunty main restricted

тут я обрадовался и запустил инсталлятор. Тот пошуршал байтами и попросил меня вставить диск в привод /cdrom/. «Ага!», — сказали мужики и задумались. Именно в этом месте я забил в прошлый раз. Но сейчас на глаза мне попалась строчка из мана apt-cdrom: «Configuration Item: Acquire::cdrom::mount.» Что-то похоже я уже видел в настройках apt. Например, в /etc/apt/apt.conf.d/10periodic:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "0";
APT::Periodic::Unattended-Upgrade "1";

Дальше было просто. Я создал файл /etc/apt/apt.conf.d/35cdrom с одной строчкой:

Acquire::cdrom::mount "/media/ubuntu/";

после этого пакеты ставились и продолжают ставиться большей частью с диска: «Need to get 929kB/5920kB of archives.» Впрочем, локально того же эффекта можно было добиться, указав эту опцию в командной строке к dist-upgrade:

sudo apt-get dist-upgrade -o Acquire::cdrom::mount="/media/ubuntu/"

итак, кратко то же самое (от рута):

# mkdir /media/ubuntu
# echo "/media/l-large/ubuntu-9.04-dvd-i386.iso /media/ubuntu udf,iso9660 noauto,loop" >> /etc/fstab
# sudo apt-cdrom -d /media/ubuntu add 
# echo 'Acquire::cdrom::mount "/media/ubuntu/";\n' >> /etc/apt/apt.conf.d/35cdrom

ps: собравшись опубликовать это на хабре, обнаружил там быстрый рецепт для обновления с сиди:

/cdmountpoint/cdromupgrade

browsers market share

за последнюю неделю мне пришли две новости, из которых можно сделать интересный вывод. Первая — про 270 миллионов пользователей Firefox (via). Вторая — про 35-40 миллионов пользователей Opera. Методики подсчёта у них приблизительно одинаковые, и, конечно, мы обеим компаниям верим ; )

впрочем, почему бы не проверить? Что говорят глобальные сервисы статистики на эту тему? W3Schools считает только своих посетителей, которые в большинстве своём веб-разработчики, поэтому даже не буду смотреть его сторону. Ещё есть, например, Net Applications и StatCounter. Первый из них — в своём роде Alexa — известный, древний и однобокий (подсчитывает преимущественно американские сайты). А вот второй показывает лучшее соответствие заявкам компаний. Получается 30%/270млн у фф, 3%/27млн у оперы и 2%.20млн у хрома, который ещё в конце года рапортовал как раз 10 миллионов

в общем, можно не верить StatCounter'у и Опере, а можно не верить только Net Applications. Жаль только, что блоггеры обычно хватают только первые попавшиеся цифры, и чаще всего ими оказываются данные именно NA

Читай код

Эту статью я написал по просьбе организаторов специально для сайта конференции software people. Опубликована здесь: http://www.softwarepeople.ru/press/articles/09/

Когда я заступил на работу в компанию CQG в конце 1999 года, у меня уже был, как мне казалось, достаточно большой опыт в разработке ПО – три года создания корпоративных приложений БД под заказ. Мне уже казалось, что я очень много знаю и умею, и я был крайне самоуверен. Однако, возникла некоторая загвоздка – CQG не являлось приложением баз данных, основанном на комбинации готовых сторонних технологий, таких как MS SQL сервер, Visual Basic, Delphi, JavaScript, и 1C – к которым я привык. Меня потряс объем приложения – почти 50 мегабайт основных исходников, не считая свистулек, прибамбасов, разного рода служебных и системных штук, по размеру почему-то превосходящих размер основных исходников.


Это был действительно серьезный и успешный программный комплекс, разрабатывавшийся десятками людей на тот момент на протяжении десяти лет, целиком написанный на С++, со своим собственным специализированным сервером БД, собственным встроенным языком программирования, собственным толстым клиентом, умеющим все, что может и не может пожелать трейдер, отказоустойчивый, работающий в реальном времени, сервера которого развернуты на ферме из сотен компьютеров и обслуживали порядка десятка тысяч пользователей одновременно.

Задание, которое мне было выдано, предполагало модификацию движка обработки данных и сервера, подкупало своей простотой, и практически свело меня с ума – завершить его я смог только через 7 месяцев после начала работ, после того, как прослушал лекции по архитектуре данного комплекса. Что характерно, после лекций пришлось выкинуть все, что я написал до них, и за два месяца сделать правильно.

В этот раз, перед тем, как что-либо писать, я предусмотрительно показал свой предварительный дизайн (подход к решению проблемы) Толу Корину (Tal Korin), автору и главному архитектору данной системы, и он направил меня в правильном направлении. У Тола ушло на это 5 минут. Это был первый случай, когда я сам инициировал дизайн-ревью (не зная, как оно называется), и был рад найденным у меня проблемам. После успешного выполнения данного задания я поступил в распоряжение Тола Корина, поскольку, с его слов и к моему безмерному удивлению, я оказался одним из немногих, кому пошли впрок лекции по архитектуре.

Каких-либо иллюзий на свой счет, меж тем, к тому моменту у меня уже не осталось – я понял, что цена всем моим знаниям, университетскому образованию, и опыту – ломаный грош. Меня поражал простой факт – я был объективно образован в Computer Science гораздо лучше Тола, и _знал_ больше. При этом, и, после некоторого опыта работы, я был в этом абсолютно уверен – я бы не смог спроектировать и реализовать такую систему за год, как это десять лет назад с одним помощником сделал Тол. Сложность системы явно превосходила мои возможности - я бы по ходу работы закопался в деталях. И уж тем более, у меня не получилось сделать систему так гибко, чтобы она прожила 10 лет, и была до сих пор адекватна ситуации.

То есть, до меня начало доходить, что есть нечто очень важное, что совершенно перпендикулярно университетскому образованию, чего нас просто не учили даже замечать. Оно перпендикулярно «дизайн-паттернам» и книгам по ОО проектированию. И оно, это нечто, у Тола есть, а у меня – нет. Если мои знания не могут мне помочь сделать такую систему – то много ли они стоят? Понимание и знание требуется для действия, ни для чего другого – это не китайская декоративная ваза.

С этого момента я начал внимательно наблюдать за Толом, изучать его решения и подход, и твердо решил разобраться, что же это такое за неуловимая штука, которой я не понимаю. То есть, я «записался в ученики», и Тол с удовольствием взял роль наставника. И за несколько лет Тол сделал меня инженером, показав мне на практике, что это такое, и за что я ему буду всегда благодарен.

По большей части это напоминало дзен, когда вам дают задание, разрывающее мозг, вроде хлопка одной ладонью, и через некоторое время вы неожиданно ловите просветление. Удивительный опыт. Вот один небольшой пример, на что это было похоже.
- Тол, скажи, а как работает вот эта штука.
- Влад, вот этого я на самом деле не знаю. А ты почитай код, и разберись!
- Тол, ты издеваешься надо мной?! Здесь пятьдесят мегабайт этого гребанного недокументированного кода! Ты знаешь все Тол, и это ни для кого не секрет.
- Хорошо, смотри, – не стал спорить Тол, - Я тебе говорю – я не знаю, и поэтому я должен сам почитать код, чтобы ответить на твой вопрос. Поэтому, я открываю код.
Тол открывает правильный файл в одну попытку, продираясь через файловую систему, не пользуясь класс-браузером, мотает файл в правильную середину.
- Так. Ты сказал, вот эта фигня? Вот, открыл. Так… Тебе нужен вот этот метод. Читаем. Вот, смотри, он вызывает вот этого парня (так Тол называл классы и объекты – look – now this guy tell that guy to do this thing). Видишь? Вот, происходит тут то-то и то-то. Все просто.
- Спасибо, Тол! Теперь все ясно. А говорил – не знаешь!
- Я тебе говорю – код читай, блин! Все то же самое ты можешь сделать сам!
- Тол, ну в нем же нихрена не понятно без документации, - сказал я, будучи совершенно уверен, что я не смогу сделать того же сам. Происходящее напоминало ловкий фокус.
- Тебе, чтобы читать код, нужна документация? Прости – какая?
- Ну, там, диаграммы классов, например.
- У нас была одна, вроде, составленная лет пять назад. Она сейчас, мягко говоря, не соответствует действительности. Сам понимаешь, у нас 50 инженеров, и разработка идет очень активная. Но если ты уверен, что она тебе поможет, я могу поискать, – участливо смотрит на меня Тол, - ну так что, искать?
- Не, устаревшая, мне, пожалуй, не поможет, - подумав, ответил я, - это ж я все равно должен весь код изучить, чтобы понять, где ей можно доверять, а где нет.
- На самом деле, я не уверен, что тебе сильно поможет даже новая, и поэтому я тебе и говорю: код – лучшая документация! – терпеливо разъясняет Тол, - Она _всегда_ актуальна, и _никогда_ не устаревает, помимо того, что более информативна чем диаграмма классов, конечно.
- Хорошо, я понял, а может, ты мне еще объяснишь, вот в этом месте как работает…
- Нет. Это ты мне объяснишь, после того, как прочтешь. Мне как раз надо скоро будет туда правки вносить. Давай, парень, я не тебя рассчитываю. Иди - читай код.
- Хорошо, Тол, – обреченно сказал я, и пошел читать код.

Да, надо сказать, я тогда немного обиделся на Тола, я думал, что он нифига не понимает. И долгое время считал, что он был не прав. Как-то года через три ко мне подошел коллега, с вопросом. Я был утомлен от работы, голова соображала вяло. К этому моменту я выкинул все свои диаграммы классов, за ненадобностью – зачем на них смотреть, если они давно уже в голове?

- Слушай, Влад, не поможешь, объясни, как работает вот эта подсистема?
Я вяло поднимаю глаза на коллегу, вижу безнадежность в его взгляде, тяжело вздыхаю, и решаю ему помочь. Хоть я ничего и не понимаю в этой подсистеме – так, рядом проходил.
- Хорошо, смотри, – тут я «вслепую», без всяких класс-браузеров, продираюсь к «правильному» файлу, открываю его, и поиском нахожу нужный метод, - видишь, вот здесь что происходит?

Я читаю код, без труда восстанавливая логику поведения и структуру программы в уме, и одновременно простыми словами объясняю это коллеге. Тут у меня в голове что-то перещелкивает, и я с изумлением вспоминаю наш разговор с Толом трехлетней давности, сознание у меня как бы раздваивается, и я наблюдаю за собой со стороны.

- Вот, видишь, как все просто, - заканчиваю я. И к своему чудовищному удивлению добавляю, то, что надо сказать, потому что это правда:
- А вообще - читай код. Код – лучшая документация. Ты вот думаешь, я разбираюсь в этой подсистеме? Нет, я этот код вижу в первый раз, так же как и ты.
- Но этот код совершенно не документирован! Диаграммы хоть какие-нибудь бы!
- Смотри, - говорю я улыбаясь, окончательно осознавая, что Тол в очередной раз, как и всегда, оказался прав, - вот я запускаю Rational Rose, где у меня всосана вся наша система в режиме reverse engineering, и бросаю на чистый лист эти пять классов. Видишь? Вот тебе свежая, актуальная диаграмма. Какой смысл тратить усилия на документирование того, что устаревает за год, и может быть в любой момент восстановлено за пару минут? Если она тебе сильно поможет, я сейчас ее тебе распечатаю. Распечатать?
- Да нет, пожалуй, - задумчиво отвечает коллега, рассматривая диаграмму. Ясности она не добавляла.
- Вот. Диаграммы не стоят ничего, ценны мыслительные процессы, происходящие у тебя в голове в процессе их составления. Поэтому я и говорю: код – лучшая документация. Читай код.

Разумеется, Тол хотел мне показать не только и не столько практическую бесполезность проектной документации, как это могло показалось на первый взгляд. Философия "код - лучшая документация" дает гораздо большее, чем отсутствие документации. Это необходимое ограничение, только приняв и осознав которое, и в результате - рассчитывая только на свои силы, понимая - что код - основной источник информации, его нельзя боятся, с ним надо столкнуться в лоб, и этого не получится избежать, обойти, и перепрыгнуть, - можно достичь мастерства в reverse engineering и вообще понять, что это такое.

Создать свою структуру и пришлепать ее сбоку может любой дурак. Квалифицированный инженер-программист (с упором на первом слове, не путать с "программером") умеет проводить анализ "чужой" подсистемы, восстановит мысль и идею автора, сможет мысль автора развить, продолжить ее, и эффективно решить свою задачу в рамках чужого подхода к проблеме. Все это - работая с кодом. Это отличительная компетенция архитектора, высший уровень инженерного мастерства. И это имеет весьма отдаленное отношение к "рефакторингу".

Толу на самом деле было все равно, есть документация или нет. В совершенстве владея reverse engineering, он в уме потрясающе легко умел переходить от кода к архитектуре, и наоборот. В результате, проектируя, он всегда детально представлял, в какой код превратятся его мысли, и поэтому был способен быстро прокручивать в голове огромное количество вариантов, отбрасывая "плохие". В его понимании, архитектор, не умеющий читать чужой код с "листа", и не пишущий своего - подобен инвалиду, пытающемуся бегать на костылях. Он довольно быстро закончит очень плохим архитектором - вопрос нескольких лет.

Второй важный аспект этой философии - понимание того, что код пишется в первую очередь для человека, и только во вторую - для компьютера. Это приводит нас к идеям, близким по духу к literate programming, за которое ратует Кнут. Как может человек, который не в состоянии внятно выразить свою мысль на неформальном, знакомом ему с детства естественном языке, выразить эту же мысль понятным образом на существенно более формальном языке программирования? Но это уже другая история.

"Стандарт, который так легко растягивается, — гондон, а не стандарт."

“Стандарт, который так легко растягивается, — гондон, а не стандарт.”

- Влад Головач в книге «Дизайн пользовательского интерфейса II»

An Antic Disposition: Update on ODF Spreadsheet Interoperability - http://www.robweir.com/blog/2009/05/update-on-odf-spreadsheet.html

Системы управления версиями / Ссылка Линус Торвальдс о GIT на Google Talks [перевод]

Ровно два года назад Линус сделал знаменательный доклад о преимуществах распределенных систем контроля версий над централизованными, в частности Git над SVN. На youtube есть видео, но оно [imho] неразборчивое, доклад долгий, английский Линуса не прост — в общем, не все в состоянии его осилить. Предлагаю перевод-стенограмму (по переводу — претензии мне) доклада вместе с слайдами и другими кадрами видео. Посмотрите/проникнитесь/посмейтесь…

DVCSAnalysis - support - Analysis of Git and Mercurial - Google Code

новый метод-глагол для http

все веб-разработчики знают про GET/POST, многие — ещё и про PUT/DELETE. Я также наслышан о том, что WebDav добавляет несколько специфичных для себя методов. Но тут внезапно! обнаруживаю в статье «REST worst practices» отсылку к новому глаголу PATCH, черновик спеки которого уже почти готов. Предполагается, что этот метод будет использоваться очень широко, потому что решает очень общую задачу: обновление только части объекта. Проблема в том, что PUT заменяет объект полностью, а иногда удобнее исправить только одну небольшую часть. Очень разумное предложение, буду ждать выхода стандарта

← предыдущий месяц