general spec of location?
		if (submorph.isEpimorph) return;
		this.layout(supermorph);
		this.adjustShapeBoundsToSubmorphBounds(supermorph)
    },
    afterRemoveMorph: function($super, supermorph, submorph) {
		if (submorph.isEpimorph) return;
		this.layout(supermorph);
		this.adjustShapeBoundsToSubmorphBounds(supermorph)
		supermorph.layoutChanged();
    },
	submorphExtentChanged: function(supermorph, submorph) {
		if (submorph.isEpimorph) return;
	
		var newExtent = submorph.getExtent();
		var cachedExtent = this.getCachedExtent(supermorph, submorph)
		if (!cachedExtent ||  !(cachedExtent.eqPt(newExtent))) {
			this.setCachedExtent(supermorph, submorph, newExtent)
			this.layout(supermorph);
			this.adjustShapeBoundsToSubmorphBounds(supermorph);
		}
	},
	layout: function($super, supermorph, submorph) {
		// console.log('full layout ' + supermorph.id());
		// logStack();
		$super(supermorph, submorph)
	}	
}
VerticalLayout.subclass('VerticalShrinkLayout', ShrinkTrait);
Object.extend(VerticalShrinkLayout, { 
	fromLiteral: function(literal) { return new this() } 
})
HorizontalLayout.subclass('HorizontalShrinkLayout', ShrinkTrait)
Object.extend(HorizontalShrinkLayout, { 
	fromLiteral: function(literal) { return new this() } 
})
// splitArrayIntoPiecesOfLength([1,2,3,4,5,6,7], 3) -> [[1, 2, 3], [4, 5, 6], [7]]
splitArrayIntoPiecesOfLength = function(array, n) {
	return array.inject([[]], function(a, ea) {
		var last = a.last()
		if(last.length == n) {
			last = [];
			a.push(last)
		}
		last.push(ea)
		return a
	})
}
BoxMorph.subclass("ShrinkBoxMorph", {
	layoutManager: new HorizontalShrinkLayout(),
	style: {fill: Color.white, fillOpacity: 0},
	layoutChanged: function($super) {
		$super();
		if (this.owner && this.owner.submorphExtentChanged)
			this.owner.submorphExtentChanged(this);
	},
	submorphExtentChanged: function(submorph) {
		if (this.layoutManager && this.layoutManager.submorphExtentChanged)
			this.layoutManager.submorphExtentChanged(this, submorph)
	},
})
ShrinkBoxMorph.subclass("ResourceNodeMorph", {
	defaultExtent: pt(120,40),
	padding: new Rectangle(5,5,0,0),
	margin: new Rectangle(5,3,0,0),
	initialize: function($super, url, optPosition, optLevel) {
		var pos = optPosition || pt(0,0);
		$super(pos.extent(this.defaultExtent))
		this.setFill(Color.blue.darker());
		this.setFillOpacity(0.3)
		this.setBorderColor(Color.darkGray)
		this.label = new TextMorph(new Rectangle(0,0,100,20)).beLabel();
		this.addMorph(this.label)
		this.url = url
		this.setupConnections()
		this.layoutManager = new VerticalShrinkLayout();
	},
	setupConnections: function() {
		connect(this, "url", this.label, 'setTextString', {converter: function(value) {
			if (value instanceof URL)
				return value.filename()
			else
				return "no valid url"
		}}).update(this.url)
	},
	expand: function(depth, level) {
		if (depth === 0)
			return;
		if (depth === undefined)
			depth = 1;
	
		if (!this.url) return;
		var children = new WebResource(this.url).getSubElements(1).subCollections
		children.each(function(ea) {
			var m = new ResourceNodeMorph(ea.getURL(), undefined ,this.level + 1);
			m.expand(depth - 1)			
			this.addMorph(m)
		}, this) 
		var leafChildren = new WebResource(this.url).getSubElements(1).subDocuments
		var leafChildrenRows = splitArrayIntoPiecesOfLength(leafChildren, 4);
		leafChildrenRows.each(function(eaRow) {
			var rowMorph = new ShrinkBoxMorph();
			eaRow.each(function(ea) {
				var m = new ResourceNodeMorph(ea.getURL(),  undefined , this.level + 1);
				m.submorphExtentChanged(m.label)
				rowMorph.addMorph(m)
			}, this);
			this.addMorph(rowMorph)
		}, this);
	},
	
})
]]>