Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to lie cheat and steal

How to lie cheat and steal

Better browsers, more CPU cores, faster Javascript engines — performance on the client side has been improving rapidly over the past years. And with HTML5 web app developers now have more possibilities than ever to take advantage of all this power.

Time to move some of the heavy lifting from the server to the client. Time to “lie, cheat, and steal”, as Aaron Patterson put it in his RubyConf keynote.

Experimentation is the foundation for this talk, so put on your lab coats. You might not want to put every bit of code you’ll see into your production apps, but you may just get some new (and wild) ideas. Make the browser work for your (Rails) app!

Florian Plank

March 02, 2013
Tweet

More Decks by Florian Plank

Other Decks in Programming

Transcript

  1. start: -> start = (new Date).getTime() started = true isStarted:

    -> started? and started stop: -> started = false isStopped: -> started == false
  2. success = (stream) => preview.src = window.URL.createObjectURL(stream) localMediaStream = stream

    preview.addEventListener 'loadeddata', capture error = -> console.error arguments navigator.getUserMedia video: true, success, error
  3. capture: => ctx.drawImage(preview, 0, 0) if localMediaStream? now = (new

    Date).getTime() pixels = ctx.getImageData(0, 0, WIDTH, HEIGHT).data timestamp = now - start createFrame(pixels, timestamp) requestAnimationFrame capture unless isStopped()
  4. createFrame = (pixels, timestamp) -> intensity = 0 intensity +=

    pixel for pixel in pixels by 4 when pixel? { intensity: intensity, timestamp: timestamp }
  5. 86

  6. crack = (hash, maxLength = 10, charset) -> charset ?=

    ( 'abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789' ).split('') stack = [''] for [1..maxLength] buffer = [] for item in stack for character in charset word = item + character if md5(word) == hash return word else buffer.push word stack = stack.concat buffer
  7. def crack(hash, max_length = 10, charset = nil) charset ||=

    ( 'abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789' ).split('') stack = [''] max_length.times do buffer = [] for item in stack for character in charset word = item + character if Digest::MD5.hexdigest(word) == hash return word else buffer << word end end end stack = stack + buffer end end
  8. v

  9. # Creates a new object URL. window.URL.createObjectURL() # Revokes an

    object URL previously created window.URL.revokeObjectURL()
  10. THUMBNAILSIZE = 0.25 $(video).on 'canplaythrough', -> width = video.videoWidth *

    THUMBNAILSIZE height = video.videoHeight * THUMBNAILSIZE extractFrame(video, width, height)
  11. step = 1 # extract a frame every on second

    extractFrame = (video, width, height, time = 0) -> video.currentTime = time $(video).one 'seeked', -> ctx = createAndInsertCanvas(width, height) ctx.drawImage(video, 0, 0, width, height) time += step if time < video.duration extractFrame(video, width, height, time) else $('#output') .show() .on('mousemove', scrub) .find('canvas:not(:last)') .hide()
  12. $output = $('#output') outputOffset = $output.offset().left outputWidth = $output.width() pages

    = $output.find('canvas') pageCount = pages.length stepSize = outputWidth / (pageCount - 1) scrub = (e) -> page = Math.round((e.pageX - outputOffset) / stepSize) pages.hide().eq(page).show()
  13. width = $image.data('width') height = $image.data('height') src = $image.attr('src') $canvas

    = $('<canvas />') $canvas.attr(width: width, height: height) ctx = $canvas.get(0).getContext('2d') image = new Image() image.onload = -> ratio = if width > height then height / width else height / height [sWidth, sHeight] = if width > height [@width, @width * ratio] else [@height * ratio, @height] ctx.drawImage(@, 0, 0, sWidth, sHeight, 0, 0, width, height) $image.replaceWith $canvas
  14. ctx.drawImage( image, # image object sx, # crop positition sy,

    # sWidth, # crop size sHeight, # dx, # target position dy, # dWidth, # target size dHeight # )
  15. $('img.resize').resize() $('img.resize').resize(gravity: 'ne', zoom: false) # resize, crop if necessary

    to maintain aspect ratio # north-east gravity $('img.resize').resize('400x300#ne') # resize only if the image is smaller than this $('img.resize').resize('400x300<')
  16. createFrame = (pixels, timestamp) -> intensity = 0 intensity +=

    pixel for pixel in pixels by 4 when pixel? { intensity: intensity, timestamp: timestamp } & requestAnimationFrame capture unless isStopped()
  17. job = new Orange.Job 'calculate_intensity', pixels : pixels timestamp: timestamp

    job.on 'complete', (data) => console.log data.intensity job.perform() # or run whole set at once set.push(job) set.perform()
  18. self.onmessage = (event) -> [type, data] = [event.data.type, event.data.data] switch

    type when 'perform' intensity = 0 intensity += pixel for pixel in data.pixels by 4 ↵ when pixel? self.postMessage type: 'complete' data: intensity: intensity timestamp: data.timestamp
  19. The Future — Worker API Persistent jobs (?) Worker class

    shim Queue interface Custom events Job retry
  20. The Future — Worker API Persistent jobs (?) Worker class

    shim Queue interface Custom events Job retry Error handling