686 snippets – displaying 1–30

A gulp.js template for React.js and ES6 projects

This gulp.js template will compile JSX to JS and ES6 to ES5 using Babel.


  • browserify (dependency management)
  • sourcemaps
  • ES6 to ES5
  • React.js (with JSX to JS compilation)
  • Error notifications

var gulp       = require('gulp');
var browserify = require('browserify');
var babelify   = require('babelify');
var notify     = require("gulp-notify");
var source     = require('vinyl-source-stream');

var paths = {
  	js : { src : [ 'app/**/*.js', 'app/**/*.jsx' ], dest : 'public/js/' }

gulp.task('default', ['build']);

// Watch
gulp.task('watch', function () {
  	gulp.watch(paths.js.src, ['compile']);

// Compile
gulp.task('build', [ 'compile' ]);

gulp.task('compile', function () {
    entries: [ './app/index.js' ],
    extensions: [ '.js', '.jsx' ],
    debug: true // Add sourcemaps
  .transform(babelify) // JSX and ES6 => JS
  .bundle() // Browserify bundles required files
    .on('error', console.error.bind(console))
    .on("error", notify.onError({
      message: 'Error: <%= error.message %>',
      sound: 'Sosumi'
  .pipe(source('app.js')) // Desired filename of bundled files


  "name": "snippets",
  "version": "0.0.1",
  "author": "christian@aktagon.com",
  "main": "app/index.js",
  "dependencies": {},
  "devDependencies": {
    "babelify": "^6.1.2",
    "browserify": "^10.2.1",
    "gulp": "^3.6.2",
    "gulp-notify": "^2.2.0",
    "material-ui": "^0.8.0",
    "mocha": "*",
    "react": "^0.13.3",
    "react-tap-event-plugin": "^0.1.7",
    "vinyl-source-stream": "^1.1.0"
  "scripts": {
    "main": "gulp",
    "test": "gulp build && mocha"

First save the files to your project directory then install the dependencies:

$ brew install npm
$ npm install

Start coding (app/index.js):

React = require('react')
_ = require('lodash')


ALERT: ActiveRecord#order and ActiveRecord#default_scope are dangerous

Consider this model:

class Transaction
  default_scope -> { order("created_at ASC") }

  def self.latest
    order('created_at DESC')

   def self.approved_for_customer(customer)
    where('approved is not null and customer_id = ?', customer).order('approved_at DESC')

And this controller:

class TransactionsWorker
   def perform(...)
      transaction = Transaction.for_customer.latest # WTF!

The order will be “ORDER BY created_at ASC, approved_at DESC, created_at DESC”, not “created_at DESC”.


  • Don’t return an instead of ActiveRecord::Relation if you use order, return an array (.all, .first, etc)
  • Don’t use order and default_scope at all in models, ordering usually belongs in the business logic layer.
  • Use reorder as the last method call if chaining ActiveRecord::Relation in the business layer, e.g. Transaction.where(‘…’).reorder(:approved_at)

A safer model:

class Transaction
   def self.latest
    order('created_at DESC').all

   def self.approved_for_customer(customer)
    where('approved is not null and customer_id = ?', customer).order('approved_at DESC').all

Rails Form Pattern With Delegated Validations

Where do you put validations when you implement the Form pattern in Rails:

  • all in the model?
  • all in the form?
  • both in the model and form? This is a bad idea because you have to keep both model and form validations in sync.

This example defines all validations in the model, i.e. validation errors and form helpers work without additional code.

# Form object wrapper for all models created when creating a new event.
class CreateEventForm
  # Rails 4+
  include ActiveModel::Model
  # Rails 3
  #extend ActiveModel::Naming
  #include ActiveModel::Conversion
  #include ActiveModel::Validations

  attr_accessor :event, :calendar
  delegate :id, :persisted?, to: :event

  def initialize(attributes = {})
    @event = Event.new
    @calendar = Calendar.new
    attributes.each do |key, value|
      public_send("#{key}=", value)

  # Save the event and all related models.
  def save
    if valid?
      ActiveRecord::Base.transaction do

  def self.model_name

  def event_attributes=(attributes)
    event.attributes = attributes

  def calendar_attributes=(attributes)
    calendar.attributes = attributes

  def valid?
    valid = super
    # errors.base(:validation_error) unless valid_children?
    valid && valid_children?


  def valid_children?
    [ event, calendar ].map(&:valid?).all? { |valid| valid == true }

  def setup_associations
    calendar.event = event

View example:

<%= simple_form_for @form do |f| # @form = CreateEventForm.new %>
f.simple_fields_for :calendar do |calendar|
f.simple_fields_for :event do |event|
<% end %>

Note, instead of form objects you can always use accepts_nested_attributes_for. However, why should the view define what the model should look like? accepts_nested_attributes_for is a similar hack as the deprecated attr_accessible.

Tax Optimizer For Suomi/Finland, not Sweden

finlandtaxchristianVersion 9


$ ruby vero.rb --gross-income-step 1000 --gross-income 20000-35000 --capital-income-step 1000 --capital-income 0-20000
Usage: ruby vero.rb [options]
        --entrepreneur [ARG]         Y/N (FöPL/YEL is assumed to be equal to gross income)
        --gross-income [ARG]         Gross income range, e.g. 25000-30000
        --gross-income-step [ARG]    Gross income step, e.g. 1000
        --capital-income [ARG]       Capital income range, e.g. 0-20000
        --capital-income-step [ARG]  Capital income step, e.g. 1000
    -h, --help                       Display this help

Save this file to vero.rb (edit it if you’re not me):

require 'mechanize'
require 'pry'
require 'csv'
require 'optparse'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: ruby vero.rb [options]"
  opts.on('--entrepreneur [ARG]', "Y/N (FöPL/YEL is assumed to be equal to gross income)") do |v|
    options[:entrepreneur] = v.strip.downcase == 'y'
  opts.on('--gross-income [ARG]', "Gross income range, e.g. 25000-30000") do |v|
    parts = v.split('-')
    options[:gross_income_range] = (parts[0].to_f..parts[1].to_f)
  opts.on('--gross-income-step [ARG]', "Gross income step, e.g. 1000") do |v|
    options[:gross_income_step] = v.to_f
  opts.on('--capital-income [ARG]', "Capital income range, e.g. 25000-30000") do |v|
    parts = v.split('-')
    options[:capital_income_range] = (parts[0].to_f..parts[1].to_f)
  opts.on('--capital-income-step [ARG]', "Capital income step, e.g. 1000") do |v|
    options[:capital_income_step] = v.to_f
  opts.on('-h', '--help', 'Display this help') do
    puts opts
  puts opts

puts options

def tax_for(options = {})
  gross_income = options.fetch(:gross_income)
  capital_income = options.fetch(:capital_income, 0)
  entrepreneur = options.fetch(:entrepreneur, false)
  mech = Mechanize.new
  page = mech.get('http://prosentti.vero.fi/VPL2015/Sivut/Aloitus.aspx')
  # Page 1
  page_1 = mech.click(page.link_with(text: /Veroprosenttilaskuri 2015/))
  form_1 = page_1.form_with(action: 'Henkilotiedot.aspx')
  form_1.field_with(name: "ddKotikunta").option_with(text: "Espoo").click
  form_1.field_with(name: "ddSeurakunta").option_with(text: "ei kirkollisverovelvollinen").click
  form_1.field_with(name: "ddSyntymavuosi").value = "1976"
  form_1.field_with(name: "ddPuoliso").value = "Kyllä"
  form_1.field_with(name: "tbYhteishuoltoLapset").value = "2"
  form_1.field_with(name: "tbLapset").value = "2"
  # Page 2
  page_2 = form_1.submit(form_1.button_with(name: "btnJatka"))
  fail page_2.body unless page_2.uri.to_s == 'http://prosentti.vero.fi/VPL2015/Sivut/TulotJaVahennykset.aspx'
  form_2 = page_2.form_with(action: 'TulotJaVahennykset.aspx') do |f|
    # Bruttoinkomster
    f.field_with(name: "tbPaatoimiArvioTulo").value = gross_income.to_s.gsub('.', ',')
    # Dividender
    # f.field_with(name: "tbOsingotJulkNotPotArvioTulo").value = capital_income.to_s.gsub('.', ',')
    # Övrig kapitalinkomster
    f.field_with(name: "tbVuokratulotJaTappiotVuoratulotOsakehuoneistoista").value = capital_income.to_s.gsub('.', ',')
    # Entrepreneurs need to include "FöPL- eller LFöPL-arbetsinkomst (YEL)":
    if entrepreneur
      f.field_with(name: "tbShJaPaivarahamaksunTiedotYelTyotulo").value = gross_income.to_s.gsub('.', ',')
      f.field_with(name: "tbShJaPaivarahamaksunTiedotTyotuloillaKorvattavaYpalkka").value = gross_income.to_s.gsub('.', ',')
  # Page 3
  page_3 = form_2.submit(form_2.button_with(name: "btnJatka"))
  base = Float(page_3.at('#riviPerusprosentti').at('#neljassoluPerusprosentti').text.gsub(',', '.'))
  additional = Float(page_3.at('#riviLisaprosentti').at('#neljassoluLisaprosentti').text.gsub(',', '.'))
  [ base, additional ]
#rescue => e
  #puts e

CSV.open("taxes.csv", "w") do |csv|
  cols = [ "bruttoinkomster", "kapitalinkomster", "grundprocent", "tilläggsprocent" ]
  csv << cols
  options.fetch(:gross_income_range).step(options.fetch(:gross_income_step)).each do |gross_income|
    options.fetch(:capital_income_range).step(options.fetch(:capital_income_step)).each do |capital_income|
      taxes = tax_for(gross_income: gross_income, capital_income: capital_income)
      row = [ gross_income, capital_income, taxes ].flatten
      puts Hash[cols.zip row]
      csv << row

Open taxes.csv and think about what you’re doing.

Finnish SSID/HETU generator in Ruby

module Ssid
  module Fake
    # Generates fake Finnish SSIDs (HETU).
    # Original Python version:
    # https://gist.github.com/puumuki/11172310
    class Finnish
      CENTURIES = { '18' => '+',
                    '19' => '-',
                    '20' => 'A' }
      def self.generate(start_year=1800, end_year=2014)
        year = start_year + rand(start_year - end_year)
        month = 1 + rand(12)
        day = 1 + rand(days_in_month(year, month))
        century_sep = CENTURIES[year.to_s[0..1]]
        order_num = 2 + rand(889)
        check_number = "%02d%02d%s%03d" % [ day, month, year.to_s[0..1], order_num ]
        check_number_index = check_number.to_i % 31
        key = CHECK_KEYS[check_number_index]
        "%02d%02d%s%s%03d%s" % [ day, month, year.to_s[0..1], century_sep, order_num, key ]


      def self.days_in_month(year, month)
        (Date.new(year, 12, 31) << (12-month)).day

How to get notified when a Cron job fails

To get notified when a cron script fails you can tell cron to send any errors to you by email.

It already does this by default, but the emails are sent to the Unix account’s mailbox:

cat /var/spool/mail/<username> | less

To use a different email address use the MAILTO setting as described here:

0 */2 * * * /bin/backup.sh > /dev/null

Cron will now send an email whenever the script (/bin/backup.sh) prints something to stderr.

If the script is printing to stderr without it failing try Cronic:

0 */2 * * * cronic /bin/backup.sh

You can of course also try to fix the script by not printing to STDERR unless it’s really an error.

Check the mail log to see if it’s working:

sudo tail -f /var/log/mail.log

If you’re email server is rejecting emails sent by cron you might need to set the MAILFROM variable. However, only some cron version supports MAILFROM.

How to mark deprecated methods in Ruby

This code can be used to mark deprecated methods in Ruby:

module Kernel
  def mark_deprecated(new_method)
    warn "DEPRECATED: the #{__method__} called from #{caller.first} has been deprecated and replaced by #{new_method}!!!"


class Horse
  def self.shit

Checklist for how to write background jobs/workers (Sidekiq/Resque/DelayedJob/<XXX>)


  1. Idempotent
    Jobs should be idempotent. If a job is performed multiple times the work should only be performed once, or at least the end-result should be the same.
  1. Optimistic/pessimistic/distributed locking
    You need to use different types of strategies to prevent code from being executed more than once in a distributed environment. Jobs can be executed twice under many circumstances, e.g. because of:
    – misconfiguration of Sidekiq
    a bug in Sidekiq, or another one
    – queueing job twice
    - millions of other reasons

Solving these issues can be done with, e.g.: optimistic locking, pessimistic locking, and distributed locking, e.g. with redis-semaphore.

  1. Retry
    Set retry to zero for jobs that don’t need to or shouldn’t be retried.
  1. Priority
    Specify a queue and a queue priority for jobs that need a higher or lower priority.
  1. Transactions
    Does the job need database transactions? Use transactions e.g. when a job does more than one insert, update, delete, or create, otherwise you will end up having data duplication/inconsistency issues.
  1. Messaging
    Sidekiq is not a messaging queue. At-least-once execution is 100% guaranteed by Sidekiq Pro. I don’t trust that guarantee 100%, but that is another story. The question is: what happens if the job fails (dead job queue, dev null)? What you usually need is “job successfully executed at-least-once” not “job executed at-least once”.

Ensuring jobs are performed at-least-once and at-most-once

You can’t rely on Sidekiq, or any other messaging or job queue, to execute your job (business logic) once and exactly once. All work needs to be checked for consistency.

For example, messages/jobs can be lost under many circumstances, and the same job (business logic) can be executed an unlimited amount of times unless your application takes the necessary steps to ensure that the job is performed correctly. A background processing/messaging server should be considered unreliable.


Use a reconsiliation step, e.g. a separate worker that runs once per day, to make sure jobs are executed at least once: http://www.mikeperham.com/2014/05/27/the-reconciliation-step/

  1. Databases: At-least-once is achieved when you have the data in your database and are polling to see if the job has been performed. Locking => performance issues.
  2. Sidekiq: At-least-once is achieved when you monitor the dead job queue 100% using available eyeballs.
  3. Messaging queues: At-least-once is achieved through message acknowledgment and/or through monitoring the dead letter queue 100% using available eyeballs.


Use a flag, nonce, or a guid to ensure a job is only run once, i.e. do nothing if a job is queued twice for some reason. Avoid locking database tables when possible. Use optimistic/pessimistic/distributed locks when locking is needed.


Don’t trust your messaging and background processing server to do its job without either manual supervision (eyeballs) or automated supervision (at-least-once and at-most-once).

Using Ruby 2.2.0 with Rails 3.x

rubyrailschristianVersion 4

Steps for upgrading a Rails 3.x app to Ruby 2.2.0:

  1. Install Ruby 2.2.0, e.g. brew update; brew upgrade ruby-build; rbenv install 2.2.0
  2. Set app’s ruby version to 2.2.0, e.g. rbenv local 2.2.0
  3. Update gems that are broken, e.g. bundle update pg eventmachine rubocop
  4. Add test-unit to Gemfile to fix “cannot load such file — test/unit/testcase (LoadError)” error:

gem 'test-unit'

  1. Rollback to 2.1 when you notice all warnings, related to e.g. Comparable, or continue with the warnings

JavaScript Promises With Q.js

This Q.js example calls two asynchronous methods in sequence:

class InitializeApp
  constructor: ->
    findDevice = ->
      df = Q.defer()
      onSuccess = (devices) ->
        console.log "Finding device"
        df.resolve("device 2")
      setTimeout(onSuccess, 2000)

    connectToDevice = (id) ->
      df = Q.defer()
      onSuccess = ->
        console.log "Connecting to #{id}"
      setTimeout(onSuccess, 2000)



new InitializeApp()
# ...Sleep 2 seconds
# => Finding device
# ...Sleep 2 seconds
# => Connecting to device 2

How to use Font Awesome in iOS/Phonegap apps

First, install Font Awesome:

  1. Download the latest Font Awesome version
  2. Double-click fontawesome-webfont.ttf and install it on your laptop/desktop (optional)
  3. Copy fontawesome.css to www/css
  4. Remove the references to font files in fontawesome.css, i.e. remove @font-face declaration

Then in Xcode:

  1. Copy fontawesome-webfont.ttf into “Your Project/Resources/fonts/fontawesome-webfont.ttf”
  2. Add Font Awesome to the .plist file by selecting the “Info” tab
  3. Add a new property named “Fonts provided by application” and set the value to “fontawesome-webfont.ttf”

Clean and build your project. Font Awesome is now ready to be used.

Phonegap example:

<i class="fa fa-cog"/>

How to hide the status bar in a Phonegap iOS app

To hide the status bar in a phonegap project:

  1. Double click on your project, or .plist, in XCode
  2. Select the tab named “Info”
  3. Add a new property by selecting an item in the list and then clicking the plus sign
  4. Name the property “View controller-based status bar appearance”
  5. Set the property value to “NO”


  1. Select the tab named general
  2. Check the “Hide status bar” located under “Deployment Info”


How to Open Safari's Web Inspector With Applescript to Debug a Phonegap App

This trick will save years of your life. This applescript will make Safari’s Web Inspector connect to a Phonegap application running on my iPhone that was started through XCode:


set device_name to "Christian Hellsten iPhone"
tell application "Safari"
	tell application "System Events"
			click menu item "index.html" of menu device_name of menu item device_name of menu "Utvecklare" of menu bar item "Utvecklare" of menu bar 1 of application process "Safari"
		end try
	end tell
end tell

Save the file, as e.g. open-web-inspector.applescript, then execute it:

chmod +x open-web-inspector.applescript

For English version, change “Utvecklare” to “Develop”.


  1. Error -1719 most likely means you need to enable assistive access for iTerm or whatever app you’re running the script from.
  1. Error -10810 means “bad luck” in Applescript. Try restarting the computer.

If all else fails, run the script using the Applescript Editor. Also see, this script.

Tested on OSX Yosemite.

CoffeeScript variable visibility

coffeescriptchristianVersion 3

This Coffeescript:

class Device
  x: 1 # Instance variable
  y = 2 # Private instance variable
  @z: 3 # Class variable

 # Address and name are instance variables
  constructor: (@address, @name) ->

gives us this JavaScript:

Device = (function() {
  var y;
  Device.prototype.x = 1;
  y = 2;
  function Device(address, name) {
    this.address = address;
    this.name = name;
  return Device;

and the following visibility:

dev = new Device('X', 'Y') # => Device {address: "X", name: "Y", x: 1}
dev.y # => undefined
Device.z # => 3

How to Debug Phonegap Applications With Safari's Remote Debugger

  1. On your iPhone/iPad: Enable Web Inspector . Open “Settings” → “Safari” → “Advanced”.
  2. On your desktop/laptop: Enable Developer tools in Safari. Open “Preferences” → “Advanced” check “Show Develop menu in menu bar”.
  3. Connect your iPhone via USB to your desktop/laptop.
  4. Start the application on your iPad/iPhone via XCode.
  5. On your desktop/laptop: Open the Safari Web Inspect debugger. Go to “Preferences” → “Your phone” → “index.html”.

You can automate the last step by using applescript to open Safari’s Web Inspector.

Note: Use CMD+R to reload index.html.

Phonegap Autorotate

In MainViewController#shouldAutorotateToInterfaceOrientation return YES:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    // Return YES for supported orientations
    return YES; //[super shouldAutorotateToInterfaceOrientation:interfaceOrientation];

Running a Phonegap App in a Specific Version of iPhone


cordova emulate ios --target="iPhone-4s"
cordova emulate ios --target="iPad-Air"
cordova emulate ios --target="iPhone-6"
cordova emulate ios --target="iPhone-6-Plus"


phonegap run ios --target="iPhone-4s"
phonegap run ios --target="iPad-Air"
phonegap run ios --target="iPhone-6"
phonegap run ios --target="iPhone-6-Plus"

Gulpfile.js example with Slim, Coffeescript, Sass, Browser Sync, Lint

slimgulpchristianVersion 8

A Gulpfile.js example with Slim, Coffeescript, Sass, Browser Sync, Lint. The script is suitable for building e.g. static websites and prototyping mobile apps.

Gulpfile expects your project to be structured in the following way (configurable):
- src/css/.scss,.css
- src/js/.coffee,.js
- src/*.slim

Output is written to “www” folder.

# Gulpfile with:
# - Slim
# - Sass
# - Lint
# - Browsersync
# - CSS and HTML compression
# Install dependencies:
#   $ npm install gulp gulp-concat gulp-uglify event-stream gulp-coffee gulp-sass gulp-cssmin gulp-coffee gulp-coffeelint browser-sync gulp-util gulp-shell
# Then start developing:
#   $ gulp

gulp        = require 'gulp'
concat      = require 'gulp-concat'
es          = require('event-stream')
sass        = require 'gulp-sass'
uglify      = require 'gulp-uglify'
streamqueue = require 'streamqueue' # Preserves file order (vendor...)
coffee      = require 'gulp-coffee'
gutil       = require 'gulp-util'
shell       = require 'gulp-shell'
cssmin      = require 'gulp-cssmin'
coffeelint  = require 'gulp-coffeelint'
browserSync = require 'browser-sync'

isProd = gutil.env.type is 'prod'

sources =
  sass: 'src/css/**/*.scss'
  css: 'src/css/**/*.css'
  html: 'src/**/*.slim'
  js: 'src/js/**/*.js'
  coffee: 'src/js/**/*.coffee'

targets =
  css: 'www/css'
  html: 'www/'
  js: 'www/js'

# Check for errors
gulp.task 'lint', ->

# Compile Coffeescript
gulp.task 'js', ->
  stream = streamqueue(objectMode: true)
  # Vendor files
  # App files use Coffee
    .pipe(if isProd then uglify() else gutil.noop())

# Compile Slim
gulp.task 'slim', ->
    .pipe(shell(["slimrb -r ./lib/helpers.rb -p <%= file.path %> > ./#{targets.html}/<%= file.relative.replace(\".slim\", \".html\") %>"]))

# Compile CSS
gulp.task 'css', ->
  stream = streamqueue(objectMode: true)
  # Vendor files
  # App files
  stream.queue(gulp.src(sources.sass).pipe(sass(style: 'expanded', includePaths: ['src/css'], errLogToConsole: true)))
    .pipe(if isProd then uglify() else gutil.noop())

# Reload browser
gulp.task 'server', ->
  browserSync.init null,
    open: true
      baseDir: targets.html
    reloadDelay: 2000 # Prevent white screen of death
      debounceDelay: 1000

# Watch files for changes
gulp.task 'watch', ->
  gulp.watch sources.js, ['js']
  gulp.watch sources.css, ['css']
  gulp.watch sources.html, ['slim']
  gulp.watch 'www/**/**', (file) ->
    browserSync.reload(file.path) if file.type is "changed"

# Build everything
gulp.task 'build', ['lint', 'js', 'css', 'slim']

# Start a server and watch for file changes
gulp.task 'default', ['watch', 'server']

Also see A gulp.js template for React.js and ES6 projects

Writing a DSL in Ruby

When defining a simple DSL instance_eval and instance_exec is your friend:

class Worker
  attr_reader :where
  def call(where, &block)
    @where = where
    instance_eval &block

  def cut_trees
    puts "Cutting trees"

  def make_planks
    puts "Making planks"

  def i(what, &block)
    instance_eval &block

def work where, &block
  puts "Working #{where}"
  Worker.new.(where, &block)
  puts "Going home"

Use the DSL like this:

work "in the woods" do
  i "take a coffee break" do
    puts "Cooking coffee #{where}"

Output is:

Working in the woods
Cutting trees
Making planks
Cooking coffee in the woods
Going home

instance_exec method allows you to pass arguments to your blocks, which instance_eval doesn’t allow.

Ruby's call method

rubycallchristianVersion 4

What does this print:

class RubyCall
  def call(*args)
    puts "Call: #{args}"

xxx = RubyCall.new
xxx.("hello", 1, 2, 3)

It calls the #call method and prints “Call: [”hello", 1, 2, 3]".

If you want you can do this:


How to record and replay TCP traffic

tcpreplaychristianVersion 2

First attempt

1) Record TCP traffic with tcpdump to pcap file

Record traffic on ethic from host and port 2332, write to app-traffic.pcap:

tcpdump -vvv -i eth0 host and port 2332 -w app-traffic.pcap &

2) View captured traffic

tcpdump -qns 0 -X -r app-traffic.pcap

Edit captured traffic if needed with Wireshark.

3) Edit source IP so that it’s on your own network

See the ”example in tcprewrite documentation”:http://tcpreplay.synfin.net/wiki/tcprewrite for details on how to rewrite source IP:

$ tcprewrite --pnat=, --infile=input.pcap --outfile=output.pcap --skipbroadcast

4) Replay traffic with tcplivereplay from recorded pcap file (note step #3)

”See tcpliveplay documentation”:http://tcpreplay.synfin.net/wiki/tcpliveplay for details.

Note that tcpliveplay is only available on Linux not OSX.

Second attempt


sudo tcpdump -i en0 host and port 2332 -w app-traffic.pcap


tcpdump -s 0 -n -e -x -vvv -r app-traffic.pcap


sudo tcpreplay -i en0 -t -K app-traffic.pcap

Or use tcplivereplay (Note: Linux only):


I couldn’t get it to work….

Big Search Field & Button = Beautiful?

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css"/>

.search-form {
  width: 40%;
  min-width: 400px;
  border: 6px solid rgba(0, 0, 0, 0.7);
  margin: 20px auto 0;

input.text {
  float: left;
  width: 80%;
  border: 5px solid #fff;
  margin: 0;
  outline: none;
  font-size: 17px;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  -ms-border-radius: 0;
  -o-border-radius: 0;
  border-radius: 0;
  -webkit-appearance: none;
  color: #3c3c3c;

input.text, input.button {
  padding: 15px;
  font-size: 17px;
  font-weight: 800;
  display: inline-block;
  -webkit-transition: all 0.3s ease;
  -moz-transition: all 0.3s ease;
  -o-transition: all 0.3s ease;
  transition: all 0.3s ease;

input.button {
  float: right;
  width: 20%;
  margin: 0;
  border: 5px solid grey;
  color: #fff;
  background-color: grey;
  -webkit-appearance: none;
  padding-left: 0;
  padding-right: 0;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  -ms-border-radius: 0;
  -o-border-radius: 0;
  border-radius: 0;

.clearfix {
  overflow: auto;

* {
  font-family: "Helvetica", sans-serif;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;

  <div class="search-form clearfix">
    <input name="query" class="text" type="text" placeholder="Find your dog&hellip;">
    <input type="submit" value="Search" class="button">