Mike Slinn

Jekyll Plugin Snippets

Published 2023-01-10. Last modified 2024-01-24.
Time to read: 2 minutes.

This page is part of the jekyll collection.

The Visual Studio Code extension called Snippet by Devon Ray is a real timesaver. I have defined snippets for my Jekyll plugins. To use the VSCode Snippets extension with my snippets, install the plugin, then save the following file to ~/.config/Code/User/snippets/html.json. For some reason, one of my 3 Windows machines needs that file installed to %AppData%\Code\User\snippets\html.json.

{
  // Place your snippets for html here. Each snippet is defined under a snippet name and has a prefix, body and
  // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
  // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
  // same ids are connected.
  // Example:
  // "Print to console": {
  // 	"prefix": "log",
  // 	"body": [
  // 		"console.log('$1');",
  // 		"$2"
  // 	],
  // 	"description": "Log output to console"
  // }
  //
  // Run html_json_update after modifying this file

  "Insert archive_display invocation": {
    "prefix": "archive_display",
    "body": [
      "{% archive_display $1 %}"
    ],
    "description": "Insert an {% archive_display %} plugin invocation"
  },

  "Insert basename invocation": {
    "prefix": "basename",
    "body": [
      "{{ 'blah/blah/filename.ext' | basename }}"
    ],
    "description": "Insert a {{ basename }} filter invocation"
  },

  "Insert basename_without_extension invocation": {
    "prefix": "basename_without_extension",
    "body": [
      "{{ 'blah/blah/filename.ext' | basename_without_extension }}"
    ],
    "description": "Insert an {{ basename_without_extension }} filter invocation"
  },

  "Insert background yellow": {
    "prefix": "bg_yellow",
    "body": [
      "<span class='bg_yellow'></span>"
    ],
    "description": "Insert a padded yellow background span."
  },

  "Insert background yellow nopad": {
    "prefix": "bg_yellow_nopad",
    "body": [
      "<span class='bg_yellow_nopad'></span>"
    ],
    "description": "Insert a yellow background span without padding."
  },




  "Insert todays date": {
    "prefix": "date",
    "body": [
      "$CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}"
    ],
    "description": "Insert today's date YYYY-mm-dd."
  },

  "Insert days_since invocation": {
    "prefix": "days_since",
    "body": [
      "{{ '1959' | days_since }}"
    ],
    "description": "Insert a {{ days_since }} plugin invocation. A wide variety of date formats can be used."
  },

  "Insert dirname invocation": {
    "prefix": "dirname",
    "body": [
      "{{ 'blah/blah/filename.ext' | dirname }}"
    ],
    "description": "Insert an {{ dirname }} filter invocation"
  },

  "Insert download_link invocation": {
    "prefix": "download_link",
    "body": [
      "{% download_link $1 %}"
    ],
    "description": "Insert a {% download_link %} filter invocation"
  },

  "Insert emoji": {
    "prefix": "emoji",
    "body": [
      "{% emoji name='smiley' align='right' size='3em' %}"
    ],
    "description": "Emojis are: angry, boom, clap, confounded, eggplant, grimace, grin, halo, horns, kiss, loudly_cry, notes, open, please, poop, rolling, sad, sax, scream, smiley, smirk, sunglasses, think, two_hearts, wink, worried, unamused, vulcan, zipper."
  },

  "Insert exec": {
    "prefix": "exec",
    "body": [
      "{% exec $1 %}"
    ],
    "description": "Insert a minimal {% exec %} plugin invocation; should be placed within a {% pre %} tag."
  },

  "Insert exec max": {
    "prefix": "exec_max",
    "body": [
      "{% exec die_if_error die_if_nonzero no_escape no_strip cd='.' $1 %}"
    ],
    "description": "Insert a full {% exec %} plugin invocation with all options; should be placed within a {% pre %} tag."
  },

  "Insert flexible_include maximal invocation": {
    "prefix": "flexible_include_max",
    "body": [
      "{% flexible_include copyButton dark do_not_escape download file='$1' label='$2' highlight='[\\w./\\-_]*django-admin[\\w.\\-_]*' number pre %}"
    ],
    "description": "Insert a full {% flexible_include %} plugin invocation with all available options."
  },

  "Insert flexible_include minimal invocation": {
    "prefix": "flexible_include",
    "body": [
      "{% flexible_include file='$1' %}"
    ],
    "description": "Insert a minimal {% flexible_include %} plugin invocation with only the necessary options."
  },

  "Insert from, to and until invocations": {
    "prefix": "from_to_until",
    "body": [
      "{{ '$1' | from: '$2' | to: '$3' | until: '$3' }}"
    ],
    "description": "Insert a chained {{ from }}, {{ to }} and {{ until }} plugin invocation."
  },

  "Insert AV Studio front matter": {
    "prefix": "front_matter_av_studio",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: av_studio",
      "order: $4",
      "published: false",
      "title: '$6'",
      "---"
    ],
    "description": "Insert AV Studio front matter."
  },

  "Insert Blog front matter": {
    "prefix": "front_matter_blog",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: blog",
      "title: '$4'",
      "---"
    ],
    "description": "Insert Blog front matter."
  },

  "Insert Evelyn front matter": {
    "prefix": "front_matter_evelyn",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: evelyn",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert Evelyn front matter."
  },

  "Insert Git front matter": {
    "prefix": "front_matter_git",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: git",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert Git front matter."
  },

  "Insert Jekyll front matter": {
    "prefix": "front_matter_jekyll",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: jekyll",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert Jekyll front matter."
  },

  "Insert LLM front matter": {
    "prefix": "front_matter_llm",
    "body": [
      "---",
      "categories: [ AI, LLM, $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: llm",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert LLM front matter."
  },

  "Insert Mainframe front matter": {
    "prefix": "front_matter_mainframe",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: mainframe",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert mainframe front matter."
  },
  "Insert Ruby front matter": {
    "prefix": "front_matter_ruby",
    "body": [
      "---",
      "categories: [ $1 ]",
      "date: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "description: 35 characters.",
      "javascriptEnd: /assets/js/clipboard.min.js",
      "javascriptInline: new ClipboardJS('.copyBtn');",
      "last_modified_at: $CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}",
      "layout: ruby",
      "order: $4",
      "published: false",
      "title: '$5'",
      "---"
    ],
    "description": "Insert Ruby front matter."
  },

  "Insert Song front matter": {
    "prefix": "front_matter_song",
    "body": [
      "---",
      "composed: $1",
      "date: $2",
      "description: $3, an original composition by Mike Slinn. All rights reserved.",
      "guitar_pro_file: ",
      "image: ",
      "last_modified_at: $4",
      "layout: songs",
      "live_file: ",
      "message: \"\"",
      "mp3: ",
      "musicxml: ",
      "order: $5",
      "pdf: ",
      "pro_tools: ",
      "published: false",
      "qr_code: $6",
      "title: \"$7\"",
      "youtube: ",
      "---"
    ],
    "description": "Insert Song front matter."
  },

  "Insert href minimal": {
    "prefix": "href",
    "body": [
      "{% href label='$1' url='$2' %}"
    ],
    "description": "Insert a minimal {% href %} plugin invocation with only the necessary options."
  },

  "Insert href maximal invocation": {
    "prefix": "href_max",
    "body": [
      "{% href attribution follow match label='$1' summary='$2' summary_exclude target='none' url='$3' %}"
    ],
    "description": "Insert a full {% href %} plugin invocation using all available options."
  },

  "Insert href_summary invocation": {
    "prefix": "href_summary",
    "body": [
      "{% href_summary attribution include_local %}"
    ],
    "description": "Insert a full {% href_summary %} plugin invocation with all options."
  },

  "Insert img url only": {
    "prefix": "img",
    "body": [
      "{% img src='$1' %}"
    ],
    "description": "Insert a minimal {% href %} plugin url invocation."
  },

  "Insert img maximal invocation": {
    "prefix": "img_max",
    "body": [
      "{% img",
      "  align='left|center|right'",
      "  caption='$1'",
      "  class='rounded shadow'",
      "  size='initial|halfsize|fullsize|quartersize|eighthsize|15px|10%'",
      "  src='$2'",
      "  url='$3'",
      "  wrapper_class=''",
      "  wrapper_style=''",
      "%}"
    ],
    "description": "Insert a full {% href %} plugin invocation with all available options."
  },

  "Insert math-field": {
    "prefix": "mathfield",
    "body": [
      "<p>",
      "  <math-field style='font-size:2rem;'>\\displaystyle (\\epsilon_\\theta - \\epsilon)</math-field>",
      "</p>"
    ],
    "description": "Insert a normal-font MathLive expression."
  },

  "Insert mathlive large": {
    "prefix": "mathlive_large",
    "body": [
      "<p class='center mathlive' style='font-size: 20pt;'>",
      "  $1",
      "</p>"
    ],
    "description": "Insert a large-font MathLive expression."
  },

  "Insert mathlive small": {
    "prefix": "mathlive_small",
    "body": [
      "<span class='mathlive'>$1</span>"
    ],
    "description": "Insert a small-font MathLive expression."
  },

  "Insert months_since invocation": {
    "prefix": "months_since",
    "body": [
      "{{{ '1959' | months_since }}"
    ],
    "description": "Insert a {{ months_since }} plugin invocation. A wide variety of date formats can be used."
  },

  "Insert noselect": {
    "prefix": "noselect",
    "body": [
      "{% noselect $1 %}"
    ],
    "description": "Insert a {% noselect %} plugin invocation; should be inserted within a {% pre %} tag."
  },

  "Insert nth filter invocation": {
    "prefix": "nth",
    "body": [
      "{{ '1,2,3,4,5' | split: ',' | nth: 2 }}"
    ],
    "description": "Insert an {{ nth }} plugin invocation."
  },

  "Insert outline invocation": {
    "prefix": "outline",
    "body": [
      "{% outline attribution collection_name %}",
      "      0: Section Head 1",
      "  10000: Section Head 2",
      "  20000: Section Head 3",
      "{% endoutline %}"
    ],
    "description": "Insert an {% outline %} plugin invocation."
  },

  "Insert pre dialog invocation": {
    "prefix": "pre_dialog",
    "body": [
      "<!-- #region pre -->",
      "{% pre copyButton dedent label=\"$1\" %}",
      "{% noselect %}$2",
      "{% noselect $3 %}<br>",
      "{% noselect %}$4",
      "{% noselect $5 %}<br>",
      "{% noselect %}$6",
      "{% noselect $7 %}",
      "{% endpre %}",
      "<!-- endregion -->"
    ],
    "description": "Insert a {% pre %} generic dialog containing several {% noselect %} tags."
  },

  "Insert pre maximal invocation": {
    "prefix": "pre_max",
    "body": [
      "{% pre clear copyButton dark dedent number label=\"$1\"",
      "       class=''",
      "       highlight='regex'",
      "       label='Label'",
      "       style=''",
      "%}",
      "{% noselect %}$2",
      "{% noselect $3 %}<br>",
      "{% noselect %}$4",
      "{% noselect $5 %}",
      "{% exec die_if_error die_if_nonzero no_escape no_strip cd='.' ls %}",
      "{% endpre %}"
    ],
    "description": "Insert a full generic {% pre %} plugin invocation with all available options, and embedded {% noselect %} and {% exec %} tags."
  },

  "Insert pre minimal invocation": {
    "prefix": "pre_min",
    "body": [
      "<!-- #region pre -->",
      "{% pre copyButton dedent label=\"$1\" %}",
      "{% endpre %}",
      "<!-- endregion -->"
    ],
    "description": "Insert a minimal generic {% pre %} plugin invocation with only the necessary options."
  },

  "Insert pre Scala REPL invocation": {
    "prefix": "pre_scala_repl",
    "body": [
      "<!-- #region pre Scala REPL -->",
      "{% pre copyButton dedent label=\"Scala REPL\" %}",
      "{% noselect scala&gt; %}$1",
      "{% noselect $2 %}<br>",
      "{% noselect scala&gt; %}$3",
      "{% noselect $4 %}",
      "{% endpre %}",
      "<!-- endregion -->"
    ],
    "description": "Insert a pre Scala REPL plugin invocation."
  },

  "Insert pre shell invocation": {
    "prefix": "pre_shell",
    "body": [
      "<!-- #region pre -->",
      "{% pre copyButton dedent %}",
      "$1",
      "{% endpre %}",
      "<!-- endregion -->"
    ],
    "description": "Insert a minimal {% pre %} plugin invocation for shell commands."
  },

  "Insert HTML region": {
    "prefix": "region",
    "body": [
      "<!-- #region $1 -->",
      "<h2 id=\"$2\">$3</h2>",
      "<p>",
      "  $4",
      "</p>",
      "<!-- endregion -->"
    ],
    "description": "Insert an HTML region containing an H2 tag."
  },


  "Insert HTML region_pre": {
    "prefix": "region_pre",
    "body": [
      "<!-- #region $1 -->",
      "<h2 id=\"$2\">$3</h2>",
      "<p>",
      "  $4",
      "</p>",
      "<!-- #region pre -->",
      "{% pre dedent copyButton shell %}",
      "{% noselect $4 %}",
      "{% endpre %}",
      "<!-- endregion -->",
      "<!-- endregion -->"
    ],
    "description": "Insert an HTML region containing an H2 tag and a pre section."
  },


  "Insert quote minimal invocation": {
    "prefix": "quote",
    "body": [
      "{% quote %}",
      "  $3",
      "{% endquote %}"
    ],
    "description": "Insert a minimal {% quote %} plugin invocation with only the necessary options."
  },

  "Insert quote maximal invocation": {
    "prefix": "quote_max",
    "body": [
      "{% quote break by noprep",
      "     cite='$1'",
      "     url='$2' %}",
      "  $3",
      "{% endquote %}"
    ],
    "description": "Insert a full {% quote %} plugin invocation with all available options."
  },

  "Insert random_hex_string invocation": {
    "prefix": "random_hex_string",
    "body": [
      "{% assign id = random_hex_string %}"
    ],
    "description": "Insert a random_hex_string plugin invocation."
  },

  "Insert region start tag": {
    "prefix": "region_start",
    "body": [
      "<!-- #region $1 -->"
    ],
    "description": "Insert a #region start tag."
  },

  "Insert region stop tag": {
    "prefix": "region_end",
    "body": [
      "<!-- endregion -->"
    ],
    "description": "Insert a #region end tag."
  },

  "Insert run invocation": {
    "prefix": "run",
    "body": [
      "{% run echo 'asdf' %}"
    ],
    "description": "Insert a {% run %} plugin invocation."
  },

  "Insert snippet definition": {
    "prefix": "snippet_definition",
    "body": [
      "  \"Insert $1\": {",
      "  \"prefix\": \"$2\",",
      "  \"body\": [",
      "    \"$3\",",
      "  ],",
      "  \"description\": \"$4\"",
      "},"
    ],
    "description": "Insert a snippet definition."
  },

  "Insert HTML table": {
    "prefix": "table",
    "body": [
      "<table class='noborder table'>",
      "  <tr>",
      "    <th>Head1</th>",
      "    <th>Head2</th>",
      "    <th>Head3</th>",
      "  </tr>",
      "  <tr>",
      "    <td></td>",
      "    <td></td>",
      "    <td></td>",
      "  </tr>",
      "  <tr>",
      "    <td></td>",
      "    <td></td>",
      "    <td></td>",
      "  </tr>",
      "</table>"
    ],
    "description": "Insert a typical table definition."
  },

  "Insert HTML table with all options": {
    "prefix": "table_max",
    "body": [
      "<table class='condensed info info2 noborder table table_cell_top table_cell_vspace'>",
      "  <tr>",
      "    <th nobreak>Non_Breaking_Head</th>",
      "    <th tableLabel>TableLabel</th>",
      "    <th>Head3</th>",
      "  </tr>",
      "  <tr>",
      "    <td nobreak></td>",
      "    <td></td>",
      "    <td></td>",
      "  </tr>",
      "  <tr>",
      "    <td nobreak></td>",
      "    <td></td>",
      "    <td></td>",
      "  </tr>",
      "</table>"
    ],
    "description": "Insert a full table definition with all available CSS classes."
  },

  "Insert JTabs": {
    "prefix": "tabs",
    "body": [
      "<div class='jtabs'>",
      "  <div id='jtabs-headers'>",
      "    <div>$1</div>",
      "    <div>$2</div>",
      "    <div>$3</div>",
      "    <div>$4</div>",
      "  </div>",
      "  <div id='jtabs-content'>",
      "    <div id='jtabs1'>",
      "      $5",
      "    </div>",
      "    <div id='jtabs2'>",
      "      $6",
      "    </div>",
      "    <div id='jtabs3'>",
      "      $7",
      "    </div>",
      "    <div id='jtabs4'>",
      "      $8",
      "    </div>",
      "  </div>",
      "</div>"
    ],
    "description": "Insert a typical jSuites.tabs HTML."
  },

  "Insert TODO": {
    "prefix": "todo",
    "body": [
      "{%- comment -%}",
      "TODO: $1",
      "{%- endcomment -%}"
    ],
    "description": "Insert a TODO comment."
  },

  "Insert weeks_since invocation": {
    "prefix": "weeks_since",
    "body": [
      "{{{ '1959' | weeks_since }}"
    ],
    "description": "Insert a {{ weeks_since }} plugin invocation. A wide variety of date formats can be used."
  },

  "wrap in code": {
    "scope": "javascript,html",
    "prefix": "wrap_in_code",
    "body": "<code>$TM_SELECTED_TEXT</code>"
  },

  "Insert years_since invocation": {
    "prefix": "years_since",
    "body": [
      "{{{ '1959' | years_since }}"
    ],
    "description": "Insert a {{ years_since }} plugin invocation. A wide variety of date formats can be used."
  },

  "Insert YouTube": {
    "prefix": "youtube",
    "body": [
      "{% youtube '$1' %}"
    ],
    "description": "Insert {% youtube %} tag; requires the URL of a YouTube video."
  }
}

The above file defines the following snippets. I used my run plugin to generate the output, and it shows the bash commands it ran to produce the output, followed by the output (which is unselectable).

Shell
$ cat ~/.config/Code/User/snippets/html.json | \
  grep -v '//' | \
  jq -r 'values[].prefix' 
archive_display
basename
basename_without_extension
bg_yellow
bg_yellow_nopad
date
days_since
dirname
download_link
emoji
exec
exec_max
flexible_include_max
flexible_include
from_to_until
front_matter_av_studio
front_matter_blog
front_matter_evelyn
front_matter_git
front_matter_jekyll
front_matter_llm
front_matter_mainframe
front_matter_ruby
front_matter_song
href
href_max
href_summary
img
img_max
mathfield
mathlive_large
mathlive_small
months_since
noselect
nth
outline
pre_dialog
pre_max
pre_min
pre_scala_repl
pre_shell
region
region_pre
quote
quote_max
random_hex_string
region_start
region_end
run
snippet_definition
table
table_max
tabs
todo
weeks_since
wrap_in_code
years_since
youtube

But Wait, There Is More!

In addition to snippets for my Jekyll plugins, I defined a snippet, called region, for HTML regions. A region is a foldable section of HTML, set up the way I like when writing articles such as this. If you have a long jekyll_pre passage, like:

HTML or markdown
{% pre %}
blah blah blah
{% endpre %}

... placing it within a foldable region makes the source HTML much easier to work with. Regions within regions allows you to unfold to any degree of detail you require.

HTML or markdown
<!-- #region -->
{% pre %}
blah blah blah
{% endpre %}
<!-- endregion -->

Foldable regions are provided by the regionfolder Visual Studio Code extension by maptz. The inserted nested regions from the snippet look like this:

HTML or markdown
<!-- #region -->
<h2 id='$1'>$2</h2>
<p>
</p>
<!-- #region -->
{% pre shell copyButton %}
{% noselect %}
{% noselect %}
{% endpre %}
<!-- endregion -->
<!-- endregion -->

You control the visibility of nested regions with a series of two keystrokes.

  • All nested regions can be folded by pressing CTRL-K CTRL-0.
  • Unfolding just the first level of nested regions can be accomplished by pressing CTRL-K CTRL-1.
  • Unfolding to the second level of nested regions can be accomplished by pressing CTRL-K CTRL-2.

Key Bindings

Key bindings can also insert snippets. On Windows and WSL, my key bindings are defined in %AppData%/Code/User/keybindings.json. The following additional key binding wraps selected text within <code></code> tags:

%AppData%/Code/User/keybindings.json
{
  "key": "alt+c",
  "command": "editor.action.insertSnippet",
  "when": "editorTextFocus",
  "args": {
    "snippet": "${TM_SELECTED_TEXT}"
  }
},

Videos

Here are some videos that show the Visual Studio Code snippets extension in action.

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.