 							adjustBuffer()
 
 						doInsert = (locator, item) ->
-							inserted = []
 							if angular.isFunction locator
 								throw new Error('not implemented - Insert with locator function')
 							else
 								if 0 <= locator-first-1 < buffer.length
-									inserted.push (insert locator, item)
+									insert locator, item
 									next++
 							item.scope.$index = first + i for item,i in buffer
-							adjustBuffer(null, inserted)
+							adjustBuffer()
 
 						eventListener.$on "insert.item", (event, locator, item)->doInsert(locator, item)
 						eventListener.$on "update.items", (event, locator, newItem)-> doUpdate(locator, newItem)

							adapter.isLoading = value
							setValueChain($scope, $attr.isLoading, value) if $attr.isLoading
							datasource.loading(value) if typeof datasource.loading is 'function'

						ridActual = 0
						first = 1
						next = 1
						buffer = []
						pending = []
						eof = false
						bof = false

						#removes items from start (including) through stop (excluding)
						removeFromBuffer = (start, stop)->
							for i in [start...stop]
								buffer[i].scope.$destroy()
								buffer[i].element.remove()
							buffer.splice start, stop - start

						reload = ->
							ridActual++
							first = 1
							next = 1
							removeFromBuffer(0, buffer.length)
							builder.topPadding(0)
							builder.bottomPadding(0)
							pending = []
							eof = false
							bof = false
							adjustBuffer(ridActual)

						bottomVisiblePos = ->
							viewport.scrollTop() + viewport.outerHeight()

						topVisiblePos = ->
							viewport.scrollTop()

						shouldLoadBottom = ->
							!eof && builder.bottomDataPos() < bottomVisiblePos() + bufferPadding()

						clipBottom = ->
							# clip the invisible items off the bottom
							bottomHeight = 0 #builder.bottomPadding()
							overage = 0

							for i in [buffer.length-1..0]
								item = buffer[i]
								itemTop = item.element.offset().top
								newRow = rowTop isnt itemTop
								rowTop = itemTop
								itemHeight = item.element.outerHeight(true) if newRow
								if (builder.bottomDataPos() - bottomHeight - itemHeight > bottomVisiblePos() + bufferPadding())
									bottomHeight += itemHeight if newRow
									overage++
									eof = false
								else
									break if newRow
									overage++

							if overage > 0
								builder.bottomPadding(builder.bottomPadding() + bottomHeight)
								removeFromBuffer(buffer.length - overage, buffer.length)
								next -= overage
								#log "clipped off bottom #{overage} bottom padding #{builder.bottomPadding()}"

						shouldLoadTop = ->
							!bof && (builder.topDataPos() > topVisiblePos() - bufferPadding())

						clipTop = ->
							# clip the invisible items off the top
							topHeight = 0
							overage = 0
							for item in buffer
								itemTop = item.element.offset().top
								newRow = rowTop isnt itemTop
								rowTop = itemTop
								itemHeight = item.element.outerHeight(true) if newRow
								if (builder.topDataPos() + topHeight + itemHeight < topVisiblePos() - bufferPadding())
									topHeight += itemHeight if newRow
									overage++
									bof = false
								else
									break if newRow
									overage++
							if overage > 0
								builder.topPadding(builder.topPadding() + topHeight)
								removeFromBuffer(0, overage)
								first += overage
								#log "clipped off top #{overage} top padding #{builder.topPadding()}"

						enqueueFetch = (rid, direction)->
							if (!adapter.isLoading)
								loading(true)
							if pending.push(direction) == 1
								fetch(rid)

						insert = (index, item) ->
							itemScope = $scope.$new()
							itemScope[itemName] = item
							toBeAppended = index > first
							itemScope.$index = index
							itemScope.$index-- if toBeAppended
							wrapper =
								scope: itemScope

							linker itemScope, (clone) ->
								wrapper.element = clone
								wrapper.toBeAppended = toBeAppended
								if toBeAppended
									if index == next
										wrapper.doInsert = ->
											builder.append clone
											builder.bottomPadding(Math.max(0,builder.bottomPadding() - wrapper.element.outerHeight(true)))
										buffer.push wrapper
									else
										wrapper.doInsert = ->
											buffer[index-first-1].element.after clone
										buffer.splice index-first+1, 0, wrapper
								else
									wrapper.doInsert = ->
										builder.prepend clone
										# an element is inserted at the top
										newHeight = builder.topPadding() - wrapper.element.outerHeight(true)
										# adjust padding to prevent it from visually pushing everything down
										if newHeight >= 0
											# if possible, reduce topPadding
											builder.topPadding(newHeight)
										else
											# if not, increment scrollTop
											viewport.scrollTop(viewport.scrollTop() + wrapper.element.outerHeight(true))
									buffer.unshift wrapper

						doAdjustment = (rid, finalize)->
							#log "top {actual=#{builder.topDataPos()} visible from=#{topVisiblePos()} bottom {visible through=#{bottomVisiblePos()} actual=#{builder.bottomDataPos()}}"
							if shouldLoadBottom()
								enqueueFetch(rid, true)
							else
								enqueueFetch(rid, false) if shouldLoadTop()
							finalize(rid) if finalize
							if pending.length == 0
								topHeight = 0
								for item in buffer
									itemTop = item.element.offset().top
									newRow = rowTop isnt itemTop
									rowTop = itemTop
									itemHeight = item.element.outerHeight(true) if newRow
									if newRow and (builder.topDataPos() + topHeight + itemHeight < topVisiblePos())
										topHeight += itemHeight
									else
										topVisible(item) if newRow
										break

						adjustBuffer = (rid, newItems, finalize)->
							if newItems
								$timeout ->
									prepended = []
									for wrapper in buffer
										if wrapper.element.parent().length == 0
											if wrapper.toBeAppended
												wrapper.doInsert()
											else
												prepended.unshift wrapper
									# prepended items have to be inserted from the bottom up
									for wrapper in prepended
										wrapper.doInsert()
									doAdjustment(rid, finalize)
							else
								doAdjustment(rid, finalize)

						finalize = (rid, newItems)->
							adjustBuffer rid, newItems, ->
								pending.shift()
								if pending.length == 0
									loading(false)
								else
									fetch(rid)

						fetch = (rid) ->
							direction = pending[0]
							#log "Running fetch... #{{true:'bottom', false: 'top'}[direction]} pending #{pending.length}"
							if direction
								if buffer.length && !shouldLoadBottom()
									finalize(rid)
								else
									#log "appending... requested #{bufferSize} records starting from #{next}"
									datasource.get next, bufferSize,
									(result) ->
										return if (rid and rid isnt ridActual) or $scope.$$destroyed
										if result.length < bufferSize
											eof = true
											builder.bottomPadding(0)
											#log "eof is reached"
										if result.length > 0
											clipTop()
											for item in result
												insert ++next, item
											#log "appended: requested #{bufferSize} received #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
										finalize rid, result.length > 0
							else
								if buffer.length && !shouldLoadTop()
									finalize(rid)
								else
									#log "prepending... requested #{size} records starting from #{start}"
									datasource.get first-bufferSize, bufferSize,
									(result) ->
										return if (rid and rid isnt ridActual) or $scope.$$destroyed
										if result.length < bufferSize
											bof = true
											builder.topPadding(0)
											#log "bof is reached"
										if result.length > 0
											clipBottom() if buffer.length
											for i in [result.length-1..0]
												insert --first, result[i]
											#log "prepended: requested #{bufferSize} received #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
										finalize rid, result.length > 0

						# events and bindings

						resizeAndScrollHandler = ->
							if !$rootScope.$$phase && !adapter.isLoading
								adjustBuffer()
								$scope.$apply()

						wheelHandler = (event) ->
							scrollTop = viewport[0].scrollTop
							yMax = viewport[0].scrollHeight - viewport[0].clientHeight
							if (scrollTop is 0 and not bof) or (scrollTop is yMax and not eof)
								event.preventDefault()

						viewport.bind 'resize', resizeAndScrollHandler
						viewport.bind 'scroll', resizeAndScrollHandler
						viewport.bind 'mousewheel', wheelHandler

						$scope.$watch datasource.revision, reload

						if datasource.scope
							eventListener = datasource.scope.$new()
						else
							eventListener = $scope.$new()

						$scope.$on '$destroy', ->
							for item in buffer
								item.scope.$destroy()
								item.element.remove()
							viewport.unbind 'resize', resizeAndScrollHandler
							viewport.unbind 'scroll', resizeAndScrollHandler
							viewport.unbind 'mousewheel', wheelHandler


						# adapter initializing

						adapter = {}
						adapter.isLoading = false

						removeElement =
							if $animate

									deferred = $q.defer()
									deferred.resolve()
									deferred.promise

						ridActual = 0
						first = 1
						next = 1
						buffer = []
						pending = []
						eof = false
						bof = false

						#removes items from start (including) through stop (excluding)
						removeFromBuffer = (start, stop)->
							for i in [start...stop]
								buffer[i].scope.$destroy()
								buffer[i].element.remove()
							buffer.splice start, stop - start

						reload = ->
							ridActual++
							first = 1
							next = 1
							removeFromBuffer(0, buffer.length)
							builder.topPadding(0)
							builder.bottomPadding(0)
							pending = []
							eof = false
							bof = false
							adjustBuffer ridActual

						bottomVisiblePos = ->
							viewport.scrollTop() + viewport.outerHeight()

						topVisiblePos = ->
							viewport.scrollTop()

						shouldLoadBottom = ->
							!eof && builder.bottomDataPos() < bottomVisiblePos() + bufferPadding()

						clipBottom = ->
							# clip the invisible items off the bottom
							bottomHeight = 0 #builder.bottomPadding()
							overage = 0

							for i in [buffer.length-1..0]
								item = buffer[i]
								itemTop = item.element.offset().top
								newRow = rowTop isnt itemTop
								rowTop = itemTop
								itemHeight = item.element.outerHeight(true) if newRow
								if (builder.bottomDataPos() - bottomHeight - itemHeight > bottomVisiblePos() + bufferPadding())
									bottomHeight += itemHeight if newRow
									overage++
									eof = false
								else
									break if newRow
									overage++

							if overage > 0
								builder.bottomPadding(builder.bottomPadding() + bottomHeight)
								removeFromBuffer(buffer.length - overage, buffer.length)
								next -= overage
								#log "clipped off bottom #{overage} bottom padding #{builder.bottomPadding()}"

						shouldLoadTop = ->
							!bof && (builder.topDataPos() > topVisiblePos() - bufferPadding())

						clipTop = ->
							# clip the invisible items off the top
							topHeight = 0
							overage = 0
							for item in buffer
								itemTop = item.element.offset().top
								newRow = rowTop isnt itemTop
								rowTop = itemTop
								itemHeight = item.element.outerHeight(true) if newRow
								if (builder.topDataPos() + topHeight + itemHeight < topVisiblePos() - bufferPadding())
									topHeight += itemHeight if newRow
									overage++
									bof = false
								else
									break if newRow
									overage++
							if overage > 0
								builder.topPadding(builder.topPadding() + topHeight)
								removeFromBuffer(0, overage)
								first += overage
								#log "clipped off top #{overage} top padding #{builder.topPadding()}"

						enqueueFetch = (rid, direction)->
							if (!adapter.isLoading)
								loading(true)
							if pending.push(direction) == 1
								fetch(rid)

						insert = (index, item) ->
							itemScope = $scope.$new()
							itemScope[itemName] = item
							toBeAppended = index > first
							itemScope.$index = index
							itemScope.$index-- if toBeAppended
							wrapper =
								scope: itemScope

							linker itemScope, (clone) ->
								wrapper.element = clone
								wrapper.toBeAppended = toBeAppended
								if toBeAppended
									if index == next
										wrapper.doInsert = ->
											builder.append clone
											builder.bottomPadding(Math.max(0,builder.bottomPadding() - wrapper.element.outerHeight(true)))
										buffer.push wrapper
									else
										wrapper.doInsert = ->
											buffer[index-first-1].element.after clone
										buffer.splice index-first+1, 0, wrapper
								else
									wrapper.doInsert = ->
										builder.prepend clone
										# an element is inserted at the top
										newHeight = builder.topPadding() - wrapper.element.outerHeight(true)
										# adjust padding to prevent it from visually pushing everything down
										if newHeight >= 0
											# if possible, reduce topPadding
											builder.topPadding(newHeight)
										else
											# if not, increment scrollTop
											viewport.scrollTop(viewport.scrollTop() + wrapper.element.outerHeight(true))
									buffer.unshift wrapper

						adjustBuffer = (rid, finalize)->
							# We need the item bindings to be processed before we can do adjustment
							$timeout ->
								prepended = []
								for wrapper in buffer
									if wrapper.element.parent().length == 0
										if wrapper.toBeAppended
											wrapper.doInsert()
										else
											prepended.unshift wrapper
								# prepended items have to be inserted from the bottom up
								for wrapper in prepended
									wrapper.doInsert()
								# doAdjustment(rid, finalize)
								#log "top {actual=#{builder.topDataPos()} visible from=#{topVisiblePos()} bottom {visible through=#{bottomVisiblePos()} actual=#{builder.bottomDataPos()}}"
								if shouldLoadBottom()
									enqueueFetch(rid, true)
								else
									enqueueFetch(rid, false) if shouldLoadTop()
								finalize(rid) if finalize
								if pending.length == 0
									topHeight = 0
									for item in buffer
										itemTop = item.element.offset().top
										newRow = rowTop isnt itemTop
										rowTop = itemTop
										itemHeight = item.element.outerHeight(true) if newRow
										if newRow and (builder.topDataPos() + topHeight + itemHeight < topVisiblePos())
											topHeight += itemHeight
										else
											topVisible(item) if newRow
											break

						finalize = (rid) ->
							adjustBuffer rid, ->
								pending.shift()
								if pending.length == 0
									loading(false)
								else
									fetch(rid)

						fetch = (rid) ->
							direction = pending[0]
							#log "Running fetch... #{{true:'bottom', false: 'top'}[direction]} pending #{pending.length}"
							if direction
								if buffer.length && !shouldLoadBottom()
									finalize rid
								else
									#log "appending... requested #{bufferSize} records starting from #{next}"
									datasource.get next, bufferSize,
									(result) ->
										return if (rid and rid isnt ridActual) or $scope.$$destroyed
										if result.length < bufferSize
											eof = true
											builder.bottomPadding(0)
											#log "eof is reached"
										if result.length > 0
											clipTop()
											for item in result
												insert ++next, item
											#log "appended: requested #{bufferSize} received #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
										finalize rid
							else
								if buffer.length && !shouldLoadTop()
									finalize rid
								else
									#log "prepending... requested #{size} records starting from #{start}"
									datasource.get first-bufferSize, bufferSize,
									(result) ->
										return if (rid and rid isnt ridActual) or $scope.$$destroyed
										if result.length < bufferSize
											bof = true
											builder.topPadding(0)
											#log "bof is reached"
										if result.length > 0
											clipBottom() if buffer.length
											for i in [result.length-1..0]
												insert --first, result[i]
											#log "prepended: requested #{bufferSize} received #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
										finalize rid

						# events and bindings

						resizeAndScrollHandler = ->
							if !$rootScope.$$phase && !adapter.isLoading
								adjustBuffer()
								$scope.$apply()

						wheelHandler = (event) ->
							scrollTop = viewport[0].scrollTop
							yMax = viewport[0].scrollHeight - viewport[0].clientHeight
							if (scrollTop is 0 and not bof) or (scrollTop is yMax and not eof)
								event.preventDefault()

						viewport.bind 'resize', resizeAndScrollHandler
						viewport.bind 'scroll', resizeAndScrollHandler
						viewport.bind 'mousewheel', wheelHandler

						$scope.$watch datasource.revision, reload

						if datasource.scope
							eventListener = datasource.scope.$new()
						else
							eventListener = $scope.$new()

						$scope.$on '$destroy', ->
							for item in buffer
								item.scope.$destroy()
								item.element.remove()
							viewport.unbind 'resize', resizeAndScrollHandler
							viewport.unbind 'scroll', resizeAndScrollHandler
							viewport.unbind 'mousewheel', wheelHandler


						# adapter initializing

						adapter = {}
						adapter.isLoading = false

						applyUpdate = (wrapper, newItems) ->
							animations = []
