Reorganize,  added commands

Reorganize,  added commands

# Voice commands for atom

include folders.vch;
include letters.vch;

Go Strawberry = {Ctrl+Alt+F8};
Go Blueberry ={Ctrl+Alt+o};
Go Banana = {Ctrl+Alt+F7};

# Commands for developing Atom: init.config, packages; also for navigating existing packages/commands
Reload Atom = {Ctrl+s} Wait(100)  {Shift+Ctrl+Alt+F5};
Command Palette = {Ctrl+Shift+p};
Keyboard Shortcuts = {Ctrl+.};
Run Specs = {Ctrl+Alt+p};
Show Console = {Ctrl+Alt+i};

# Commands for developing D3: D3 visualizations, D3 Sandwiches
Save and Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Ctrl+r};
Save and Really Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}") {Ctrl+Shift+r};

# File commands
Find (File | Document) = {Ctrl+t};
Save As = {Ctrl+Shift+s};
Next Window = {Ctrl+Tab};
Last Window = {Ctrl+Shift+Tab};

# --- Text navigation commands ------------------------------------
<delimiters> := (Quote = '"' | 'Single Quote' = "'" | Comma = ',' | 'Equal Sign' = '=' | Equals = '='
	| Period = '.' | Colon = ':' | 'Semi-Colon' = ';' | Hyphen = '-' |  Underscore = '_' | Slash = '/'
	| Paren = "(" | "Close Paren" = ")" | Parentheses = "(" | "Open Parenthesis" = "(" | "Close Parentheses" = ")"
	| Bracket = '[' | "Close Bracket" = ']' | Brace = '{' | 'Close Brace' = '}'	);

Line 1..200 = {Ctrl+g} $1 {Enter};
(Left = 'b' | Right = 'f') Word = {Alt+$1};
Top = {Ctrl+Home};
Bottom = {Ctrl+End};
(Find = 'Right' | 'Insert After' = 'Right' | 'Insert Before' = 'Left') (Next = 'Enter' | Last = 'Shift+F3') <delimiters>
		= {Ctrl+f} $3 {$2} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') <delimiters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') 1..20 <delimiters> =  {Ctrl+f} $3 {Enter} {Esc}   Wait(100) {F3_$2} {Shift+F3} Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') Enda <delimiters> = {End} {Ctrl+f} $2 {Enter} {Esc} {Shift+F3}  Wait(100) {$1};

Fine Alpha <letters> = {Ctrl+f} $1 {Enter} {Esc}   Wait(100) {Left};
Insert (Before = 'Left' | After = 'Right') Alpha <letters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Fine Number 0..9 = {Ctrl+f} $1 {Enter} {Esc} Wait(100) {Right};
(Find | Insert) Again = {F3} {Right};
(Find | Insert) Again 1..20 Times = {F3_$1} {Right};

(Set | Add | Clear | Hide | Delete) Bookmark = {Ctrl+Alt+F2};
(Next = 'F2' | Last = 'Shift+F2') Bookmark = {$1};

# --- Editing commands ----------------------------------------
Select Line = {Ctrl+l};
Select (Next = 'Down' | Forward = 'Down' | Last = 'Up' | Back = 'Up' | Previous = 'Up') 1..20 Lines = {Home} {Shift+$1_$2};
Move Line (Up | Down) 1..20  = {Ctrl+$1_$2};
Add 1..20 (Lines = 'Down' | Line = 'Down' | Pages = 'PgDn' | Page = 'PgDn') = {Shift+$2_$1};

Select between (Delimiters | Brackets | Tags) ={Ctrl+m} {Ctrl+Alt+m};
Delete between Tags = {Ctrl+m} {Ctrl+Alt+m}  {Del};
Delete Tags = {Ctrl+Alt+F4};
Replace With (Header | Heading) 1..7 = {Ctrl+Alt+F4}  '<h' $2 '>' {End} '</h' $2 '>' {Home};
Replace With (para = 'p') = {Ctrl+Alt+F4} '<' $1 '>' {End} '</' $1 '>';

Delete Word = {Ctrl+Del};
Delete 1..20 Words = {Ctrl+Del_$1};
Delete (Back | Last) Word = {Ctrl+Backspace};
Delete (Back | Last) 1..20 Words = {Ctrl+Backspace_$2};
Delete Enda Word = {End} {Ctrl+Backspace};

(Delete Line | Dede) = {Ctrl+Shift+k};
Delete 1..20 Lines = {Ctrl+Shift+k_$1};
(Cut = 'x' | Paste = 'v' | Copy = 'c') That = {Ctrl+$1};

Comment (That | Line) = {Ctrl+/};
Comment 1..20 Lines = {Home} {Shift+Down_$1} {Ctrl+/};

Replace = {Ctrl+f};
Replace All = {Ctrl+Enter};

(Join = 'j' | Indent = ']' | Dedent = '[')  That = {Ctrl+$1};

# --- Commands to create code/tags -------------------------------------------
# NOTE: basic HTML commands are stored in my global Vocala commands

Start (	# HTML commands
	'HTML page' = 'html' | pre = "pre" | 'Comment' = 'comment-html'
	| div = 'div'

	# D3 Recipe commands
	| 'Recipe Page' = 'recipe-page' | 'Recipe Row' = 'recipe-row'
	| 'Recipe Toy' = 'recipe-toy' | Toy = 'recipe-toy'

	# Coffeescript commands
	| Snippet = 'my-snippet'
	| 'Fix Line' = 'fix-current-line' | 'Fix Current Line' = 'fix-current-line'
) = $1 {Tab};

Stop (	#HTML commands
	'div comment' = 'comment-div-end' |  Comment = 'comment-html-end'
) = $1 {Tab};

# HTML commands
Dot HTML = '.html';
Start (Header | Heading) 1..7 = h $2 {Tab};
Add (Header | Heading) 1..7 =  '<h' $2 '>' {End} '</h' $2 '>';
Add (para = 'p') =  '<' $1 '>' {End} '</' $1 '>';

# D3 Recipe commands
Pre-Format Code =  {Ctrl+Alt+F5};

# D3 commands
Paste Function = 'function ' {Ctrl+v} ' {' {Enter} {Enter} '};' {Up};

# Coffeescript commands

# Python commands

# --- D3 commands -------------------------------------------

# --- Python commands -------------------------------------------

# --- Coffeescript commands -------------------------------------------

# Voice commands for atom

include folders.vch;
include letters.vch;

Go Strawberry = {Ctrl+Alt+F8};
Go Blueberry ={Ctrl+Alt+o};
Go Banana = {Ctrl+Alt+F7};

Start Far = 'var ';

# Commands for developing Atom: init.config, packages; also for navigating existing packages/commands
Reload Atom = {Ctrl+s} Wait(100)  {Shift+Ctrl+Alt+F5};
Command Palette = {Ctrl+Shift+p};
Keyboard Shortcuts = {Ctrl+.};
Run Specs = {Ctrl+Alt+p};
Show Console = {Ctrl+Alt+i};

# Commands for developing D3: D3 visualizations, D3 Sandwiches
Save and Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}")  {Ctrl+r};
Save and Really Reload =  {Ctrl+s}  Wait(100) SendSystemKeys("{Alt+Tab}") {Ctrl+Shift+r};

# File commands
Find (File | Document) = {Ctrl+t};
Save As = {Ctrl+Shift+s};

# --- Navigation commands ------------------------------------
<delimiters> := (Quote = '"' | 'Single Quote' = "'" | Comma = ',' | 'Equal Sign' = '=' | Equals = '='
	| Period = '.' | Colon = ':' | 'Semi-Colon' = ';' | Hyphen = '-' |  Underscore = '_' | Slash = '/'
	| Paren = "(" | "Close Paren" = ")" | Parentheses = "(" | "Close Parentheses" = ")"
	| Bracket = '[' | "Close Bracket" = ']' | Brace = '{' | 'Close Brace' = '}'	);

Line 1..200 = {Ctrl+g} $1 {Enter};
(Left = 'b' | Right = 'f') Word = {Alt+$1};
Top = {Ctrl+Home};
Bottom = {Ctrl+End};
(Find = 'Right' | 'Insert After' = 'Right' | 'Insert Before' = 'Left') (Next = 'Enter' | Last = 'Shift+F3') <delimiters>
		= {Ctrl+f} $3 {$2} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') <delimiters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') 1..20 <delimiters> =  {Ctrl+f} $3 {Enter} {Esc}   Wait(100) {F3_$2} {Shift+F3} Wait(100) {$1};
Insert (Before = 'Left' | After = 'Right') Enda <delimiters> = {End} {Ctrl+f} $2 {Enter} {Esc} {Shift+F3}  Wait(100) {$1};

Fine Alpha <letters> = {Ctrl+f} $1 {Enter} {Esc}   Wait(100) {Left};
Insert (Before = 'Left' | After = 'Right') Alpha <letters> =  {Ctrl+f} $2 {Enter} {Esc}   Wait(100) {$1};
Fine Number 0..9 = {Ctrl+f} $1 {Enter} {Esc} Wait(100) {Right};
Find Again = {F3} {Right};
Find Again 1..20 Times = {F3_$1} {Right};

Find Symbol = {Ctrl+r};

(Set | Add | Clear | Hide | Delete) Bookmark = {Ctrl+Alt+F2};
(Next = 'F2' | Last = 'Shift+F2') Bookmark = {$1};

Next Window = {Ctrl+Tab};
Last Window = {Ctrl+Shift+Tab};

# --- Editing commands ----------------------------------------
Select Line = {Ctrl+l};
Select (Next = 'Down' | Forward = 'Down' | Last = 'Up' | Back = 'Up' | Previous = 'Up') 1..20 Lines = {Home} {Shift+$1_$2};
Grab 1..20 Lines = {Home} {Shift+Down_$1};
Add 1..20 (Lines = 'Down' | Line = 'Down' | Pages = 'PgDn' | Page = 'PgDn') = {Shift+$2_$1};

(Join = 'j' | Indent = ']' | Dedent = '[')  That = {Ctrl+$1};
Move Line (Up | Down) 1..20  = {Ctrl+$1_$2};

Delete Word = {Ctrl+Del};
Delete 1..20 Words = {Ctrl+Del_$1};
Delete (Back | Last) Word = {Ctrl+Backspace};
Delete (Back | Last) 1..20 Words = {Ctrl+Backspace_$2};
Delete Enda Word = {End} {Ctrl+Backspace};

(Delete Line | Dede) = {Ctrl+Shift+k};
Delete 1..20 Lines = {Ctrl+Shift+k_$1};
(Cut = 'x' | Paste = 'v' | Copy = 'c') That = {Ctrl+$1};

Comment (That | Line) = {Ctrl+/};
Comment 1..20 Lines = {Home} {Shift+Down_$1} {Ctrl+/};

Select between (Delimiters | Brackets | Tags) ={Ctrl+m} {Ctrl+Alt+m};

Delete Tags = {Ctrl+Alt+F4};

Replace = {Ctrl+f};
Replace All = {Ctrl+Enter};

# --- Code commands -------------------------------------------
Start (Item = 'li' | List = 'ul' | HTML = 'html' | pre = "pre"
	| div = 'div' | 'Comment' = 'comment-html'
	| 'Bold ID' = 'bold-id' | 'Input' = 'ds-input-text'
	| 'Fix Line' = 'fix-current-line' | 'Fix Current Line' = 'fix-current-line'
	| Snippet = 'my-snippet' | 'Recipe Row' = 'recipe-row' | 'Recipe Play' = 'recipe-play') = $1 {Tab};
Stop (Comment = 'comment-html-end' ) = $1 {Tab};
Start (para = '<p>' ) = $1;
Add (para = 'p') =  '<' $1 '>' {End} '</' $1 '>';
Replace With (para = 'p') = {Ctrl+Alt+F4} '<' $1 '>' {End} '</' $1 '>';

Start (Header | Heading) 1..7 = h $2 {Tab};
Add (Header | Heading) 1..7 =  '<h' $2 '>' {End} '</h' $2 '>';
Replace With (Header | Heading) 1..7 = {Ctrl+Alt+F4}  '<h' $2 '>' {End} '</h' $2 '>' {Home};
Mid HREF = '">';

Paste Function = 'function ' {Ctrl+v} ' {' {Enter} {Enter} '};' {Up};

Pre-Format Code =  {Ctrl+Alt+F5};

# TO ADD:
# adding HTML comments, using a snippet


do the sensible thing when working behind a proxy under our control

/* Varnish 3 example config for Drupal 7 / Pressflow 6 & 7 */
# Original source: https://github.com/NITEMAN/varnish-bites/varnish4/drupal-base.vcl
# Copyright (c) 2015 Pedro González Serrano and individual contributors.
# MIT License

# Intended to be used both in simple production environments and with learning/teaching purposes.
# Loosely based on http://www.lullabot.com/sites/default/files/default_varnish3.vcl_.txt

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-probes
probe basic {
  /* Only test that backend's IP serves content for '/' */
  # This might be a too heavy probe
  # .url = "/";
  /* Only test that backend's IP has apache working */
  # Nginx would fail this probe with a default config
  .request =
    "OPTIONS * HTTP/1.1"
    "Host: *"
    "Connection: close";
  .interval = 10s;
  .timeout = 2s;
  .window = 8;
  .threshold = 6;
}

/* Backend definitions.*/
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-declarations
backend default {
  /* Default backend on the same machine. WARNING: timeouts could be not big enought for certain POST request */
  .host = "127.0.0.1";
  .port = "8008";
  .connect_timeout = 60s;
  .first_byte_timeout = 60s;
  .between_bytes_timeout = 60s;
  .probe = basic;
}

/* Directors. */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#directors
# Empty in simple configs

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#acls
acl purge_ban {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use '"localhost";' instead
}
acl allowed_monitors {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use'"localhost";' instead
}
acl own_proxys {
  "127.0.0.1"/32; // We can use'"localhost";' instead
}

/* Custom routines */
# Empty in simple configs.
# We can name subs with no restrictions but as a task can need several chunks of code in diferent states,
# it's a good idea to identify what main sub will call each with a suffix.
# /* Example 301 client redirection removing "www" prefix from request */
# sub perm_redirections_recv {
#   if ( req.http.host ~ "^www.*$" ) {
#     error 751 "http://" + regsub(req.http.host, "^www\.", "") + req.url;
#   }
# }
# sub perm_redirections_error {
#   if (obj.status == 751) {
#     /* Get new URL from the response */
#     set obj.http.Location = obj.response;
#     /* Set HTTP 301 for permanent redirect */
#     set obj.status = 301;
#     return(deliver);
#   }
# }

/* VCL logigc overrides */
# Note that the built-in logic will be appended to our code if no return is performed before.
# Built-in logic is included commented out right after our's for reference purposes in that cases.
# See https://www.varnish-cache.org/trac/wiki/VCLExampleDefault
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#subroutines

# vcl_recv: Called at the beginning of a request, after the complete request has been received and parsed.
# Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
sub vcl_recv {
  /* 0th: general bypass, general return & authorization checks */
  # Empty in simple configs.
  # Useful for debugging we can pipe or pass the request to default backend here to bypass completely Varnish.
  # return (pipe);
  # return (pass);
  # We can also return here a 200 Ok for network performance benchmarking.
  # error 200 "Ok";
  # Finally we can perform basic HTTP authentification here by example.
  # See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    return (lookup);
  }
  # Ban logic. See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#bans
  if (req.request == "BAN") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    error 200 "Ban added";
  }
  # Custom response implementation example in order to check that Varnish is working properly.
  # This is usefull for automatic monitoring with monit or when Varnish is behind another proxies like HAProxy.
  if (req.http.host == "monitor.server.health" &&
      client.ip ~ allowed_monitors &&
      (req.request == "OPTIONS" || req.request == "GET")) {
    error 200 "Ok";
  }

  /* 2nd: Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_recv;
  # Here we can also enforce SSL when Varnish run behind some SSL termination point.

  /* 3rd: Time for backend choice */
  # Empty in simple configs.

  /* 4th: Set custom headers for backend like X-Forwarded-For (copied from built-in logic) */
  if ( req.restarts == 0 ) {
    /* See also vcl_pipe section */
    if ( ! client.ip ~ own_proxys ) {
      if ( req.http.x-forwarded-for ) {
        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
      } else {
        set req.http.X-Forwarded-For = client.ip;
      }
    }
  }

  /* 5th: Bypass breakpoint 1 */
  # Useful for debugging we can now pipe or pass the request to backend with headers setted.
  # return (pipe);
  # return (pass);

  /* 6th: Decide if we should deal with a request (mostly copied from built-in logic) */
  if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
  }
  if (req.request != "GET" && req.request != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }
  if (req.http.Authorization) {
    /* Not cacheable by default */
    return (pass);
  }

  /* 7th: Access control for some URLs by ACL */
  # Empty in simple configs.
  # By example denial some URLs depending on client-ip, we'll need to define corresponding ACL 'internal'.
  # if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ internal) {
  #   # Have Varnish throw the error directly.
  #   error 403 "Forbidden.";
  #   # Use a custom error page that you've defined in Drupal at the path "404".
  #   # set req.url = "/403";
  # }

  /* 8th: Custom exceptions */
  # Host exception example:
  # if (req.http.host == "ejemplo.exception.com") {
  #     return (pass);
  # }
  # Drupal exceptions, edit if we want to cache some AJAX/AHAH request.
  # Add here filters for never cache URLs such as Payment Gateway's callbacks
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php$" ||
      req.url ~ "^/ooyala/ping$" ||
      req.url ~ "^/admin/build/features" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$") {
    /* Do not cache these paths */
    return (pass);
  }
  # Pipe these paths directly to backend for streaming.
  if (req.url ~ "^/admin/content/backup_migrate/export") {
    return (pipe);
  }
  if (req.url ~ "^/system/files") {
    return (pipe);
  }

  /* 9th: Enable grace mode */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  if (! req.backend.healthy) {
    /* Use a longer grace period if all backends are down */
    set req.grace = 1h;
    /* Use anonymous, cached pages if all backends are down. */
    unset req.http.Cookie;
    # TO-DO: Add sick marker
  } else {
    /* Allow the backend to serve up stale content if it is responding slowly. */
    set req.grace = 30s;
  }

  /* 10th: Deal with compression and the Accept-Encoding header */
  # Althought Varnish 3 handles gziped content itself by default, just to be sure we want to
  # remove Accept-Encoding for some compressed formats.
  # See https://www.varnish-cache.org/docs/3.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.0/reference/varnishd.html?highlight=http_gzip_support
  # See (for older configs) https://www.varnish-cache.org/trac/wiki/VCLExampleNormalizeAcceptEncoding
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|mp4|flv|zip|rar)$") {
      /* Already compressed formats, no sense trying to compress again */
      remove req.http.Accept-Encoding;
    }
  }

  /* 11th: Another header manipulation */
  # Empty in simple configs.
  # We could add here a custom header grouping User-agent families.

  /* 12th: Cookie removal */
  # Always cache the following static file types for all users.
  # Use with care if we control certain downloads depending on cookies.
  # Be carefull also if appending .htm[l] via Drupal's clean URLs.
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)(\?[a-z0-9]+)?$") {
      unset req.http.Cookie;
  }
  # Remove all cookies that backend doesn't need to know about.
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
  if (req.http.Cookie) {
    /* Warning: Not a pretty solution */
    /* Prefix header containing cookies with ';' */
    set req.http.Cookie = ";" + req.http.Cookie;
    /* Remove any spaces after ';' in header containing cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    /* Prefix cookies we want to preserve with one space */
    /* 'S{1,2}ESS[a-z0-9]+' is the regular expression matching a Drupal session cookie ({1,2} added for HTTPS support) */
    /* 'NO_CACHE' is usually set after a POST request to make sure issuing user see the results of his post */
    /* 'OATMEAL' & 'CHOCOLATECHIP' are special cookies used by Drupal's Bakery module to provide Single Sign On */
    /* Keep in mind we should add here any cookie that should reach the backend such as splahs avoiding cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|OATMEAL|CHOCOLATECHIP)=", "; \1=");
    /* Remove from the header any single Cookie not prefixed with a space until next ';' separator */
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    /* Remove any '; ' at the start or the end of the header */
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      /* If there are no remaining cookies, remove the cookie header. */
      unset req.http.Cookie;
    }
  }

  /* 13th: Session cookie & special cookies bypass caching stage */
  # As we might want to cache some requests, hashed with its cookies,
  # we don't simply pass when some cookies remain present at this point.
  # Instead we look for request that must be passed due to the cookie header.
  if (req.http.Cookie ~ "SESS" ||
      req.http.Cookie ~ "SSESS" ||
      req.http.Cookie ~ "NO_CACHE" ||
      req.http.Cookie ~ "OATMEAL" ||
      req.http.Cookie ~ "CHOCOLATECHIP") {
    return (pass);
  }

  /* 14th: Bypass breakpoint 2 */
  # Useful for debugging we can now pipe or pass the request to backend to bypass cache.
  # return (pipe);
  # return (pass);

  /* 15th: Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning a lookup.
  return (lookup);
}

# vcl_pipe: Called upon entering pipe mode.
# In this mode, the request is passed on to the backend,
# and any further data from either client or backend is passed on unaltered until either end closes the connection.
sub vcl_pipe {
  /* Prevent connection re-using for piped requests */
  # Note that only the first request to the backend will have X-Forwarded-For set.
  # As we use X-Forwarded-For and want to have it set for all requests,
  # we have to make sure connection won't be reused after the request.
  # It is not set by default as it might break some broken web applications, like IIS with NTLM authentication.
  # See https://www.varnish-cache.org/trac/wiki/VCLExamplePipe
  # TO-DO: make sure this is compatible with websockets piping,
  # reference https://www.varnish-cache.org/docs/3.0/tutorial/websockets.html
  set bereq.http.connection = "close";

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (pipe);
}

# vcl_pass: Called upon entering pass mode.
# In this mode, the request is passed on to the backend, and the backend's response is passed on to the client,
# but is not entered into the cache.
# Subsequent requests submitted over the same client connection are handled normally.
# sub vcl_pass {
#     return (pass);
# }

# vcl_hash: You may call hash_data() on the data you would like to add to the hash.
# Hash is used by Varnish to uniquely identify objects.
sub vcl_hash {
  /* Hash cookie data */
  # As requests with same URL and host can produce diferent results when issued with different cookies,
  # we need to store items hashed with the associated cookies. Note that cookies are already sanitized when we reach this point.
  if (req.http.Cookie) {
    /* Include cookie in cache hash */
    hash_data(req.http.Cookie);
  }

  /* Custom header hashing */
  # Empty in simple configs.
  # Example for caching differents object versions by device previously detected (when static content could also vary):
  # if (req.http.X-UA-Device) {
  #   hash_data(req.http.X-UA-Device);
  # }
  # Example for caching diferent object versions by X-Forwarded-Proto, trying to be smart about what kind of request
  # could generate diffetent responses.
  # if (req.http.X-Forwarded-Proto &&
  #     req.url !~ "(?i)\.(png|gif|jpeg|jpg|ico|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)$") {
  #   hash_data(req.http.X-Forwarded-Proto);
  # }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (hash);
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
sub vcl_hit {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hit {
#     return (deliver);
# }

# vcl_miss: Called after a cache lookup if the requested document was not found in the cache.
# Its purpose is to decide whether or not to attempt to retrieve the document from the backend, and which backend to use.
sub vcl_miss {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_miss {
#     return (fetch);
# }

# vcl_fetch: Called after a document has been successfully retrieved from the backend.
sub vcl_fetch {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # See https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl
  # Drupal's Imagecache module can return a 307 redirection to the requested url itself and, depending on Drupal's cache settings,
  # this could lead to a redirection loop being cached for a long time but also we want Varnish to shield a little the backend.
  # See http://drupal.org/node/1248010
  # See http://drupal.org/node/310656
  if (beresp.status == 307 &&
      /* TO-DO: verify that this work better than 'req.url ~ "imagecache"' */
      beresp.http.Location == req.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Enable grace mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  set beresp.grace = 1h;

  /* Enable saint mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#saint-mode
  if (beresp.status == 500) {
    set beresp.saintmode = 20s;
    # TO-DO: consider not restarting POST requests as seen on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return(restart);
  }

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)(\?[a-z0-9]+)?$") {
    unset beresp.http.set-cookie;
  }

  /* Gzip response */
  # Empty in simple configs
  # Use Varnish to Gzip respone, if suitable, before storing it on cache
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.0/phk/gzip.html
  # if (! beresp.http.Content-Encoding &&
  #     (beresp.http.content-type ~ "text" ||
  #      beresp.http.content-type ~ "application/x-javascript" ||
  #      beresp.http.content-type ~ "application/javascript" ||
  #      beresp.http.content-type ~ "application/rss+xml" ||
  #      beresp.http.content-type ~ "application/xml" ||
  #      beresp.http.content-type ~ "Application/JSON")
  # ) {
  #   set beresp.do_gzip = true;
  #   if ( beresp.http.Vary ) {
  #     if ( ! beresp.http.Vary ~ "Accept-Encoding" ) {
  #       set beresp.http.Vary = beresp.http.Vary + ",Accept-Encoding";
  #     }
  #   } else {
  #     set beresp.http.Vary = "Accept-Encoding";
  #   }
  # }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # We can add the name of the backend that has processed the request:
  # set beresp.http.X-Backend = beresp.backend.name;
  # We can use a header to tell if the object was gziped by Varnish
  # if (beresp.do_gzip) {
  #   set beresp.http.X-Varnish-Gzipped = "yes";
  # } else {
  #   set beresp.http.X-Varnish-Gizipped = "no";
  # }
  # We can also add headers informing whether the object is cacheable or not and why.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Varnish3.0
  if (beresp.ttl <= 0s) {
    /* Varnish determined the object was not cacheable */
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
  } elsif (req.http.Cookie ~ "(SESS|SSESS|NO_CACHE|OATMEAL|CHOCOLATECHIP)") {
    /* We don't wish to cache content for logged in users or with certain cookies. Related with our 9th stage on vcl_recv */
    set beresp.http.X-Cacheable = "NO:Cookies";
    # return(hit_for_pass);
  } elsif (beresp.http.Cache-Control ~ "private") {
    /* We are respecting the Cache-Control=private header from the backend */
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    # return(hit_for_pass);
  } else {
    /* Varnish determined the object was cacheable */
    set beresp.http.X-Cacheable = "YES";
  }

  /* Further header manipulation */
  # Empty in simple configs.
  # We can also unset some headers to prevent information disclosure and save some cache space
  # unset beresp.http.Server;
  # unset beresp.http.X-Powered-By;

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_fetch {
#     if (beresp.ttl <= 0s ||
#         beresp.http.Set-Cookie ||
#         beresp.http.Vary == "*") {
#               /*
#                * Mark as "Hit-For-Pass" for the next 2 minutes
#                */
#               set beresp.ttl = 120 s;
#               return (hit_for_pass);
#     }
#     return (deliver);
# }

# vcl_deliver: Called before an object is delivered to the client
sub vcl_deliver {
  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Add whether the object is a cache hit or miss and the number of hits for the object.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
    set resp.http.X-Cache-Hits = obj.hits;
  } else {
    set resp.http.X-Cache = "MISS";
    /* Show the results of cookie sanitization */
    set resp.http.X-Cookie = req.http.Cookie;
  }
  # TO-DO: Add sick marker
  # Restart count
  if ( req.restarts > 0) {
    set resp.http.X-Restarts = req.restarts;
  }
  # Add the Varnish server hostname
  set resp.http.X-Varnish-Server = server.hostname;
  # If we have setted a custom header with device family detected we can show it:
  # if (req.http.X-UA-Device) {
  #   set resp.http.X-UA-Device = req.http.X-UA-Device;
  # }
  # If we have recived a custom header with the protocol in the request we can show it:
  # if (req.http.X-Forwarded-Proto) {
  #   set resp.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto;
  # }

  /* Vary header manipulation */
  # Empty in simple configs.
  # By example, if we are storing & serving diferent objects depending on User-Agent header we must set the correct Vary header:
  # if (resp.http.Vary) {
  #   set resp.http.Vary = resp.http.Vary + ",User-Agent";
  # } else {
  #   set resp.http.Vary = "User-Agent";
  # }

  /* Fake headers */
  # Empty in simple configs
  # We can fake server headers here, by example:
  # set resp.http.Server = "Deep thought";
  # set resp.http.X-Powered-By = "BOFH";
  # Or have some fun with headers:
  # See http://www.nextthing.org/archives/2005/08/07/fun-with-http-headers
  # See http://royal.pingdom.com/2012/08/15/fun-and-unusual-http-response-headers/
  # set resp.http.X-Thank-You = "for bothering to look at my HTTP headers";
  # set resp.http.X-Answer = "42";

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_deliver {
#     return (deliver);
# }

# vcl_error: Called when we hit an error, either explicitly or implicitly due to backend or internal errors.
sub vcl_error {
  /* Avoid DOS vulnerability CVE-2013-4484 */
  # See https://www.varnish-cache.org/lists/pipermail/varnish-announce/2013-October/000686.html
  if (obj.status == 400 || obj.status == 413) {
    return(deliver);
  }

  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_error;

  /* Try to restart request in case of failure */
  # Note that max_restarts defaults to 4
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (obj.status == 503 && req.restarts < 4) {
    set obj.http.X-Restarts = req.restarts;
    return(restart);
  }

  /* Set common headers for synthetic responses */
  set obj.http.Content-Type = "text/html; charset=utf-8";

  /* HTTP Authentification client request */
  # Empty in simple configs. See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* We're using error 200 for monitoring puposes */
  # Consider adding some analytics stuff to trace accesses
  if (obj.status == 200) {
    synthetic {"
      <?xml version="1.0" encoding="utf-8"?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
      <html>
        <head>
          <title>"} + obj.status + " " + obj.response + {"</title>
      </head>
      <body><h1>"} + obj.status + ": " + obj.response + {"</h1></body>
    "};
    return(deliver);
  }

  /* Error page & refresh / redirections */
  # We have plenty of choices when we have to serve an error to the client,
  # from the default error page to javascript black magic or plain redirections.
  # Adding some external statistic javascript to track failures served to clients is strongly suggested.
  # We can't use external resources on synthetic content, everything must be inlined.
  # If we need to include images we can embed them in base64 encoding.
  # Here is the default error page for Varnish 3 (not so pretty)
  set obj.http.Retry-After = "5";
  synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (deliver);
}

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# sub vcl_init {
#       return (ok);
# }

# vcl_fini: Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
# sub vcl_fini {
#       return (ok);
# }

/* Varnish 3 example config for Drupal 7 / Pressflow 6 & 7 */
# Original source: https://github.com/NITEMAN/varnish-bites/varnish4/drupal-base.vcl
# Copyright (c) 2015 Pedro González Serrano and individual contributors.
# MIT License

# Intended to be used both in simple production environments and with learning/teaching purposes.
# Loosely based on http://www.lullabot.com/sites/default/files/default_varnish3.vcl_.txt

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-probes
probe basic {
  /* Only test that backend's IP serves content for '/' */
  # This might be a too heavy probe
  # .url = "/";
  /* Only test that backend's IP has apache working */
  # Nginx would fail this probe with a default config
  .request =
    "OPTIONS * HTTP/1.1"
    "Host: *"
    "Connection: close";
  .interval = 10s;
  .timeout = 2s;
  .window = 8;
  .threshold = 6;
}

/* Backend definitions.*/
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-declarations
backend default {
  /* Default backend on the same machine. WARNING: timeouts could be not big enought for certain POST request */
  .host = "127.0.0.1";
  .port = "8008";
  .connect_timeout = 60s;
  .first_byte_timeout = 60s;
  .between_bytes_timeout = 60s;
  .probe = basic;
}

/* Directors. */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#directors
# Empty in simple configs

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#acls
acl purge_ban {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use '"localhost";' instead
}
acl allowed_monitors {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use'"localhost";' instead
}

/* Custom routines */
# Empty in simple configs.
# We can name subs with no restrictions but as a task can need several chunks of code in diferent states,
# it's a good idea to identify what main sub will call each with a suffix.
# /* Example 301 client redirection removing "www" prefix from request */
# sub perm_redirections_recv {
#   if ( req.http.host ~ "^www.*$" ) {
#     error 751 "http://" + regsub(req.http.host, "^www\.", "") + req.url;
#   }
# }
# sub perm_redirections_error {
#   if (obj.status == 751) {
#     /* Get new URL from the response */
#     set obj.http.Location = obj.response;
#     /* Set HTTP 301 for permanent redirect */
#     set obj.status = 301;
#     return(deliver);
#   }
# }

/* VCL logigc overrides */
# Note that the built-in logic will be appended to our code if no return is performed before.
# Built-in logic is included commented out right after our's for reference purposes in that cases.
# See https://www.varnish-cache.org/trac/wiki/VCLExampleDefault
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#subroutines

# vcl_recv: Called at the beginning of a request, after the complete request has been received and parsed.
# Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
sub vcl_recv {
  /* 0th: general bypass, general return & authorization checks */
  # Empty in simple configs.
  # Useful for debugging we can pipe or pass the request to default backend here to bypass completely Varnish.
  # return (pipe);
  # return (pass);
  # We can also return here a 200 Ok for network performance benchmarking.
  # error 200 "Ok";
  # Finally we can perform basic HTTP authentification here by example.
  # See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    return (lookup);
  }
  # Ban logic. See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#bans
  if (req.request == "BAN") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    error 200 "Ban added";
  }
  # Custom response implementation example in order to check that Varnish is working properly.
  # This is usefull for automatic monitoring with monit or when Varnish is behind another proxies like HAProxy.
  if (req.http.host == "monitor.server.health" &&
      client.ip ~ allowed_monitors &&
      (req.request == "OPTIONS" || req.request == "GET")) {
    error 200 "Ok";
  }

  /* 2nd: Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_recv;
  # Here we can also enforce SSL when Varnish run behind some SSL termination point.

  /* 3rd: Time for backend choice */
  # Empty in simple configs.

  /* 4th: Set custom headers for backend like X-Forwarded-For (copied from built-in logic) */
  if (req.restarts == 0) {
    /* See also vcl_pipe section */
    if (req.http.x-forwarded-for) {
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
    } else {
      set req.http.X-Forwarded-For = client.ip;
    }
  }

  /* 5th: Bypass breakpoint 1 */
  # Useful for debugging we can now pipe or pass the request to backend with headers setted.
  # return (pipe);
  # return (pass);

  /* 6th: Decide if we should deal with a request (mostly copied from built-in logic) */
  if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
  }
  if (req.request != "GET" && req.request != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }
  if (req.http.Authorization) {
    /* Not cacheable by default */
    return (pass);
  }

  /* 7th: Access control for some URLs by ACL */
  # Empty in simple configs.
  # By example denial some URLs depending on client-ip, we'll need to define corresponding ACL 'internal'.
  # if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ internal) {
  #   # Have Varnish throw the error directly.
  #   error 403 "Forbidden.";
  #   # Use a custom error page that you've defined in Drupal at the path "404".
  #   # set req.url = "/403";
  # }

  /* 8th: Custom exceptions */
  # Host exception example:
  # if (req.http.host == "ejemplo.exception.com") {
  #     return (pass);
  # }
  # Drupal exceptions, edit if we want to cache some AJAX/AHAH request.
  # Add here filters for never cache URLs such as Payment Gateway's callbacks
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php$" ||
      req.url ~ "^/ooyala/ping$" ||
      req.url ~ "^/admin/build/features" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$") {
    /* Do not cache these paths */
    return (pass);
  }
  # Pipe these paths directly to backend for streaming.
  if (req.url ~ "^/admin/content/backup_migrate/export") {
    return (pipe);
  }
  if (req.url ~ "^/system/files") {
    return (pipe);
  }

  /* 9th: Enable grace mode */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  if (! req.backend.healthy) {
    /* Use a longer grace period if all backends are down */
    set req.grace = 1h;
    /* Use anonymous, cached pages if all backends are down. */
    unset req.http.Cookie;
    # TO-DO: Add sick marker
  } else {
    /* Allow the backend to serve up stale content if it is responding slowly. */
    set req.grace = 30s;
  }

  /* 10th: Deal with compression and the Accept-Encoding header */
  # Althought Varnish 3 handles gziped content itself by default, just to be sure we want to
  # remove Accept-Encoding for some compressed formats.
  # See https://www.varnish-cache.org/docs/3.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.0/reference/varnishd.html?highlight=http_gzip_support
  # See (for older configs) https://www.varnish-cache.org/trac/wiki/VCLExampleNormalizeAcceptEncoding
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|mp4|flv|zip|rar)$") {
      /* Already compressed formats, no sense trying to compress again */
      remove req.http.Accept-Encoding;
    }
  }

  /* 11th: Another header manipulation */
  # Empty in simple configs.
  # We could add here a custom header grouping User-agent families.

  /* 12th: Cookie removal */
  # Always cache the following static file types for all users.
  # Use with care if we control certain downloads depending on cookies.
  # Be carefull also if appending .htm[l] via Drupal's clean URLs.
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)(\?[a-z0-9]+)?$") {
      unset req.http.Cookie;
  }
  # Remove all cookies that backend doesn't need to know about.
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
  if (req.http.Cookie) {
    /* Warning: Not a pretty solution */
    /* Prefix header containing cookies with ';' */
    set req.http.Cookie = ";" + req.http.Cookie;
    /* Remove any spaces after ';' in header containing cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    /* Prefix cookies we want to preserve with one space */
    /* 'S{1,2}ESS[a-z0-9]+' is the regular expression matching a Drupal session cookie ({1,2} added for HTTPS support) */
    /* 'NO_CACHE' is usually set after a POST request to make sure issuing user see the results of his post */
    /* 'OATMEAL' & 'CHOCOLATECHIP' are special cookies used by Drupal's Bakery module to provide Single Sign On */
    /* Keep in mind we should add here any cookie that should reach the backend such as splahs avoiding cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|OATMEAL|CHOCOLATECHIP)=", "; \1=");
    /* Remove from the header any single Cookie not prefixed with a space until next ';' separator */
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    /* Remove any '; ' at the start or the end of the header */
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      /* If there are no remaining cookies, remove the cookie header. */
      unset req.http.Cookie;
    }
  }

  /* 13th: Session cookie & special cookies bypass caching stage */
  # As we might want to cache some requests, hashed with its cookies,
  # we don't simply pass when some cookies remain present at this point.
  # Instead we look for request that must be passed due to the cookie header.
  if (req.http.Cookie ~ "SESS" ||
      req.http.Cookie ~ "SSESS" ||
      req.http.Cookie ~ "NO_CACHE" ||
      req.http.Cookie ~ "OATMEAL" ||
      req.http.Cookie ~ "CHOCOLATECHIP") {
    return (pass);
  }

  /* 14th: Bypass breakpoint 2 */
  # Useful for debugging we can now pipe or pass the request to backend to bypass cache.
  # return (pipe);
  # return (pass);

  /* 15th: Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning a lookup.
  return (lookup);
}

# vcl_pipe: Called upon entering pipe mode.
# In this mode, the request is passed on to the backend,
# and any further data from either client or backend is passed on unaltered until either end closes the connection.
sub vcl_pipe {
  /* Prevent connection re-using for piped requests */
  # Note that only the first request to the backend will have X-Forwarded-For set.
  # As we use X-Forwarded-For and want to have it set for all requests,
  # we have to make sure connection won't be reused after the request.
  # It is not set by default as it might break some broken web applications, like IIS with NTLM authentication.
  # See https://www.varnish-cache.org/trac/wiki/VCLExamplePipe
  # TO-DO: make sure this is compatible with websockets piping,
  # reference https://www.varnish-cache.org/docs/3.0/tutorial/websockets.html
  set bereq.http.connection = "close";

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (pipe);
}

# vcl_pass: Called upon entering pass mode.
# In this mode, the request is passed on to the backend, and the backend's response is passed on to the client,
# but is not entered into the cache.
# Subsequent requests submitted over the same client connection are handled normally.
# sub vcl_pass {
#     return (pass);
# }

# vcl_hash: You may call hash_data() on the data you would like to add to the hash.
# Hash is used by Varnish to uniquely identify objects.
sub vcl_hash {
  /* Hash cookie data */
  # As requests with same URL and host can produce diferent results when issued with different cookies,
  # we need to store items hashed with the associated cookies. Note that cookies are already sanitized when we reach this point.
  if (req.http.Cookie) {
    /* Include cookie in cache hash */
    hash_data(req.http.Cookie);
  }

  /* Custom header hashing */
  # Empty in simple configs.
  # Example for caching differents object versions by device previously detected (when static content could also vary):
  # if (req.http.X-UA-Device) {
  #   hash_data(req.http.X-UA-Device);
  # }
  # Example for caching diferent object versions by X-Forwarded-Proto, trying to be smart about what kind of request
  # could generate diffetent responses.
  # if (req.http.X-Forwarded-Proto &&
  #     req.url !~ "(?i)\.(png|gif|jpeg|jpg|ico|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)$") {
  #   hash_data(req.http.X-Forwarded-Proto);
  # }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (hash);
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
sub vcl_hit {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hit {
#     return (deliver);
# }

# vcl_miss: Called after a cache lookup if the requested document was not found in the cache.
# Its purpose is to decide whether or not to attempt to retrieve the document from the backend, and which backend to use.
sub vcl_miss {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_miss {
#     return (fetch);
# }

# vcl_fetch: Called after a document has been successfully retrieved from the backend.
sub vcl_fetch {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # See https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl
  # Drupal's Imagecache module can return a 307 redirection to the requested url itself and, depending on Drupal's cache settings,
  # this could lead to a redirection loop being cached for a long time but also we want Varnish to shield a little the backend.
  # See http://drupal.org/node/1248010
  # See http://drupal.org/node/310656
  if (beresp.status == 307 &&
      /* TO-DO: verify that this work better than 'req.url ~ "imagecache"' */
      beresp.http.Location == req.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Enable grace mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  set beresp.grace = 1h;

  /* Enable saint mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#saint-mode
  if (beresp.status == 500) {
    set beresp.saintmode = 20s;
    # TO-DO: consider not restarting POST requests as seen on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return(restart);
  }

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|svg|pdf)(\?[a-z0-9]+)?$") {
    unset beresp.http.set-cookie;
  }

  /* Gzip response */
  # Empty in simple configs
  # Use Varnish to Gzip respone, if suitable, before storing it on cache
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.0/phk/gzip.html
  # if (! beresp.http.Content-Encoding &&
  #     (beresp.http.content-type ~ "text" ||
  #      beresp.http.content-type ~ "application/x-javascript" ||
  #      beresp.http.content-type ~ "application/javascript" ||
  #      beresp.http.content-type ~ "application/rss+xml" ||
  #      beresp.http.content-type ~ "application/xml" ||
  #      beresp.http.content-type ~ "Application/JSON")
  # ) {
  #   set beresp.do_gzip = true;
  #   if ( beresp.http.Vary ) {
  #     if ( ! beresp.http.Vary ~ "Accept-Encoding" ) {
  #       set beresp.http.Vary = beresp.http.Vary + ",Accept-Encoding";
  #     }
  #   } else {
  #     set beresp.http.Vary = "Accept-Encoding";
  #   }
  # }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # We can add the name of the backend that has processed the request:
  # set beresp.http.X-Backend = beresp.backend.name;
  # We can use a header to tell if the object was gziped by Varnish
  # if (beresp.do_gzip) {
  #   set beresp.http.X-Varnish-Gzipped = "yes";
  # } else {
  #   set beresp.http.X-Varnish-Gizipped = "no";
  # }
  # We can also add headers informing whether the object is cacheable or not and why.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Varnish3.0
  if (beresp.ttl <= 0s) {
    /* Varnish determined the object was not cacheable */
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
  } elsif (req.http.Cookie ~ "(SESS|SSESS|NO_CACHE|OATMEAL|CHOCOLATECHIP)") {
    /* We don't wish to cache content for logged in users or with certain cookies. Related with our 9th stage on vcl_recv */
    set beresp.http.X-Cacheable = "NO:Cookies";
    # return(hit_for_pass);
  } elsif (beresp.http.Cache-Control ~ "private") {
    /* We are respecting the Cache-Control=private header from the backend */
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    # return(hit_for_pass);
  } else {
    /* Varnish determined the object was cacheable */
    set beresp.http.X-Cacheable = "YES";
  }

  /* Further header manipulation */
  # Empty in simple configs.
  # We can also unset some headers to prevent information disclosure and save some cache space
  # unset beresp.http.Server;
  # unset beresp.http.X-Powered-By;

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_fetch {
#     if (beresp.ttl <= 0s ||
#         beresp.http.Set-Cookie ||
#         beresp.http.Vary == "*") {
#               /*
#                * Mark as "Hit-For-Pass" for the next 2 minutes
#                */
#               set beresp.ttl = 120 s;
#               return (hit_for_pass);
#     }
#     return (deliver);
# }

# vcl_deliver: Called before an object is delivered to the client
sub vcl_deliver {
  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Add whether the object is a cache hit or miss and the number of hits for the object.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
    set resp.http.X-Cache-Hits = obj.hits;
  } else {
    set resp.http.X-Cache = "MISS";
    /* Show the results of cookie sanitization */
    set resp.http.X-Cookie = req.http.Cookie;
  }
  # TO-DO: Add sick marker
  # Restart count
  if ( req.restarts > 0) {
    set resp.http.X-Restarts = req.restarts;
  }
  # Add the Varnish server hostname
  set resp.http.X-Varnish-Server = server.hostname;
  # If we have setted a custom header with device family detected we can show it:
  # if (req.http.X-UA-Device) {
  #   set resp.http.X-UA-Device = req.http.X-UA-Device;
  # }
  # If we have recived a custom header with the protocol in the request we can show it:
  # if (req.http.X-Forwarded-Proto) {
  #   set resp.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto;
  # }

  /* Vary header manipulation */
  # Empty in simple configs.
  # By example, if we are storing & serving diferent objects depending on User-Agent header we must set the correct Vary header:
  # if (resp.http.Vary) {
  #   set resp.http.Vary = resp.http.Vary + ",User-Agent";
  # } else {
  #   set resp.http.Vary = "User-Agent";
  # }

  /* Fake headers */
  # Empty in simple configs
  # We can fake server headers here, by example:
  # set resp.http.Server = "Deep thought";
  # set resp.http.X-Powered-By = "BOFH";
  # Or have some fun with headers:
  # See http://www.nextthing.org/archives/2005/08/07/fun-with-http-headers
  # See http://royal.pingdom.com/2012/08/15/fun-and-unusual-http-response-headers/
  # set resp.http.X-Thank-You = "for bothering to look at my HTTP headers";
  # set resp.http.X-Answer = "42";

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_deliver {
#     return (deliver);
# }

# vcl_error: Called when we hit an error, either explicitly or implicitly due to backend or internal errors.
sub vcl_error {
  /* Avoid DOS vulnerability CVE-2013-4484 */
  # See https://www.varnish-cache.org/lists/pipermail/varnish-announce/2013-October/000686.html
  if (obj.status == 400 || obj.status == 413) {
    return(deliver);
  }

  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_error;

  /* Try to restart request in case of failure */
  # Note that max_restarts defaults to 4
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (obj.status == 503 && req.restarts < 4) {
    set obj.http.X-Restarts = req.restarts;
    return(restart);
  }

  /* Set common headers for synthetic responses */
  set obj.http.Content-Type = "text/html; charset=utf-8";

  /* HTTP Authentification client request */
  # Empty in simple configs. See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* We're using error 200 for monitoring puposes */
  # Consider adding some analytics stuff to trace accesses
  if (obj.status == 200) {
    synthetic {"
      <?xml version="1.0" encoding="utf-8"?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
      <html>
        <head>
          <title>"} + obj.status + " " + obj.response + {"</title>
      </head>
      <body><h1>"} + obj.status + ": " + obj.response + {"</h1></body>
    "};
    return(deliver);
  }

  /* Error page & refresh / redirections */
  # We have plenty of choices when we have to serve an error to the client,
  # from the default error page to javascript black magic or plain redirections.
  # Adding some external statistic javascript to track failures served to clients is strongly suggested.
  # We can't use external resources on synthetic content, everything must be inlined.
  # If we need to include images we can embed them in base64 encoding.
  # Here is the default error page for Varnish 3 (not so pretty)
  set obj.http.Retry-After = "5";
  synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (deliver);
}

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# sub vcl_init {
#       return (ok);
# }

# vcl_fini: Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
# sub vcl_fini {
#       return (ok);
# }


Configuration for Varnish.

Configuration for Varnish.

# This is a Varnish 4.x VCL file
vcl 4.0;

# Rails server
backend default {
    .host = "127.0.0.1";
    .port = "3000";
}

# Sinatra server
# backend sinatra {
#     .host = "127.0.0.1";
#     .port = "4567";
# }

# Node.js server
# backend nodejs {
#     .host = "127.0.0.1";
#     .port = "5678";
# }

# Handle the HTTP request received by the client
sub vcl_recv {
	if (req.url ~ "^/api/v1") {
        set req.backend_hint = default;
    }

	# if (req.url ~ "^/api/v1/products") {
	#         set req.backend_hint = sinatra;
	#     } else if (req.url ~ "^/api/v2/products") {
	#         set req.backend_hint = sinatra;
	#     } else {
	#         set req.backend_hint = default;
	#     }

	# if (req.url ~ "^/api/v1/products") {
	#         set req.backend_hint = sinatra;
	#     } else if (req.url ~ "^/api/v2/products") {
	#         set req.backend_hint = sinatra;
	#     } else if (req.url ~ "^/api/v3/products") {
	#         set req.backend_hint = nodejs;
	#     } else {
	#         set req.backend_hint = default;
	#     }
}

# This is a Varnish 4.x VCL file
vcl 4.0;

backend default {
    .host = "127.0.0.1";
    .port = "3000";
}

backend sinatra {
    .host = "127.0.0.1";
    .port = "4567";
}

backend nodejs {
    .host = "127.0.0.1";
    .port = "5678";
}

# Handle the HTTP request received by the client
sub vcl_recv {
	if (req.url ~ "^/api/v1/products") {
        set req.backend_hint = sinatra;
    } else if (req.url ~ "^/api/v2/products") {
        set req.backend_hint = sinatra;
    } else if (req.url ~ "^/api/v3/products") {
        set req.backend_hint = nodejs;
    } else {
        set req.backend_hint = default;
    }
}


Add varnish configuration for caching http and https requests differently

# This is a sample VCL configuration file for varnish running in front
# of Alaveteli.  See the vcl(7) man page for details on VCL syntax and
# semantics.

#
# Default backend definition.  Set this to point to your content
# server.  In this case, apache + Passenger running on port 80
#

backend default {
    .host = "127.0.0.1";
    .port = "80";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
}

// set the servers alaveteli can issue a purge from
acl purge {
   "localhost";
   "127.0.0.1";
}

sub vcl_recv {

   # Handle IPv6
   if (req.http.Host ~ "^ipv6.*") {
        set req.http.host = regsub(req.http.host, "^ipv6\.(.*)","www\.\1");
   }

    # Sanitise X-Forwarded-For...
    remove req.http.X-Forwarded-For;
    set req.http.X-Forwarded-For = client.ip;

    # Remove Google Analytics, has_js, and last-seen cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|has_js|has_seen_country_message|seen_foi2)=[^;]*", "");

    # Normalize the Accept-Encoding header
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv|pdf|ico)$") {
            # No point in compressing these
            remove req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        } else {
            # unknown algorithm
            remove req.http.Accept-Encoding;
        }
    }

    # Ignore empty cookies
    if (req.http.Cookie ~ "^\s*$") {
        remove req.http.Cookie;
    }

    if (req.request != "GET" &&
       req.request != "HEAD" &&
       req.request != "POST" &&
       req.request != "PUT" &&
       req.request != "PURGE" &&
       req.request != "DELETE" ) {
        # We don't allow any other methods.
        error 405 "Method Not Allowed";
    }

    if (req.request != "GET" && req.request != "HEAD" && req.request != "PURGE") {
        /* We only deal with GET and HEAD by default, the rest get passed direct to backend */
        return (pass);
    }

    # Ignore Cookies on images...
    if (req.url ~ "\.(png|gif|jpg|jpeg|swf|css|js|rdf|ico|txt)(\?.*|)$") {
        remove req.http.Cookie;
        return (lookup);
    }

    if (req.http.Authorization || req.http.Cookie) {
        return (pass);
    }
    # Let's have a little grace
    set req.grace = 30s;
    # Handle PURGE requests
    if (req.request == "PURGE") {
      if (!client.ip ~ purge) {
         error 405 "Not allowed.";
      }

      # For an explanation of the followng roundabout way of defining
      # ban lists, see
      # http://kristianlyng.wordpress.com/2010/07/28/smart-bans-with-varnish/

      # XXX in Varnish 2.x, the following would be
      # purge("obj.http.x-url ~ " req.url);
      ban("obj.http.x-url ~ " + req.url);
      error 200 "Banned";
    }
    return (lookup);
}

sub vcl_fetch {
    set beresp.http.x-url = req.url;
    if (req.url ~ "\.(png|gif|jpg|jpeg|swf|css|js|rdf|ico|txt)(\?.*|)$") {
    # Ignore backend headers..
        remove beresp.http.set-Cookie;
        set beresp.ttl = 3600s;
        return (deliver);
    }

     if (beresp.status == 404 || beresp.status == 301 || beresp.status == 500) {
        set beresp.ttl = 1m;
        return (deliver);
    }
}

# We need to separately cache requests originating via http and via https
# since we are serving very slightly different content in each case

# Varnish 2.x version of vcl_hash
#sub vcl_hash {
#    set req.hash += req.url;
#    if (req.http.host) {
#        set req.hash += req.http.host;
#    } else {
#        set req.hash += server.ip;
#    }
#
#    # Include the X-Forward-Proto header, since we want to treat HTTPS
#    # requests differently, and make sure this header is always passed
#    # properly to the backend server.
#    if (req.http.X-Forwarded-Proto) {
#        set req.hash += req.http.X-Forwarded-Proto;
#    }
#
#    return (hash);
#}

# Varnish 3 version of vcl_hash
sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # Include the X-Forward-Proto header, since we want to treat HTTPS
    # requests differently, and make sure this header is always passed
    # properly to the backend server.
    if (req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }

    return (hash);
}


Added X-Language and X-Province headers to response.

vcl 4.0;

import directors;
import std;

###
# Varnish Documentation
#   https://www.varnish-cache.org/docs/trunk/users-guide/vcl-built-in-subs.html
#   https://www.varnish-cache.org/docs/trunk/reference/vcl.html
##

{% for backend in varnish_backend_hosts %}
backend application_{{ loop.index }} {
  .host = "{{ backend }}";
  .port = "{{ varnish_backend_port }}";
{% if varnish_health_checks_enabled %}
  .probe = {
    .url = "{{ varnish_health_check_url }}";
    .interval = {{ varnish_health_check_interval }};
    .timeout  = {{ varnish_health_check_timeout }};
    .window = {{ varnish_health_check_window }};
    .threshold = {{ varnish_health_check_threshold }};
  }
{% endif %}
}
{% endfor %}

###
# vcl_init
#   Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
###
# The vcl_init subroutine may terminate with calling return() with one of the following keywords:
#
# ok
#   Normal return, VCL continues loading.
##

sub vcl_init {
  new application = directors.round_robin();
{% for backend in varnish_backend_hosts %}
  application.add_backend(application_{{ loop.index }});
{% endfor %}
}

###
# vcl_recv
#   Called at the beginning of a request, after the complete request has been received and parsed.
#   Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
#   It is also used to modify the request
###
# The vcl_recv subroutine may terminate with calling return() on one of the following keywords:
#
# synth(status code, reason)
#   Return a synthetic object with the specified status code to the client and abandon the request.
# pass
#   Switch to pass mode. Control will eventually pass to vcl_pass.
# pipe
#   Switch to pipe mode. Control will eventually pass to vcl_pipe.
# hash
#   Continue processing the object as a potential candidate for caching. Passes the control over to vcl_hash.
# purge
#   Purge the object and it's variants. Control passes through vcl_hash to vcl_purge.
#

sub vcl_recv {
  set req.backend_hint = application.backend();

  ###
  # Avoid processing uncacheable requests
  ###

  if (req.http.Authorization) {
    return (pass);
  }

  ###
  # Inject X-Forwarded-For headers, but only once.
  ###

  if (req.restarts == 0) {
    if (req.http.X-Forwarded-For) {
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
    } else {
      set req.http.X-Forwarded-For = client.ip;
    }
  }

{% if varnish_header_sanitization_enabled %}
  ###
  # Header Sanitization
  ###

{% if varnish_discards_port_from_host_header %}
  set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
{% endif %}

  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
      unset req.http.Accept-Encoding;
    } elsif (req.http.Accept-Encoding ~ "gzip") {
      set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
      set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_enabled %}
  ###
  # Cookie Sanitization
  ###

  ### Google Analytics
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### Quantcast
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### AddThis
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### General Cleanup
  set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
  if (req.http.cookie ~ "^\s*$") {
      unset req.http.cookie;
  }
{% endif %}

{% if varnish_uri_sanitization_enabled %}
  ###
  # URI Sanitization
  ###

  if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
    set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
    set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
    set req.url = regsub(req.url, "\?&", "?");
    set req.url = regsub(req.url, "\?$", "");
  }
  if (req.url ~ "\#") {
    set req.url = regsub(req.url, "\#.*$", "");
  }

{% endif %}

{% if varnish_workaround_telusdotcom_browser_profile %}
  ###
  # Workaround for BrowserProfile and Language/Region Detection on TELUS.com
  ###

  if (req.http.Cookie ~ "BrowserProfile") {
    set req.http.X-Language = regsuball(req.http.Cookie, "language..:\\.(.*)\\.,", "\1");
    set req.http.X-Province = regsuball(req.http.Cookie, "region..:\\.(.*)\\.,", "\1");
  } else {
    if (req.http.Cookie ~ "lang=") {
      set req.http.X-Language = regsuball(req.http.Cookie, "lang=(.*);", "\1");
    } else {
      set req.http.X-Language = "en";
    }

    if (req.http.Cookie ~ "prov=") {
      set req.http.X-Province = regsuball(req.http.Cookie, "prov=(.*);", "\1");
    } else {
      set req.http.X-Province = "BC";
    }
  }

  if (req.url ~ "/(en|fr)/") {
    if (req.url ~ "/en/" && req.http.X-Language != "en") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Language)";
      return(pass);
    }
    if (req.url ~ "/fr/" && req.http.X-Language != "fr") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Language)";
      return(pass);
    }
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Language)";
    return(pass);
  }

  if (req.url ~ "/(ab|bc|mb|nb|nl|ns|nt|nu|on|pe|qc|sk|yt)/") {
    {% for province in ['ab', 'bc', 'mb', 'nb', 'nl', 'ns', 'nt', 'nu', 'on', 'pe', 'qc', 'sk', 'yt'] %}
    if (req.url ~ "{{ province }}" && req.http.X-Province != "{{ province }}") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Province)";
      return(pass);
    }
    {% endfor %}
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Province)";
    return(pass);
  }
{% endif %}

{% if varnish_blacklist_enabled %}
  if ((req.url ~ "{{ varnish_blacklist_regexp }}")) {
    set req.http.X-Passthrough-Reason = "Path in Blacklist";
    return(pass);
  } else {
{% if varnish_discards_client_cookies %}
    unset req.http.Cookie;
{% endif %}
  }
{% endif %}

}

###
# vcl_hit
#   Called when a cache lookup is successful.
###
# The vcl_hit subroutine may terminate with calling return() with one of the following keywords:
#
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
# deliver
#   Deliver the object. Control passes to vcl_deliver.
# synth(status code, reason)
#   Return the specified status code to the client and abandon the request.
###

sub vcl_hit {
  if (obj.ttl > 0s) {
    return (deliver);
  }
{% if varnish_health_checks_enabled %}
  if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
    return (deliver);
  } else {
    return (fetch);
  }
{% else %}
  if (obj.ttl + obj.grace > 0s) {
     return (deliver);
  }

  return (fetch);
{% endif %}
}

###
# vcl_backend_response
#   Called after the response headers has been successfully retrieved from the backend.
###
# The vcl_backend_response subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Possibly insert the object into the cache, then deliver it to the Control will eventually pass to vcl_deliver.
# abandon
#   Abandon the backend request and generates an error.
# retry
#   Retry the backend transaction. Increases the retries counter. If the number of retries is higher than max_retries Varnish emits a guru meditation error.
###

sub vcl_backend_response {
{% if varnish_workaround_telusdotcom_browser_profile %}
  if (bereq.http.X-Language) {
    set bereq.http.X-Language;
  }
  if (bereq.http.X-Province) {
    set bereq.http.X-Province;
  }
{% endif %}

{% if varnish_blacklist_enabled %}
  if (bereq.url ~ "{{ varnish_blacklist_regexp }}") {
    set beresp.http.X-Cacheable = "NO:Path in Blacklist";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    if (bereq.http.X-Passthrough-Reason) {
      set beresp.http.X-Passthrough-Reason = bereq.http.X-Passthrough-Reason;
      return(deliver);
    } else {
{% if varnish_discards_server_cookies %}
      unset beresp.http.Set-Cookie;
{% endif %}
    }
  }
{% else %}
{% if varnish_discards_server_cookies %}
  unset beresp.http.Set-Cookie;
{% endif %}
{% endif %}

{% if varnish_cache_diagnostics_enabled %}
  if (bereq.http.Cookie) {
    set beresp.http.X-Cacheable = "NO:Cookie in Request";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Set-Cookie) {
    set beresp.http.X-Cacheable = "NO:Set-Cookie in Response";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.X-No-Cache) {
    set beresp.http.X-Cacheable = "NO:X-No-Cache";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    set beresp.http.X-Cacheable = "YES";
  }
{% endif %}

  set beresp.grace = {{ varnish_grace_period }};
}

###
# vcl_deliver
#   Called before a cached object is delivered to the client.
###
# The vcl_deliver subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Deliver the object to the client.
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
###

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
}

vcl 4.0;

import directors;
import std;

###
# Varnish Documentation
#   https://www.varnish-cache.org/docs/trunk/users-guide/vcl-built-in-subs.html
#   https://www.varnish-cache.org/docs/trunk/reference/vcl.html
##

{% for backend in varnish_backend_hosts %}
backend application_{{ loop.index }} {
  .host = "{{ backend }}";
  .port = "{{ varnish_backend_port }}";
{% if varnish_health_checks_enabled %}
  .probe = {
    .url = "{{ varnish_health_check_url }}";
    .interval = {{ varnish_health_check_interval }};
    .timeout  = {{ varnish_health_check_timeout }};
    .window = {{ varnish_health_check_window }};
    .threshold = {{ varnish_health_check_threshold }};
  }
{% endif %}
}
{% endfor %}

###
# vcl_init
#   Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
###
# The vcl_init subroutine may terminate with calling return() with one of the following keywords:
#
# ok
#   Normal return, VCL continues loading.
##

sub vcl_init {
  new application = directors.round_robin();
{% for backend in varnish_backend_hosts %}
  application.add_backend(application_{{ loop.index }});
{% endfor %}
}

###
# vcl_recv
#   Called at the beginning of a request, after the complete request has been received and parsed.
#   Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
#   It is also used to modify the request
###
# The vcl_recv subroutine may terminate with calling return() on one of the following keywords:
#
# synth(status code, reason)
#   Return a synthetic object with the specified status code to the client and abandon the request.
# pass
#   Switch to pass mode. Control will eventually pass to vcl_pass.
# pipe
#   Switch to pipe mode. Control will eventually pass to vcl_pipe.
# hash
#   Continue processing the object as a potential candidate for caching. Passes the control over to vcl_hash.
# purge
#   Purge the object and it's variants. Control passes through vcl_hash to vcl_purge.
#

sub vcl_recv {
  set req.backend_hint = application.backend();

  ###
  # Avoid processing uncacheable requests
  ###

  if (req.http.Authorization) {
    return (pass);
  }

  ###
  # Inject X-Forwarded-For headers, but only once.
  ###

  if (req.restarts == 0) {
    if (req.http.X-Forwarded-For) {
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
    } else {
      set req.http.X-Forwarded-For = client.ip;
    }
  }

{% if varnish_header_sanitization_enabled %}
  ###
  # Header Sanitization
  ###

{% if varnish_discards_port_from_host_header %}
  set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
{% endif %}

  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
      unset req.http.Accept-Encoding;
    } elsif (req.http.Accept-Encoding ~ "gzip") {
      set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
      set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_enabled %}
  ###
  # Cookie Sanitization
  ###

  ### Google Analytics
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### Quantcast
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### AddThis
  set req.http.Cookie = regsuball(req.http.Cookie, "***REMOVED***=[^;]+(; )?", "");

  ### General Cleanup
  set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
  if (req.http.cookie ~ "^\s*$") {
      unset req.http.cookie;
  }
{% endif %}

{% if varnish_uri_sanitization_enabled %}
  ###
  # URI Sanitization
  ###

  if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
    set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
    set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
    set req.url = regsub(req.url, "\?&", "?");
    set req.url = regsub(req.url, "\?$", "");
  }
  if (req.url ~ "\#") {
    set req.url = regsub(req.url, "\#.*$", "");
  }

{% endif %}

{% if varnish_workaround_telusdotcom_browser_profile %}
  ###
  # Workaround for BrowserProfile and Language/Region Detection on TELUS.com
  ###

  if (req.http.Cookie ~ "BrowserProfile") {
    set req.http.X-Language = regsuball(req.http.Cookie, "language..:\\.(.*)\\.,", "\1");
    set req.http.X-Province = regsuball(req.http.Cookie, "region..:\\.(.*)\\.,", "\1");
  } else {
    if (req.http.Cookie ~ "lang=") {
      set req.http.X-Language = regsuball(req.http.Cookie, "lang=(.*);", "\1");
    } else {
      set req.http.X-Language = "en";
    }

    if (req.http.Cookie ~ "prov=") {
      set req.http.X-Province = regsuball(req.http.Cookie, "prov=(.*);", "\1");
    } else {
      set req.http.X-Province = "BC";
    }
  }

  if (req.url ~ "/(en|fr)/") {
    if (req.url ~ "/en/" && req.http.X-Language != "en") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Language)";
      return(pass);
    }
    if (req.url ~ "/fr/" && req.http.X-Language != "fr") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Language)";
      return(pass);
    }
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Language)";
    return(pass);
  }

  if (req.url ~ "/(ab|bc|mb|nb|nl|ns|nt|nu|on|pe|qc|sk|yt)/") {
    {% for province in ['ab', 'bc', 'mb', 'nb', 'nl', 'ns', 'nt', 'nu', 'on', 'pe', 'qc', 'sk', 'yt'] %}
    if (req.url ~ "{{ province }}" && req.http.X-Province != "{{ province }}") {
      set req.http.X-Passthrough-Reason = "Unaligned Path and Cookie (Province)";
      return(pass);
    }
    {% endfor %}
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Province)";
    return(pass);
  }
{% endif %}

{% if varnish_blacklist_enabled %}
  if ((req.url ~ "{{ varnish_blacklist_regexp }}")) {
    set req.http.X-Passthrough-Reason = "Path in Blacklist";
    return(pass);
  } else {
{% if varnish_discards_client_cookies %}
    unset req.http.Cookie;
{% endif %}
  }
{% endif %}

}

###
# vcl_hit
#   Called when a cache lookup is successful.
###
# The vcl_hit subroutine may terminate with calling return() with one of the following keywords:
#
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
# deliver
#   Deliver the object. Control passes to vcl_deliver.
# synth(status code, reason)
#   Return the specified status code to the client and abandon the request.
###

sub vcl_hit {
  if (obj.ttl > 0s) {
    return (deliver);
  }
{% if varnish_health_checks_enabled %}
  if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
    return (deliver);
  } else {
    return (fetch);
  }
{% else %}
  if (obj.ttl + obj.grace > 0s) {
     return (deliver);
  }

  return (fetch);
{% endif %}
}

###
# vcl_backend_response
#   Called after the response headers has been successfully retrieved from the backend.
###
# The vcl_backend_response subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Possibly insert the object into the cache, then deliver it to the Control will eventually pass to vcl_deliver.
# abandon
#   Abandon the backend request and generates an error.
# retry
#   Retry the backend transaction. Increases the retries counter. If the number of retries is higher than max_retries Varnish emits a guru meditation error.
###

sub vcl_backend_response {
{% if varnish_blacklist_enabled %}
  if (bereq.url ~ "{{ varnish_blacklist_regexp }}") {
    set beresp.http.X-Cacheable = "NO:Path in Blacklist";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    if (bereq.http.X-Passthrough-Reason) {
      set beresp.http.X-Passthrough-Reason = bereq.http.X-Passthrough-Reason;
      return(deliver);
    } else {
{% if varnish_discards_server_cookies %}
      unset beresp.http.Set-Cookie;
{% endif %}
    }
  }
{% else %}
{% if varnish_discards_server_cookies %}
  unset beresp.http.Set-Cookie;
{% endif %}
{% endif %}

{% if varnish_cache_diagnostics_enabled %}
  if (bereq.http.Cookie) {
    set beresp.http.X-Cacheable = "NO:Cookie in Request";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Set-Cookie) {
    set beresp.http.X-Cacheable = "NO:Set-Cookie in Response";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.X-No-Cache) {
    set beresp.http.X-Cacheable = "NO:X-No-Cache";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    set beresp.http.X-Cacheable = "YES";
  }
{% endif %}

  set beresp.grace = {{ varnish_grace_period }};
}

###
# vcl_deliver
#   Called before a cached object is delivered to the client.
###
# The vcl_deliver subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Deliver the object to the client.
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
###

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
}