# record_sheet

id: capybara
git_filename: ./capybara.md
format: md
field_title: Capybara
field_category: Ruby libraries
field_tags: Featurable
field_updated: 2020-06-13
field_updated___timezone: UTC
data:
{"title": "Capybara", "category": "Ruby libraries", "weight": -5, "updated": "2020-06-13", "tags": ["Featurable"], "body": "### Navigating\n\n    visit articles_path\n\n### Clicking links and buttons\n\n```ruby\nclick_on 'Link Text'\nclick_button\nclick_link\n```\n\n### Interacting with forms\n\n```ruby\nattach_file 'Image', '/path/to/image.jpg'\nfill_in 'First Name', with: 'John'\n```\n\n```ruby\ncheck 'A checkbox'\nuncheck 'A checkbox'\n```\n\n```ruby\nchoose 'A radio button'\n```\n\n```ruby\nselect 'Option', from: 'Select box'\nunselect\n```\n\n### Limiting\n\n```ruby\nwithin '.classname' do\n  click '...'\nend\n```\n\n```ruby\nwithin_fieldset :id do\n  ...\nend\n```\n\n## Querying\n\n### Predicates\n\n```ruby\npage.has_css?('.button')\nexpect(page).to have_css('.button')\npage.should have_css('.button')\n```\n{: .-setup}\n\n| Positive                          | Negative               |\n| ---                               | ---                    |\n| `has_content?`                    | `has_no_content?`      |\n| ---                               | ---                    |\n| `has_css?` _(selector)_           | `has_no_css?`          |\n| ---                               | ---                    |\n| `has_xpath?` _(path)_             | `has_no_xpath?`        |\n| ---                               | ---                    |\n| `has_link?` _(selector)_          | `has_no_link?`         |\n| ---                               | ---                    |\n| `has_button?` _(selector)_        | `has_no_button?`       |\n| ---                               | ---                    |\n| `has_field?` _(selector)_         | `has_no_field?`        |\n| ---                               | ---                    |\n| `has_checked_field?` _(selector)_ | `has_unchecked_field?` |\n| ---                               | ---                    |\n| `has_table?` _(selector)_         | `has_no_table?`        |\n| ---                               | ---                    |\n| `has_select?` _(selector)_        | `has_no_select?`       |\n{: .-headers.-left-align}\n\nIn Rspec, these also map to matchers like `page.should have_content`.\n\n### Selectors\n\n```ruby\nexpect(page).to have_button('Save')\n```\n\n```ruby\nexpect(page).to have_button('#submit')\n```\n\n```ruby\nexpect(page).to have_button('//[@id=\"submit\"]')\n```\n\nThe `selector` arguments can be text, CSS selector, or XPath expression.\n\n### RSpec assertions\n\n```ruby\npage.has_button?('Save')\n```\n\n```ruby\nexpect(page).to have_no_button('Save')\n```\n\nIn RSpec, you can use `page.should` assertions.\n\n### About negatives\n\n```ruby\nexpect(page).to have_no_button('Save')\n```\n\n```ruby\nexpect(page).not_to have_button('Save')\n```\n\nThe two above statements are functionally equivalent.\n\n## RSpec\n\n### Matchers\n\n```ruby\nexpect(page).to \\\n```\n{: .-setup}\n\n```ruby\n  have_current_path(expected_path)\n  have_selector '.blank-state'\n  have_selector 'h1#hola', text: 'Welcome'\n  have_button 'Save'\n  have_checked_field '#field'\n  have_unchecked_field\n  have_css '.class'\n  have_field '#field'\n  have_table '#table'\n  have_xpath '//div'\n```\n\n```ruby\n  have_link 'Logout', href: logout_path\n```\n\n```ruby\n  have_select 'Language',\n    selected: 'German'\n    options: ['Engish', 'German']\n    with_options: ['Engish', 'German'] # partial match\n```\n\n```ruby\n  have_text 'Hello',\n    type: :visible # or :all\n    # alias: have_content\n```\n\n### Common options\n\nAll matchers have these options:\n{: .-setup}\n\n```ruby\n  text: 'welcome'\n  text: /Hello/\n  visible: true\n  count: 4\n  between: 2..5\n  minimum: 2\n  maximum: 5\n  wait: 10\n```\n\n## Other features\n\n### Finding\n\n```ruby\nfind(selector)\nfind_button(selector)\nfind_by_id(id)\nfind_field(selector)\nfind_link(selector)\nlocate\n```\n\n### Scoping\n\n```ruby\nwithin '#delivery' do\n  fill_in 'Street', with: 'Hello'\nend\n```\n\n```ruby\nwithin :xpath, '//article'\nwithin_fieldset\nwithin_table\nwithin_frame\nscope_to\n```\n\n```ruby\nfind('#x').fill_in('Street', with: 'Hello')\n# same as within\n```\n\n### Scripting\n\n```ruby\nexecute_script('$(\"input\").trigger(\"change\")')\nevaluate_script('window.ga')\n```\n\nExecutes JavaScript.\n\n### Debugging\n\n```ruby\nsave_and_open_page\n```\n\nOpens the webpage in your browser.\n\n### Page\n\n```ruby\npage\n  .all('h3')\n  .body\n  .html\n  .source\n  .current_host\n  .current_path\n  .current_url\n```\n\n### AJAX\n\n```ruby\nusing_wait_time 10 do\n  ...\nend\n```\n\n### Misc\n\n    drag\n    field_labeled\n\n### Page object\n\n```ruby\npage.status_code == 200\npage.response_headers\n```\n\nSee: <https://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Session>\n\n### Poltergeist\n\n```ruby\nCapybara.register_driver :poltergeist do |app|\n  Capybara::Poltergeist::Driver.new(app, :inspector => true)\nend\nCapybara.javascript_driver = :poltergeist\n```\n\nUse [poltergeist](https://github.com/teampoltergeist/poltergeist) to integrate PhantomJS.\n\n### Blacklist\n\n```ruby\nconfig.before :each, :js do\n  page.driver.browser.url_blacklist = [\n    'fonts.googleapis.com',\n    'use.typekit.net',\n    'f.vimeocdn.com',\n    'player.vimeo.com',\n    'www.googletagmanager.com'\n  ].flat_map { |domain| [ \"http://#{domain}\", \"https://#{domain}\" ] }\nend\n```\n\n### Debugging\n\nEnable `inspector: true` and then:\n{: .-setup}\n\n```ruby\npage.driver.debug\n```\n\nTo pause execution for a while:\n\n```ruby\npage.driver.pause\n```\n\n## Selenium\n\n### Accepting confirm() and alert()\n\n```ruby\naccept_alert { ... }\ndismiss_confirm { ... }\naccept_prompt(with: 'hi') { ... }\n```\n\nAlternatively:\n\n```ruby\npage.driver.browser.switch_to.alert.accept\n```\n\n### Updating session\n\n```ruby\npage.set_rack_session(foo: 'bar')\n```\n\n## See also\n{: .-one-column}\n\n- <https://rubydoc.info/github/jnicklas/capybara/Capybara/RSpecMatchers>\n- <https://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers>"}

field_body:
### Navigating

    visit articles_path

### Clicking links and buttons

```ruby
click_on 'Link Text'
click_button
click_link
```

### Interacting with forms

```ruby
attach_file 'Image', '/path/to/image.jpg'
fill_in 'First Name', with: 'John'
```

```ruby
check 'A checkbox'
uncheck 'A checkbox'
```

```ruby
choose 'A radio button'
```

```ruby
select 'Option', from: 'Select box'
unselect
```

### Limiting

```ruby
within '.classname' do
  click '...'
end
```

```ruby
within_fieldset :id do
  ...
end
```

## Querying

### Predicates

```ruby
page.has_css?('.button')
expect(page).to have_css('.button')
page.should have_css('.button')
```
{: .-setup}

| Positive                          | Negative               |
| ---                               | ---                    |
| `has_content?`                    | `has_no_content?`      |
| ---                               | ---                    |
| `has_css?` _(selector)_           | `has_no_css?`          |
| ---                               | ---                    |
| `has_xpath?` _(path)_             | `has_no_xpath?`        |
| ---                               | ---                    |
| `has_link?` _(selector)_          | `has_no_link?`         |
| ---                               | ---                    |
| `has_button?` _(selector)_        | `has_no_button?`       |
| ---                               | ---                    |
| `has_field?` _(selector)_         | `has_no_field?`        |
| ---                               | ---                    |
| `has_checked_field?` _(selector)_ | `has_unchecked_field?` |
| ---                               | ---                    |
| `has_table?` _(selector)_         | `has_no_table?`        |
| ---                               | ---                    |
| `has_select?` _(selector)_        | `has_no_select?`       |
{: .-headers.-left-align}

In Rspec, these also map to matchers like `page.should have_content`.

### Selectors

```ruby
expect(page).to have_button('Save')
```

```ruby
expect(page).to have_button('#submit')
```

```ruby
expect(page).to have_button('//[@id="submit"]')
```

The `selector` arguments can be text, CSS selector, or XPath expression.

### RSpec assertions

```ruby
page.has_button?('Save')
```

```ruby
expect(page).to have_no_button('Save')
```

In RSpec, you can use `page.should` assertions.

### About negatives

```ruby
expect(page).to have_no_button('Save')
```

```ruby
expect(page).not_to have_button('Save')
```

The two above statements are functionally equivalent.

## RSpec

### Matchers

```ruby
expect(page).to \
```
{: .-setup}

```ruby
  have_current_path(expected_path)
  have_selector '.blank-state'
  have_selector 'h1#hola', text: 'Welcome'
  have_button 'Save'
  have_checked_field '#field'
  have_unchecked_field
  have_css '.class'
  have_field '#field'
  have_table '#table'
  have_xpath '//div'
```

```ruby
  have_link 'Logout', href: logout_path
```

```ruby
  have_select 'Language',
    selected: 'German'
    options: ['Engish', 'German']
    with_options: ['Engish', 'German'] # partial match
```

```ruby
  have_text 'Hello',
    type: :visible # or :all
    # alias: have_content
```

### Common options

All matchers have these options:
{: .-setup}

```ruby
  text: 'welcome'
  text: /Hello/
  visible: true
  count: 4
  between: 2..5
  minimum: 2
  maximum: 5
  wait: 10
```

## Other features

### Finding

```ruby
find(selector)
find_button(selector)
find_by_id(id)
find_field(selector)
find_link(selector)
locate
```

### Scoping

```ruby
within '#delivery' do
  fill_in 'Street', with: 'Hello'
end
```

```ruby
within :xpath, '//article'
within_fieldset
within_table
within_frame
scope_to
```

```ruby
find('#x').fill_in('Street', with: 'Hello')
# same as within
```

### Scripting

```ruby
execute_script('$("input").trigger("change")')
evaluate_script('window.ga')
```

Executes JavaScript.

### Debugging

```ruby
save_and_open_page
```

Opens the webpage in your browser.

### Page

```ruby
page
  .all('h3')
  .body
  .html
  .source
  .current_host
  .current_path
  .current_url
```

### AJAX

```ruby
using_wait_time 10 do
  ...
end
```

### Misc

    drag
    field_labeled

### Page object

```ruby
page.status_code == 200
page.response_headers
```

See: <https://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Session>

### Poltergeist

```ruby
Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, :inspector => true)
end
Capybara.javascript_driver = :poltergeist
```

Use [poltergeist](https://github.com/teampoltergeist/poltergeist) to integrate PhantomJS.

### Blacklist

```ruby
config.before :each, :js do
  page.driver.browser.url_blacklist = [
    'fonts.googleapis.com',
    'use.typekit.net',
    'f.vimeocdn.com',
    'player.vimeo.com',
    'www.googletagmanager.com'
  ].flat_map { |domain| [ "http://#{domain}", "https://#{domain}" ] }
end
```

### Debugging

Enable `inspector: true` and then:
{: .-setup}

```ruby
page.driver.debug
```

To pause execution for a while:

```ruby
page.driver.pause
```

## Selenium

### Accepting confirm() and alert()

```ruby
accept_alert { ... }
dismiss_confirm { ... }
accept_prompt(with: 'hi') { ... }
```

Alternatively:

```ruby
page.driver.browser.switch_to.alert.accept
```

### Updating session

```ruby
page.set_rack_session(foo: 'bar')
```

## See also
{: .-one-column}

- <https://rubydoc.info/github/jnicklas/capybara/Capybara/RSpecMatchers>
- <https://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers>


id: canvas
git_filename: ./canvas.md
format: md
field_title: Canvas
field_category: JavaScript
data:
{"title": "Canvas", "category": "JavaScript", "body": "### Getting the context\n\n```js\nvar canvas = document.getElementById('c')\nvar c = canvas.getContext('2d')\n```\n\n### Basic drawing\n\n```js\n// x = 10, y = 20, width = 200, height = 100\nc.fillStyle = '#ff0000'\nc.strokeStyle = '#ff00ff'\n```\n\n```js\nc.lineWidth = 5\nc.lineCap = 'round'\n```\n\n```js\nc.fillRect(10, 20, 200, 100)\n```\n\n```js\nc.stroke()\nc.fill()\n```\n\n### Saving and restoring\n\n```js\nc.save()\n```\n\n```js\nc.restore()\n```\n\nSaves: `strokeStyle` `fillStyle` `globalAlpha` `lineWidth` `lineCap` `lineJoin` `miterLimit` `shadowOffsetX` `shadowOffsetY` `shadowBlur` `shadowColor`\n`globalCompositeOperation`, Transformations (`translate` `rotate` `scale` `transform` `setTransform`), Clipping path\n\n\n### Animation\n\n```js\nonframe: function() {\n  c.clearRect(0, 0, w, h)\n}\n```\n\n### Transformations\n\n```js\nc.translate(0, 0)\nc.rotate(Math.PI*2/5)\nc.scale(1.0, 1.0)\n```\n\nTo rotate along origin:\n\n```js\nc.translate(ox, oy)\nc.rotate(theta)\nc.translate(-ox, -oy)\n```\n\nTo scale along origin:\n\n```js\nc.translate(-ox*x, -oy*y)\nc.scale(x, y)\nc.translate(ox/x, oy/y)\n```\n\nSee [MDN: Transformations][xform].\n\n### Image drawing\n\n```js\nc.drawImage(image, dx, dy, [dw, dh]);\n/* `image` can be HTML Image/Canvas/Video */\n```\n\nSee [MDN: Images][images].\n\n### Colors, styles shadows\n\n```js\nc.strokeStyle = '#ff00ff';\nc.fillStyle = '#ff00ff';\n```\n\n```js\nc.shadowOffsetX = 0;\nc.shadowOffsetY = 0;\nc.shadowOffsetBlur = 3.0;\nc.shadowColor = 'rgba(0,0,0,0.2)';\n```\n\nSee [MDN: Styles][styles]\n\n### Gradients\n\n```js\ngr = c.createLinearGradient(x0,y0,x1,y1)\ngr = c.createRadialGradient(x0,y0,r0,x1,y1,r1)\npat = c.createPattern(image, 'repeat-x')\n```\n\n```js\nc.fillStyle = gr\n```\n\n### Drawing\n\n```js\nc.beginPath()\nc.moveTo(x,y)\nc.lineTo(x,y)\nc.quadraticCurveTo(cpx,cpy,x,y)\nc.bezierCurveTo(cp1x,cp1y,cp2x,cp2y)\nc.arcTo(...)\nc.arc(...)\nc.closePath()\n```\n\n### More resources\n\n  * [Canvas Cheatsheet PDF][pdf]\n\n[pdf]: http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.pdf\n[xform]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Transformations\n[styles]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Applying_styles_and_colors\n[images]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Using_images"}

field_body:
### Getting the context

```js
var canvas = document.getElementById('c')
var c = canvas.getContext('2d')
```

### Basic drawing

```js
// x = 10, y = 20, width = 200, height = 100
c.fillStyle = '#ff0000'
c.strokeStyle = '#ff00ff'
```

```js
c.lineWidth = 5
c.lineCap = 'round'
```

```js
c.fillRect(10, 20, 200, 100)
```

```js
c.stroke()
c.fill()
```

### Saving and restoring

```js
c.save()
```

```js
c.restore()
```

Saves: `strokeStyle` `fillStyle` `globalAlpha` `lineWidth` `lineCap` `lineJoin` `miterLimit` `shadowOffsetX` `shadowOffsetY` `shadowBlur` `shadowColor`
`globalCompositeOperation`, Transformations (`translate` `rotate` `scale` `transform` `setTransform`), Clipping path


### Animation

```js
onframe: function() {
  c.clearRect(0, 0, w, h)
}
```

### Transformations

```js
c.translate(0, 0)
c.rotate(Math.PI*2/5)
c.scale(1.0, 1.0)
```

To rotate along origin:

```js
c.translate(ox, oy)
c.rotate(theta)
c.translate(-ox, -oy)
```

To scale along origin:

```js
c.translate(-ox*x, -oy*y)
c.scale(x, y)
c.translate(ox/x, oy/y)
```

See [MDN: Transformations][xform].

### Image drawing

```js
c.drawImage(image, dx, dy, [dw, dh]);
/* `image` can be HTML Image/Canvas/Video */
```

See [MDN: Images][images].

### Colors, styles shadows

```js
c.strokeStyle = '#ff00ff';
c.fillStyle = '#ff00ff';
```

```js
c.shadowOffsetX = 0;
c.shadowOffsetY = 0;
c.shadowOffsetBlur = 3.0;
c.shadowColor = 'rgba(0,0,0,0.2)';
```

See [MDN: Styles][styles]

### Gradients

```js
gr = c.createLinearGradient(x0,y0,x1,y1)
gr = c.createRadialGradient(x0,y0,r0,x1,y1,r1)
pat = c.createPattern(image, 'repeat-x')
```

```js
c.fillStyle = gr
```

### Drawing

```js
c.beginPath()
c.moveTo(x,y)
c.lineTo(x,y)
c.quadraticCurveTo(cpx,cpy,x,y)
c.bezierCurveTo(cp1x,cp1y,cp2x,cp2y)
c.arcTo(...)
c.arc(...)
c.closePath()
```

### More resources

  * [Canvas Cheatsheet PDF][pdf]

[pdf]: http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.pdf
[xform]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Transformations
[styles]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Applying_styles_and_colors
[images]: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Using_images


id: camp
git_filename: ./camp.md
format: md
field_title: Camp
field_category: JavaScript libraries
field_updated: 2017-09-21
field_updated___timezone: UTC
data:
{"title": "Camp", "category": "JavaScript libraries", "updated": "2017-09-21", "weight": -1, "intro": "[Camp](https://github.com/espadrine/sc/) is a Node.js web server framework. This guide targets Camp v17.x.\n", "body": "Getting started\n---------------\n{: .-three-column}\n\n### Quick start\n{: .-prime}\n\n#### app.js\n{: .-file}\n\n```js\nconst Camp = require('camp')\nconst camp = Camp.start({ port: 1234 })\n```\n\n#### web/index.html\n{: .-file}\n\n```html\n<!doctype html>\n<body>Hello world!</body>\n```\n\nCamp serves files in `web/` by default.\n\n### Routes\n\n#### Handles `/search?q=rainbows`\n\n```js\ncamp.path('/search', (req, res) => {\n  const q = res.query.q\n  res.json({ results: \u00b7\u00b7\u00b7 })\n})\n```\n{: data-line=\"2\"}\n\nAlso available: `camp.post`, `camp.get`.\n\n### Templates\n\n```js\nconst tpl = Camp.template('./templates/post.html')\n\ncamp.path('/blog/:post.html', (req, res) => {\n  res.template({\n    text: 'Hello world'\n  }, tpl)\n})\n```\n{: data-line=\"1,4\"}\n\nSee: [Templates](https://github.com/espadrine/sc/blob/master/doc/Readme.md#templates)\n\n### Not found\n\n```js\ncamp.notFound('/*.lol', (req, res) => {\n  res.file('/404.html')\n})\n```\n{: data-line=\"1\"}\n\nSee: [Fall through](https://github.com/espadrine/sc/blob/master/doc/Readme.md#fall-through)\n\n### Low level handler\n\n```js\ncamp.handle((req, res, next) => {\n  res.setHeader('X-Hello', 'world')\n  next()\n})\n```\n{: data-line=\"1\"}\n\nSee: [Handlers](https://github.com/espadrine/sc/blob/master/doc/Readme.md#handlers)\n\nTemplates\n---------\n\n### Basic templates\n\n```js\nconst tpl = Camp.template('/templates/post.html')\n\ncamp.path('/blog/:post.html', (req, res) => {\n  res.template({\n    text: 'Hello world'\n  }, tpl)\n})\n```\n{: data-line=\"1,4,5,6\"}\n\n### Implicit templates\n\n```js\ncamp.path('blog.html')\n```\n\nUses `blog.html` as a template.\n\nSee: [Templates](https://github.com/espadrine/sc/blob/master/doc/Readme.md#templates)\n\nAdvanced features\n-----------------\n\n### Web sockets\n\n```js\ncamp.ws('/path', (socket) => { \u00b7\u00b7\u00b7 })\n```\n\n```js\ncamp.wsChannels[path]\n```\n\n```js\ncamp.wsBroadcast('/path', (req, res) => {\n})\n```\n\nSorry I don't completely understand this yet, but check it out in their docs.\n\nSee: [WebSocket](https://github.com/espadrine/sc/blob/master/doc/Readme.md#websocket)"}

field_intro:
[Camp](https://github.com/espadrine/sc/) is a Node.js web server framework. This guide targets Camp v17.x.

field_body:
Getting started
---------------
{: .-three-column}

### Quick start
{: .-prime}

#### app.js
{: .-file}

```js
const Camp = require('camp')
const camp = Camp.start({ port: 1234 })
```

#### web/index.html
{: .-file}

```html
<!doctype html>
<body>Hello world!</body>
```

Camp serves files in `web/` by default.

### Routes

#### Handles `/search?q=rainbows`

```js
camp.path('/search', (req, res) => {
  const q = res.query.q
  res.json({ results: ··· })
})
```
{: data-line="2"}

Also available: `camp.post`, `camp.get`.

### Templates

```js
const tpl = Camp.template('./templates/post.html')

camp.path('/blog/:post.html', (req, res) => {
  res.template({
    text: 'Hello world'
  }, tpl)
})
```
{: data-line="1,4"}

See: [Templates](https://github.com/espadrine/sc/blob/master/doc/Readme.md#templates)

### Not found

```js
camp.notFound('/*.lol', (req, res) => {
  res.file('/404.html')
})
```
{: data-line="1"}

See: [Fall through](https://github.com/espadrine/sc/blob/master/doc/Readme.md#fall-through)

### Low level handler

```js
camp.handle((req, res, next) => {
  res.setHeader('X-Hello', 'world')
  next()
})
```
{: data-line="1"}

See: [Handlers](https://github.com/espadrine/sc/blob/master/doc/Readme.md#handlers)

Templates
---------

### Basic templates

```js
const tpl = Camp.template('/templates/post.html')

camp.path('/blog/:post.html', (req, res) => {
  res.template({
    text: 'Hello world'
  }, tpl)
})
```
{: data-line="1,4,5,6"}

### Implicit templates

```js
camp.path('blog.html')
```

Uses `blog.html` as a template.

See: [Templates](https://github.com/espadrine/sc/blob/master/doc/Readme.md#templates)

Advanced features
-----------------

### Web sockets

```js
camp.ws('/path', (socket) => { ··· })
```

```js
camp.wsChannels[path]
```

```js
camp.wsBroadcast('/path', (req, res) => {
})
```

Sorry I don't completely understand this yet, but check it out in their docs.

See: [WebSocket](https://github.com/espadrine/sc/blob/master/doc/Readme.md#websocket)


id: c_preprocessor
git_filename: ./c_preprocessor.md
format: md
field_title: C Preprocessor
field_category: C-like
data:
{"title": "C Preprocessor", "category": "C-like", "intro": "Quick reference for the [C macro preprocessor](https://en.m.wikipedia.org/wiki/C_preprocessor), which can be used independent of C/C++.\n", "body": "## Reference\n{: .-three-column}\n\n### Compiling\n\n```\n$ cpp -P file > outfile\n```\n\n### Includes\n\n```\n#include \"file\"\n```\n\n### Defines\n\n```\n#define FOO\n#define FOO \"hello\"\n\n#undef FOO\n```\n\n### If\n\n```\n#ifdef DEBUG\n  console.log('hi');\n#elif defined VERBOSE\n  ...\n#else\n  ...\n#endif\n```\n\n### Error\n\n```\n#if VERSION == 2.0\n  #error Unsupported\n  #warning Not really supported\n#endif\n```\n\n### Macro\n\n```\n#define DEG(x) ((x) * 57.29)\n```\n\n### Token concat\n\n```\n#define DST(name) name##_s name##_t\nDST(object);   #=> object_s object_t;\n```\n\n### Stringification\n\n```\n#define STR(name) #name\nchar * a = STR(object);   #=> char * a = \"object\";\n```\n\n### file and line\n\n```\n#define LOG(msg) console.log(__FILE__, __LINE__, msg)\n#=> console.log(\"file.txt\", 3, \"hey\")\n```"}

field_intro:
Quick reference for the [C macro preprocessor](https://en.m.wikipedia.org/wiki/C_preprocessor), which can be used independent of C/C++.

field_body:
## Reference
{: .-three-column}

### Compiling

```
$ cpp -P file > outfile
```

### Includes

```
#include "file"
```

### Defines

```
#define FOO
#define FOO "hello"

#undef FOO
```

### If

```
#ifdef DEBUG
  console.log('hi');
#elif defined VERBOSE
  ...
#else
  ...
#endif
```

### Error

```
#if VERSION == 2.0
  #error Unsupported
  #warning Not really supported
#endif
```

### Macro

```
#define DEG(x) ((x) * 57.29)
```

### Token concat

```
#define DST(name) name##_s name##_t
DST(object);   #=> object_s object_t;
```

### Stringification

```
#define STR(name) #name
char * a = STR(object);   #=> char * a = "object";
```

### file and line

```
#define LOG(msg) console.log(__FILE__, __LINE__, msg)
#=> console.log("file.txt", 3, "hey")
```


id: bundler
git_filename: ./bundler.md
format: md
field_title: Bundler
field_category: Ruby
data:
{"title": "Bundler", "category": "Ruby", "body": "### Commands\n\n    bundle                  # same as bundle install\n    bundle install          # installs gems\n    bundle install -j3      # faster (3 jobs)\n    bundle update           # update all gems\n    bundle update --source gemname  # update specified gem\n\n    bundle outdated         # show outdated gems\n    cd `bundle show rails`  # inspect a gem's dir\n\n    bundle gem              # new gem skeleton\n\n### Gems\n\n    gem 'hello'\n    gem 'hello', group: 'development'\n\n### Github support\n\n    gem 'hello', github: 'rstacruz/hello'\n    gem 'hello', github: 'rstacruz/hello', 'branch: master'\n\n### Grouping\n\n    group :development do\n      gem 'hello'\n    end\n\n### Deployment\n\n    $ bundle install --without=test,development --deployment\n\n### Local gem development\n\nIn your Gemfile, define a Git source and a branch:\n\n    gem 'hello', github: 'rstacruz/hello', branch: 'master'\n\nAnd then:\n\n    $ bundle config --global local.xxx ~/projects/xxx\n\n### Rake Gem tasks\n\n    # Rakefile\n    require 'bundler/gem_tasks'\n\nTerminal:\n\n    $ rake release\n    $ rake build"}

field_body:
### Commands

    bundle                  # same as bundle install
    bundle install          # installs gems
    bundle install -j3      # faster (3 jobs)
    bundle update           # update all gems
    bundle update --source gemname  # update specified gem

    bundle outdated         # show outdated gems
    cd `bundle show rails`  # inspect a gem's dir

    bundle gem              # new gem skeleton

### Gems

    gem 'hello'
    gem 'hello', group: 'development'

### Github support

    gem 'hello', github: 'rstacruz/hello'
    gem 'hello', github: 'rstacruz/hello', 'branch: master'

### Grouping

    group :development do
      gem 'hello'
    end

### Deployment

    $ bundle install --without=test,development --deployment

### Local gem development

In your Gemfile, define a Git source and a branch:

    gem 'hello', github: 'rstacruz/hello', branch: 'master'

And then:

    $ bundle config --global local.xxx ~/projects/xxx

### Rake Gem tasks

    # Rakefile
    require 'bundler/gem_tasks'

Terminal:

    $ rake release
    $ rake build


id: bulma
git_filename: ./bulma.md
format: md
field_title: Bulma
field_category: CSS
field_prism_languages: css, html
field_updated: 2018-11-19
field_updated___timezone: UTC
data:
{"title": "Bulma", "category": "CSS", "prism_languages": ["css", "html"], "weight": -1, "updated": "2018-11-19", "authors": [{"github": "benolot"}], "description": "Basic guide on how to use Bulma, the lightweight css flexbox framework.\n", "body": "### Screen sizes\n\n```\n         768         1024                1216         1408\n'     '     '     '     '     '     '     '     '     '     '     '\n<---------^------------^------------------^-------------^------------->\n  mobile      tablet         desktop         widescreen      fullhd\n```\n\n### Columns\n\n```css\n.container\n```\nWrap as many `.column`'s' as you like in a `.columns` wrapper\n```html\n<div class=\"columns\">\n    <div class=\"column\"></div>\n    <div class=\"column\"></div>\n    <div class=\"column\"></div>\n    <div class=\"column\"></div>\n    <div class=\"column\"></div>\n</div>\n```\n\n### Modifiers\n\nThe following CSS classes affect the **colour**.\n\n```css\n.is-primary\n.is-link\n.is-info\n.is-success\n.is-warning\n.is-danger\n```\n\nThe following classes modify the **size**.\n```css\n.is-small\n.is-medium\n.is-large\n```\n\nThe following classes modify the **state**.\n```scss\n.is-outlined\n.is-loading\n```\n\n### Typography Helpers\n\nThe following classes modify the **font-size**\n\n| Class         | Font-size             |\n| ---           | ---                   |\n| `.is-size-1`  | 3rem                  |\n| `.is-size-2`  | 2.5rem                |\n| `.is-size-3`  | 2rem                  |\n| `.is-size-4`  | 1.5rem                |\n| `.is-size-5`  | 1.25rem               |\n| `.is-size-6`  | 1rem                  |\n| `.is-size-7`  | 0.75rem               |\n\nThe following classes **align** the text\n\n| Class                 | Alignment                             |\n| ---                   | ---                                   |\n| `.has-text-centered`  | Makes the text **centered**           |\n| `.has-text-justified` | Makes the text **justified**          |\n| `.has-text-left`.     | Makes the text align to the **left**  |\n| `.has-text-right`     | Makes the text align to the **right** |\n\nThe following classes **transform** the text\n\n| Class              | Transformation        |\n| ---                | ---                   |\n| `.is-capitalized`  | Transforms the **first character** of each word to **uppercase**   |\n| `.is-lowercase`    | Transforms **all** characters to **lowercase**                     |\n| `.is-uppercase`    | Transforms **all** characters to **uppercase**                     |\n\n### WYSIWYG Content\n\n```html\n<div class=\"content\">\n  <!-- start WYSIWYG contents -->\n  <h1>Heading</h1>\n  <p>Paragraph</p>\n\n  <ul>\n    <li>Item 1</li>\n    <li>Item 2</li>\n  </ul>\n  <!-- end WYSIWYG contents -->\n</div>\n```\n\nTo provide default stylings for commonly generated WYSIWYG contents, use the `.content` class."}

field_body:
### Screen sizes

```
         768         1024                1216         1408
'     '     '     '     '     '     '     '     '     '     '     '
<---------^------------^------------------^-------------^------------->
  mobile      tablet         desktop         widescreen      fullhd
```

### Columns

```css
.container
```
Wrap as many `.column`'s' as you like in a `.columns` wrapper
```html
<div class="columns">
    <div class="column"></div>
    <div class="column"></div>
    <div class="column"></div>
    <div class="column"></div>
    <div class="column"></div>
</div>
```

### Modifiers

The following CSS classes affect the **colour**.

```css
.is-primary
.is-link
.is-info
.is-success
.is-warning
.is-danger
```

The following classes modify the **size**.
```css
.is-small
.is-medium
.is-large
```

The following classes modify the **state**.
```scss
.is-outlined
.is-loading
```

### Typography Helpers

The following classes modify the **font-size**

| Class         | Font-size             |
| ---           | ---                   |
| `.is-size-1`  | 3rem                  |
| `.is-size-2`  | 2.5rem                |
| `.is-size-3`  | 2rem                  |
| `.is-size-4`  | 1.5rem                |
| `.is-size-5`  | 1.25rem               |
| `.is-size-6`  | 1rem                  |
| `.is-size-7`  | 0.75rem               |

The following classes **align** the text

| Class                 | Alignment                             |
| ---                   | ---                                   |
| `.has-text-centered`  | Makes the text **centered**           |
| `.has-text-justified` | Makes the text **justified**          |
| `.has-text-left`.     | Makes the text align to the **left**  |
| `.has-text-right`     | Makes the text align to the **right** |

The following classes **transform** the text

| Class              | Transformation        |
| ---                | ---                   |
| `.is-capitalized`  | Transforms the **first character** of each word to **uppercase**   |
| `.is-lowercase`    | Transforms **all** characters to **lowercase**                     |
| `.is-uppercase`    | Transforms **all** characters to **uppercase**                     |

### WYSIWYG Content

```html
<div class="content">
  <!-- start WYSIWYG contents -->
  <h1>Heading</h1>
  <p>Paragraph</p>

  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
  </ul>
  <!-- end WYSIWYG contents -->
</div>
```

To provide default stylings for commonly generated WYSIWYG contents, use the `.content` class.


id: browserify
git_filename: ./browserify.md
format: md
field_title: Browserify
field_category: JavaScript libraries
field_tags: Archived
data:
{"title": "Browserify", "category": "JavaScript libraries", "tags": ["Archived"], "archived": "Browserify has not been in active development.", "body": "### About\n{: .-intro}\n\nBrowserify is a bundler for JavaScript.\n\n- <https://browserify.org/>\n\n### Usage\n\n    browserify input.js\n      -o output.js\n      -t coffeeify\n      -t [ coffeeify --extension coffee ]\n\n      -u react (--exclude: omit a file)\n      -x react (--external: reference in another bundle)\n      -i react (--ignore: stub a file)\n      -s Myapp (--standalone: generate a UMD bundle)\n      --debug\n\n### Programmatic usage\n\n    browserify = require('browserify')\n    browserify()\n      .add('main.js')\n      .bundle()\n      .transform(coffeeify)\n      .transform({extensions: '.coffee'}, coffeeify)\n      .pipe(process.stdout)\n\n    browserify({})\n\n### Tools\n\n  * watchify (recompiles on demand)\n  * beefy (http server)\n  * debowerify\n  * es6ify (es6 to es5)\n\nTransforms\n\n  * coffeeify\n  * ractify\n  * reactify\n  * brfs\n  * cssify\n  * https://github.com/substack/node-browserify/wiki/list-of-transforms"}

field_body:
### About
{: .-intro}

Browserify is a bundler for JavaScript.

- <https://browserify.org/>

### Usage

    browserify input.js
      -o output.js
      -t coffeeify
      -t [ coffeeify --extension coffee ]

      -u react (--exclude: omit a file)
      -x react (--external: reference in another bundle)
      -i react (--ignore: stub a file)
      -s Myapp (--standalone: generate a UMD bundle)
      --debug

### Programmatic usage

    browserify = require('browserify')
    browserify()
      .add('main.js')
      .bundle()
      .transform(coffeeify)
      .transform({extensions: '.coffee'}, coffeeify)
      .pipe(process.stdout)

    browserify({})

### Tools

  * watchify (recompiles on demand)
  * beefy (http server)
  * debowerify
  * es6ify (es6 to es5)

Transforms

  * coffeeify
  * ractify
  * reactify
  * brfs
  * cssify
  * https://github.com/substack/node-browserify/wiki/list-of-transforms


id: browser-sync
git_filename: ./browser-sync.md
format: md
field_title: Browsersync
field_category: JavaScript libraries
data:
{"title": "Browsersync", "category": "JavaScript libraries", "body": "### About\n{: .-intro}\n\n`npm i -g browser-sync`\n\n* [browsersync.io](https://browsersync.io)\n\n### Start a server\n\n```sh\nbrowser-sync start --server <path> --files='**/*.html, **/*.css'\n```\n\n### Options\n\n```sh\n  --port=N\n  --proxy=\"http://127.0.0.1:3000\"\n```"}

field_body:
### About
{: .-intro}

`npm i -g browser-sync`

* [browsersync.io](https://browsersync.io)

### Start a server

```sh
browser-sync start --server <path> --files='**/*.html, **/*.css'
```

### Options

```sh
  --port=N
  --proxy="http://127.0.0.1:3000"
```


id: bootstrap
git_filename: ./bootstrap.md
format: md
field_title: Bootstrap
field_category: CSS
field_prism_languages: scss, haml, html
data:
{"title": "Bootstrap", "prism_languages": ["scss", "haml", "html"], "weight": -1, "category": "CSS", "description": ".container .row .col-md-6, @screen-sm-min, .form-control, grids, .modal-content, tooltips, and other Bootstrap CSS examples.\n", "body": "### Screen sizes\n\n```\n         768          992                1200\n'     '     '     '     '     '     '     '     '\n<---------^------------^------------------^--------->\n     xs         sm              md             lg\n   (phone)   (tablet)        (laptop)       (desktop)\n```\n\nMin:\n\n```scss\n@media (min-width: @screen-sm-min) // >= 768px (small tablet)\n@media (min-width: @screen-md-min) // >= 992px (medium laptop)\n@media (min-width: @screen-lg-min) // >= 1200px (large desktop)\n```\n\nMax:\n\n```scss\n@media (max-width: @screen-xs-max) { // < 768px (xsmall phone)\n@media (max-width: @screen-sm-max) { // < 992px (small tablet)\n@media (max-width: @screen-md-max) { // < 1200px (medium laptop)\n```\n\n### Columns\n\n```scss\n.container\n.container-fluid\n```\n\n```scss\n.col-xs-1\n.col-sm-1\n.col-md-1\n.col-lg-1\n.col-md-offset-1\n```\n\nMixins:\n\n```scss\n@include make-xs-column(12);\n@include make-sm-column(6);\n@include make-md-column(3);\n@include make-lg-column(3);\n```\n\n```scss\n@include make-sm-column-offset(1);\n@include make-sm-column-push(1);\n@include make-sm-column-pull(1);\n```\n\n### Utilities\n\n```scss\n.pull-left\n.pull-right\n```\n\n```scss\n.hidden-{xs,sm,md,lg}\n.visible-{xs,sm,md,lg}\n.visible-{xs,sm,md,lg,print}-{block,inline,inline-block}\n```\n\n```scss\n.center-block  /* margin: auto */\n.clearfix\n.text-{center,left,right,justify,nowrap}\n.text-{lowercase,uppercase,capitalize}\n```\n\n```scss\n.show\n.hidden\n```\n\n### Modal\n\n```html\n<a data-toggle='modal' data-target='#new'>\n```\n\n```haml\n#new.modal.fade(role='dialog')\n  .modal-dialog // .modal-lg, .modal-sm\n    .modal-content\n      .modal-header\n        %h4.modal-title hello\n        %button.close{type: 'button', data: { dismiss: 'modal' }}\n          %span{'aria-hidden' => true}!= \"&times;\"\n          %span.sr-only Close\n      .modal-body\n        ...\n      .modal-footer\n        ...\n```\n\n### Modal via ajax (Rails)\n\n```haml\n%button.btn{data: { |\n  toggle: 'modal', |\n  target: '#chooseTheme', |\n  remote: '/path/to/remote'}\n  Change Theme\n```\n\n```haml\n.modal.fade#chooseTheme\n  .modal-dialog.modal-xl\n    .modal-content\n      .modal-header\n        %h4.modal-title Choose a theme\n\n      .modal-body\n        .spinner-panel.-lg\n          %i\n```\n\n### Tooltip\n\n```html\n<span\n  data-toggle='tooltip'\n  title='tooltip'\n  data-placement='left|top|bottom|right'>\n```\n\n```js\n$(function () {\n  $('[data-toogle~=\"tooltip\"]').tooltip()\n})\n```\n\n### Input groups\n\n```haml\n.input-group\n    input.form-control(type='text')\n    .input-group-addon years\n```"}

field_body:
### Screen sizes

```
         768          992                1200
'     '     '     '     '     '     '     '     '
<---------^------------^------------------^--------->
     xs         sm              md             lg
   (phone)   (tablet)        (laptop)       (desktop)
```

Min:

```scss
@media (min-width: @screen-sm-min) // >= 768px (small tablet)
@media (min-width: @screen-md-min) // >= 992px (medium laptop)
@media (min-width: @screen-lg-min) // >= 1200px (large desktop)
```

Max:

```scss
@media (max-width: @screen-xs-max) { // < 768px (xsmall phone)
@media (max-width: @screen-sm-max) { // < 992px (small tablet)
@media (max-width: @screen-md-max) { // < 1200px (medium laptop)
```

### Columns

```scss
.container
.container-fluid
```

```scss
.col-xs-1
.col-sm-1
.col-md-1
.col-lg-1
.col-md-offset-1
```

Mixins:

```scss
@include make-xs-column(12);
@include make-sm-column(6);
@include make-md-column(3);
@include make-lg-column(3);
```

```scss
@include make-sm-column-offset(1);
@include make-sm-column-push(1);
@include make-sm-column-pull(1);
```

### Utilities

```scss
.pull-left
.pull-right
```

```scss
.hidden-{xs,sm,md,lg}
.visible-{xs,sm,md,lg}
.visible-{xs,sm,md,lg,print}-{block,inline,inline-block}
```

```scss
.center-block  /* margin: auto */
.clearfix
.text-{center,left,right,justify,nowrap}
.text-{lowercase,uppercase,capitalize}
```

```scss
.show
.hidden
```

### Modal

```html
<a data-toggle='modal' data-target='#new'>
```

```haml
#new.modal.fade(role='dialog')
  .modal-dialog // .modal-lg, .modal-sm
    .modal-content
      .modal-header
        %h4.modal-title hello
        %button.close{type: 'button', data: { dismiss: 'modal' }}
          %span{'aria-hidden' => true}!= "&times;"
          %span.sr-only Close
      .modal-body
        ...
      .modal-footer
        ...
```

### Modal via ajax (Rails)

```haml
%button.btn{data: { |
  toggle: 'modal', |
  target: '#chooseTheme', |
  remote: '/path/to/remote'}
  Change Theme
```

```haml
.modal.fade#chooseTheme
  .modal-dialog.modal-xl
    .modal-content
      .modal-header
        %h4.modal-title Choose a theme

      .modal-body
        .spinner-panel.-lg
          %i
```

### Tooltip

```html
<span
  data-toggle='tooltip'
  title='tooltip'
  data-placement='left|top|bottom|right'>
```

```js
$(function () {
  $('[data-toogle~="tooltip"]').tooltip()
})
```

### Input groups

```haml
.input-group
    input.form-control(type='text')
    .input-group-addon years
```


id: bookshelf
git_filename: ./bookshelf.md
format: md
field_title: Bookshelf.js
field_category: JavaScript libraries
data:
{"title": "Bookshelf.js", "category": "JavaScript libraries", "body": "Model\n-----\n\n### Model\n```js\nSummary = bookshelf.Model.extend({\n  tableName: 'summaries',\n  hasTimestamps: true,\n  hasTimestamps: ['created_at', 'updated_at'],\n})\n```\n\n### Associations\n\n```js\nSummary = bookshelf.Model.extend({\n  book () {\n    return this.belongsTo(Book)\n  },\n  author () {\n    return this.hasOne(Author)\n  }\n  // belongsToMany\n  // hasMany\n  // hasMany().through()\n})\n```\n\n### CRUD\n\n```js\nBook.create({ title: '..' }).save()\nnew Book({ title: '..' }).save()\n\nnew Book({ id: 1 }).fetch()\n\nBook.where({ id: 1 }).fetch()\nBook.where('favorite_color', 'red').fetch()\nBook.where('favorite_color', '<>', 'red').fetch()\nBook\n  .query((q) => q.orderBy('updated_at')\n```"}

field_body:
Model
-----

### Model
```js
Summary = bookshelf.Model.extend({
  tableName: 'summaries',
  hasTimestamps: true,
  hasTimestamps: ['created_at', 'updated_at'],
})
```

### Associations

```js
Summary = bookshelf.Model.extend({
  book () {
    return this.belongsTo(Book)
  },
  author () {
    return this.hasOne(Author)
  }
  // belongsToMany
  // hasMany
  // hasMany().through()
})
```

### CRUD

```js
Book.create({ title: '..' }).save()
new Book({ title: '..' }).save()

new Book({ id: 1 }).fetch()

Book.where({ id: 1 }).fetch()
Book.where('favorite_color', 'red').fetch()
Book.where('favorite_color', '<>', 'red').fetch()
Book
  .query((q) => q.orderBy('updated_at')
```


id: bolt
git_filename: ./bolt.md
format: md
field_title: Bolt Quickstart
field_category: Bolt
field_updated: 2018-12-25
field_updated___timezone: UTC
data:
{"title": "Bolt Quickstart", "category": "Bolt", "updated": "2018-12-25", "authors": [{"github": "lucywyman"}], "keywords": ["Puppet", "tasks", "modules"], "description": "A quick guide to getting started writing Bolt tasks\n", "body": "### Install Bolt\n\n```bash\n# On MacOS\nbrew cask install puppetlabs/puppet/puppet-bolt\n# On Windows\nchoco install puppet-bolt\n```\n\nBolt is available as a package for most platforms. See [installing bolt](https://puppet.com/docs/bolt/latest/bolt_installing.html)\n\n### Create a module with a task\n\n```bash\nmkdir -p ~/.puppetlabs/bolt/modules/mymodule/tasks\ncp myscript.sh ~/.puppetlabs/bolt/modules/mymodule/tasks/\n```\n\nTasks can be written in any language your targets can run. See [writing tasks](https://puppet.com/docs/bolt/latest/writing_tasks.html) for more details.\n\n### Run Bolt\n\n```bash\nbolt task run mymodule::myscript -n node1.example.com,node2.example.com --private-key ~/.ssh/id_rsa-private\n```\n\nSee `bolt task run --help` for more information and command line options."}

field_body:
### Install Bolt

```bash
# On MacOS
brew cask install puppetlabs/puppet/puppet-bolt
# On Windows
choco install puppet-bolt
```

Bolt is available as a package for most platforms. See [installing bolt](https://puppet.com/docs/bolt/latest/bolt_installing.html)

### Create a module with a task

```bash
mkdir -p ~/.puppetlabs/bolt/modules/mymodule/tasks
cp myscript.sh ~/.puppetlabs/bolt/modules/mymodule/tasks/
```

Tasks can be written in any language your targets can run. See [writing tasks](https://puppet.com/docs/bolt/latest/writing_tasks.html) for more details.

### Run Bolt

```bash
bolt task run mymodule::myscript -n node1.example.com,node2.example.com --private-key ~/.ssh/id_rsa-private
```

See `bolt task run --help` for more information and command line options.


id: bluebird
git_filename: ./bluebird.md
format: md
field_title: bluebird.js
field_category: JavaScript libraries
field_updated: 2017-09-08
field_updated___timezone: UTC
data:
{"title": "bluebird.js", "category": "JavaScript libraries", "weight": -1, "updated": "2017-09-08", "body": "### Also see\n\nAlso see the [promise cheatsheet](promise.html) and [Bluebird.js API](https://github.com/petkaantonov/bluebird/blob/master/API.md) (github.com).\n\n### Example\n\n```js\npromise\n  .then(okFn, errFn)\n  .spread(okFn, errFn)        // *\n  .catch(errFn)\n  .catch(TypeError, errFn)    // *\n  .finally(fn)\n  .map(function (e) { \u00b7\u00b7\u00b7 })  // *\n  .each(function (e) { \u00b7\u00b7\u00b7 }) // *\n```\n\nThose marked with `*` are non-standard Promise API that only work with Bluebird promises.\n\n### Multiple return values\n\n```js\n.then(function () {\n  return [ 'abc', 'def' ]\n})\n.spread(function (abc, def) {\n  \u00b7\u00b7\u00b7\n})\n```\n{: data-line=\"4\"}\n\nUse [Promise.spread](http://bluebirdjs.com/docs/api/promise.spread.html)\n\n### Multiple promises\n\n```js\nPromise.join(\n  getPictures(),\n  getMessages(),\n  getTweets(),\n  function (pics, msgs, tweets) {\n    return \u00b7\u00b7\u00b7\n  }\n)\n```\n{: data-line=\"1\"}\n\nUse [Promise.join](http://bluebirdjs.com/docs/api/promise.join.html)\n\n### Multiple promises (array)\n\n- [Promise.all](http://bluebirdjs.com/docs/api/promise.all.html)([p]) - expect all to pass\n- [Promise.some](http://bluebirdjs.com/docs/api/promise.some.html)([p], count) - expect `count` to pass\n- [Promise.any](http://bluebirdjs.com/docs/api/promise.any.html)([p]) - same as `some([p], 1)`\n- [Promise.race](http://bluebirdjs.com/docs/api/promise.race.html)([p], count) - use `.any` instead\n- [Promise.map](http://bluebirdjs.com/docs/api/promise.map.html)([p], fn, options) - supports concurrency\n\n```js\nPromise.all([ promise1, promise2 ])\n  .then(results => {\n    results[0]\n    results[1]\n  })\n\n// succeeds if one succeeds first\nPromise.any(promises)\n  .then(results => {\n  })\n```\n{: data-line=\"1,8\"}\n\n```js\nPromise.map(urls, url => fetch(url))\n  .then(\u00b7\u00b7\u00b7)\n```\n{: data-line=\"1\"}\n\nUse [Promise.map](http://bluebirdjs.com/docs/api/promise.map.html) to \"promisify\" a list of values.\n\n### Object\n\n```js\nPromise.props({\n  photos: get('photos'),\n  posts: get('posts')\n})\n.then(res => {\n  res.photos\n  res.posts\n})\n```\n{: data-line=\"1\"}\n\nUse [Promise.props](http://bluebirdjs.com/docs/api/promise.props.html).\n\n### Chain of promises\n\n```js\nfunction getPhotos() {\n  return Promise.try(() => {\n    if (err) throw new Error(\"boo\")\n    return result\n  })\n}\n\ngetPhotos().then(\u00b7\u00b7\u00b7)\n```\n{: data-line=\"2\"}\n\nUse [Promise.try](http://bluebirdjs.com/docs/api/promise.try.html).\n\n### Node-style functions\n\n```js\nvar readFile = Promise.promisify(fs.readFile)\nvar fs = Promise.promisifyAll(require('fs'))\n```\n{: data-line=\"2\"}\n\nSee [Promisification](http://bluebirdjs.com/docs/api/promisification.html).\n\n### Promise-returning methods\n\n```js\nUser.login = Promise.method((email, password) => {\n  if (!valid)\n    throw new Error(\"Email not valid\")\n\n  return /* promise */\n})\n```\n{: data-line=\"1\"}\n\nSee [Promise.method](http://bluebirdjs.com/docs/api/promise.method.html).\n\n### Generators\n\n```js\nUser.login = Promise.coroutine(function* (email, password) {\n  let user = yield User.find({email: email}).fetch()\n  return user\n})\n```\n{: data-line=\"1\"}\n\nSee [Promise.coroutine](http://bluebirdjs.com/docs/api/promise.coroutine.html).\n\n## Reference\n\n<http://bluebirdjs.com/docs/api-reference.html>"}

field_body:
### Also see

Also see the [promise cheatsheet](promise.html) and [Bluebird.js API](https://github.com/petkaantonov/bluebird/blob/master/API.md) (github.com).

### Example

```js
promise
  .then(okFn, errFn)
  .spread(okFn, errFn)        // *
  .catch(errFn)
  .catch(TypeError, errFn)    // *
  .finally(fn)
  .map(function (e) { ··· })  // *
  .each(function (e) { ··· }) // *
```

Those marked with `*` are non-standard Promise API that only work with Bluebird promises.

### Multiple return values

```js
.then(function () {
  return [ 'abc', 'def' ]
})
.spread(function (abc, def) {
  ···
})
```
{: data-line="4"}

Use [Promise.spread](http://bluebirdjs.com/docs/api/promise.spread.html)

### Multiple promises

```js
Promise.join(
  getPictures(),
  getMessages(),
  getTweets(),
  function (pics, msgs, tweets) {
    return ···
  }
)
```
{: data-line="1"}

Use [Promise.join](http://bluebirdjs.com/docs/api/promise.join.html)

### Multiple promises (array)

- [Promise.all](http://bluebirdjs.com/docs/api/promise.all.html)([p]) - expect all to pass
- [Promise.some](http://bluebirdjs.com/docs/api/promise.some.html)([p], count) - expect `count` to pass
- [Promise.any](http://bluebirdjs.com/docs/api/promise.any.html)([p]) - same as `some([p], 1)`
- [Promise.race](http://bluebirdjs.com/docs/api/promise.race.html)([p], count) - use `.any` instead
- [Promise.map](http://bluebirdjs.com/docs/api/promise.map.html)([p], fn, options) - supports concurrency

```js
Promise.all([ promise1, promise2 ])
  .then(results => {
    results[0]
    results[1]
  })

// succeeds if one succeeds first
Promise.any(promises)
  .then(results => {
  })
```
{: data-line="1,8"}

```js
Promise.map(urls, url => fetch(url))
  .then(···)
```
{: data-line="1"}

Use [Promise.map](http://bluebirdjs.com/docs/api/promise.map.html) to "promisify" a list of values.

### Object

```js
Promise.props({
  photos: get('photos'),
  posts: get('posts')
})
.then(res => {
  res.photos
  res.posts
})
```
{: data-line="1"}

Use [Promise.props](http://bluebirdjs.com/docs/api/promise.props.html).

### Chain of promises

```js
function getPhotos() {
  return Promise.try(() => {
    if (err) throw new Error("boo")
    return result
  })
}

getPhotos().then(···)
```
{: data-line="2"}

Use [Promise.try](http://bluebirdjs.com/docs/api/promise.try.html).

### Node-style functions

```js
var readFile = Promise.promisify(fs.readFile)
var fs = Promise.promisifyAll(require('fs'))
```
{: data-line="2"}

See [Promisification](http://bluebirdjs.com/docs/api/promisification.html).

### Promise-returning methods

```js
User.login = Promise.method((email, password) => {
  if (!valid)
    throw new Error("Email not valid")

  return /* promise */
})
```
{: data-line="1"}

See [Promise.method](http://bluebirdjs.com/docs/api/promise.method.html).

### Generators

```js
User.login = Promise.coroutine(function* (email, password) {
  let user = yield User.find({email: email}).fetch()
  return user
})
```
{: data-line="1"}

See [Promise.coroutine](http://bluebirdjs.com/docs/api/promise.coroutine.html).

## Reference

<http://bluebirdjs.com/docs/api-reference.html>


id: blessed
git_filename: ./blessed.md
format: md
field_title: Blessed
field_category: JavaScript libraries
data:
{"title": "Blessed", "category": "JavaScript libraries", "body": "### Screen\n\n```js\nscreen = blessed.screen({\n  smartCSR: true       // optimize for flickering\n  autoPadding: true    // ..\n})\n\nscreen.append(Element)\nscreen.destroy()\n\nscreen.width\nscreen.height\nscreen.title = 'My window title'\nscreen.key(['escape', 'q', 'C-c'], (ch, key) => { ... })\n```\n\n### Element\n\n```js\nbox = blessed.box({\n  style: { fg, bg, border.fg, scrollbar.bg, focus.bg, hover.bg },\n  border: { type: 'line'|'bg', bg, fg, bold, underline }\n  tags: true,  // parse {bold}tags{/bold}\n\n  top, left, width, height,\n  width: '100%',\n  height: '100%-1',\n  top: 'center'\n})\n```\n\n### Tags\n\n```\n{bold}\n{right} {center}\n{|}    left-right separator\n{#c0ff33-fg}{/}\n```\n\n```\nblessed.escape('...')\n```"}

field_body:
### Screen

```js
screen = blessed.screen({
  smartCSR: true       // optimize for flickering
  autoPadding: true    // ..
})

screen.append(Element)
screen.destroy()

screen.width
screen.height
screen.title = 'My window title'
screen.key(['escape', 'q', 'C-c'], (ch, key) => { ... })
```

### Element

```js
box = blessed.box({
  style: { fg, bg, border.fg, scrollbar.bg, focus.bg, hover.bg },
  border: { type: 'line'|'bg', bg, fg, bold, underline }
  tags: true,  // parse {bold}tags{/bold}

  top, left, width, height,
  width: '100%',
  height: '100%-1',
  top: 'center'
})
```

### Tags

```
{bold}
{right} {center}
{|}    left-right separator
{#c0ff33-fg}{/}
```

```
blessed.escape('...')
```


id: bash
git_filename: ./bash.md
format: md
field_title: Bash scripting
field_category: CLI
field_tags: Featured
field_updated: 2020-07-05
field_updated___timezone: UTC
data:
{"title": "Bash scripting", "category": "CLI", "tags": ["Featured"], "updated": "2020-07-05", "keywords": ["Variables", "Functions", "Interpolation", "Brace expansions", "Loops", "Conditional execution", "Command substitution"], "body": "## Getting started\n{: .-three-column}\n\n### Introduction\n{: .-intro}\n\nThis is a quick reference to getting started with Bash scripting.\n\n- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_\n- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_\n- [Bash Hackers Wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(wiki.bash-hackers.org)_\n\n### Example\n\n```bash\n#!/usr/bin/env bash\n\nname=\"John\"\necho \"Hello $name!\"\n```\n\n### Variables\n\n```bash\nname=\"John\"\necho $name  # see below\necho \"$name\"\necho \"${name}!\"\n```\n\nGenerally quote your variables unless they contain wildcards to expand or command fragments.\n\n```bash\nwildcard=\"*.txt\"\noptions=\"iv\"\ncp -$options $wildcard /tmp\n```\n\n### String quotes\n\n```bash\nname=\"John\"\necho \"Hi $name\"  #=> Hi John\necho 'Hi $name'  #=> Hi $name\n```\n\n### Shell execution\n\n```bash\necho \"I'm in $(pwd)\"\necho \"I'm in `pwd`\"  # obsolescent\n# Same\n```\n\nSee [Command substitution](https://web.archive.org/web/20230326081741/https://wiki.bash-hackers.org/syntax/expansion/cmdsubst)\n\n### Conditional execution\n\n```bash\ngit commit && git push\ngit commit || echo \"Commit failed\"\n```\n\n### Functions\n{: id='functions-example'}\n\n```bash\nget_name() {\n  echo \"John\"\n}\n\necho \"You are $(get_name)\"\n```\n\nSee: [Functions](#functions)\n\n### Conditionals\n{: id='conditionals-example'}\n\n```bash\nif [[ -z \"$string\" ]]; then\n  echo \"String is empty\"\nelif [[ -n \"$string\" ]]; then\n  echo \"String is not empty\"\nfi\n```\n\nSee: [Conditionals](#conditionals)\n\n### Strict mode\n\n```bash\nset -euo pipefail\nIFS=$'\\n\\t'\n```\n\nSee: [Unofficial bash strict mode](http://redsymbol.net/articles/unofficial-bash-strict-mode/)\n\n### Brace expansion\n\n```bash\necho {A,B}.js\n```\n\n| Expression             | Description           |\n| ---------------------- | --------------------- |\n| `{A,B}`                | Same as `A B`         |\n| `{A,B}.js`             | Same as `A.js B.js`   |\n| `{1..5}`               | Same as `1 2 3 4 5`   |\n| <code>&lcub;{1..3},{7..9}}</code> | Same as `1 2 3 7 8 9` |\n\nSee: [Brace expansion](https://web.archive.org/web/20230207192110/https://wiki.bash-hackers.org/syntax/expansion/brace)\n\n## Parameter expansions\n{: .-three-column}\n\n### Basics\n\n```bash\nname=\"John\"\necho \"${name}\"\necho \"${name/J/j}\"    #=> \"john\" (substitution)\necho \"${name:0:2}\"    #=> \"Jo\" (slicing)\necho \"${name::2}\"     #=> \"Jo\" (slicing)\necho \"${name::-1}\"    #=> \"Joh\" (slicing)\necho \"${name:(-1)}\"   #=> \"n\" (slicing from right)\necho \"${name:(-2):1}\" #=> \"h\" (slicing from right)\necho \"${food:-Cake}\"  #=> $food or \"Cake\"\n```\n\n```bash\nlength=2\necho \"${name:0:length}\"  #=> \"Jo\"\n```\n\nSee: [Parameter expansion](https://web.archive.org/web/20230408142504/https://wiki.bash-hackers.org/syntax/pe)\n\n```bash\nstr=\"/path/to/foo.cpp\"\necho \"${str%.cpp}\"    # /path/to/foo\necho \"${str%.cpp}.o\"  # /path/to/foo.o\necho \"${str%/*}\"      # /path/to\n\necho \"${str##*.}\"     # cpp (extension)\necho \"${str##*/}\"     # foo.cpp (basepath)\n\necho \"${str#*/}\"      # path/to/foo.cpp\necho \"${str##*/}\"     # foo.cpp\n\necho \"${str/foo/bar}\" # /path/to/bar.cpp\n```\n\n```bash\nstr=\"Hello world\"\necho \"${str:6:5}\"    # \"world\"\necho \"${str: -5:5}\"  # \"world\"\n```\n\n```bash\nsrc=\"/path/to/foo.cpp\"\nbase=${src##*/}   #=> \"foo.cpp\" (basepath)\ndir=${src%$base}  #=> \"/path/to/\" (dirpath)\ndir=${src%/*}     #=> \"/path/to\" (dirpath)\n```\n\n### Prefix name expansion\n\n```bash\nprefix_a=one\nprefix_b=two\necho ${!prefix_*}  # all variables names starting with `prefix_`\nprefix_a prefix_b\n```\n\n### Indirection\n\n```bash\nname=joe\npointer=name\necho ${!pointer}\njoe\n```\n\n### Substitution\n\n| Code              | Description         |\n| ----------------- | ------------------- |\n| `${foo%suffix}`   | Remove suffix       |\n| `${foo#prefix}`   | Remove prefix       |\n| ---               | ---                 |\n| `${foo%%suffix}`  | Remove long suffix  |\n| `${foo/%suffix}`  | Remove long suffix  |\n| `${foo##prefix}`  | Remove long prefix  |\n| `${foo/#prefix}`  | Remove long prefix  |\n| ---               | ---                 |\n| `${foo/from/to}`  | Replace first match |\n| `${foo//from/to}` | Replace all         |\n| ---               | ---                 |\n| `${foo/%from/to}` | Replace suffix      |\n| `${foo/#from/to}` | Replace prefix      |\n\n### Comments\n\n```bash\n# Single line comment\n```\n\n```bash\n: '\nThis is a\nmulti line\ncomment\n'\n```\n\n### Substrings\n\n| Expression      | Description                    |\n| --------------- | ------------------------------ |\n| `${foo:0:3}`    | Substring _(position, length)_ |\n| `${foo:(-3):3}` | Substring from the right       |\n\n### Length\n\n| Expression | Description      |\n| ---------- | ---------------- |\n| `${#foo}`  | Length of `$foo` |\n\n### Manipulation\n\n```bash\nstr=\"HELLO WORLD!\"\necho \"${str,}\"   #=> \"hELLO WORLD!\" (lowercase 1st letter)\necho \"${str,,}\"  #=> \"hello world!\" (all lowercase)\n\nstr=\"hello world!\"\necho \"${str^}\"   #=> \"Hello world!\" (uppercase 1st letter)\necho \"${str^^}\"  #=> \"HELLO WORLD!\" (all uppercase)\n```\n\n### Default values\n\n| Expression        | Description                                              |\n| ----------------- | -------------------------------------------------------- |\n| `${foo:-val}`     | `$foo`, or `val` if unset (or null)                      |\n| `${foo:=val}`     | Set `$foo` to `val` if unset (or null)                   |\n| `${foo:+val}`     | `val` if `$foo` is set (and not null)                    |\n| `${foo:?message}` | Show error message and exit if `$foo` is unset (or null) |\n\nOmitting the `:` removes the (non)nullity checks, e.g. `${foo-val}` expands to `val` if unset otherwise `$foo`.\n\n## Loops\n{: .-three-column}\n\n### Basic for loop\n\n```bash\nfor i in /etc/rc.*; do\n  echo \"$i\"\ndone\n```\n\n### C-like for loop\n\n```bash\nfor ((i = 0 ; i < 100 ; i++)); do\n  echo \"$i\"\ndone\n```\n\n### Ranges\n\n```bash\nfor i in {1..5}; do\n    echo \"Welcome $i\"\ndone\n```\n\n#### With step size\n\n```bash\nfor i in {5..50..5}; do\n    echo \"Welcome $i\"\ndone\n```\n\n### Reading lines\n\n```bash\nwhile read -r line; do\n  echo \"$line\"\ndone <file.txt\n```\n\n### Forever\n\n```bash\nwhile true; do\n  \u00b7\u00b7\u00b7\ndone\n```\n\n## Functions\n{: .-three-column}\n\n### Defining functions\n\n```bash\nmyfunc() {\n    echo \"hello $1\"\n}\n```\n\n```bash\n# Same as above (alternate syntax)\nfunction myfunc {\n    echo \"hello $1\"\n}\n```\n\n```bash\nmyfunc \"John\"\n```\n\n### Returning values\n\n```bash\nmyfunc() {\n    local myresult='some value'\n    echo \"$myresult\"\n}\n```\n\n```bash\nresult=$(myfunc)\n```\n\n### Raising errors\n\n```bash\nmyfunc() {\n  return 1\n}\n```\n\n```bash\nif myfunc; then\n  echo \"success\"\nelse\n  echo \"failure\"\nfi\n```\n\n### Arguments\n\n| Expression | Description                                    |\n| ---------- | ---------------------------------------------- |\n| `$#`       | Number of arguments                            |\n| `$*`       | All positional arguments (as a single word)    |\n| `$@`       | All positional arguments (as separate strings) |\n| `$1`       | First argument                                 |\n| `$_`       | Last argument of the previous command          |\n\n**Note**: `$@` and `$*` must be quoted in order to perform as described.\nOtherwise, they do exactly the same thing (arguments as separate strings).\n\nSee [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).\n\n## Conditionals\n{: .-three-column}\n\n### Conditions\n\nNote that `[[` is actually a command/program that returns either `0` (true) or `1` (false). Any program that obeys the same logic (like all base utils, such as `grep(1)` or `ping(1)`) can be used as condition, see examples.\n\n| Condition                | Description           |\n| ------------------------ | --------------------- |\n| `[[ -z STRING ]]`        | Empty string          |\n| `[[ -n STRING ]]`        | Not empty string      |\n| `[[ STRING == STRING ]]` | Equal                 |\n| `[[ STRING != STRING ]]` | Not Equal             |\n| ---                      | ---                   |\n| `[[ NUM -eq NUM ]]`      | Equal                 |\n| `[[ NUM -ne NUM ]]`      | Not equal             |\n| `[[ NUM -lt NUM ]]`      | Less than             |\n| `[[ NUM -le NUM ]]`      | Less than or equal    |\n| `[[ NUM -gt NUM ]]`      | Greater than          |\n| `[[ NUM -ge NUM ]]`      | Greater than or equal |\n| ---                      | ---                   |\n| `[[ STRING =~ STRING ]]` | Regexp                |\n| ---                      | ---                   |\n| `(( NUM < NUM ))`        | Numeric conditions    |\n\n#### More conditions\n\n| Condition            | Description              |\n| -------------------- | ------------------------ |\n| `[[ -o noclobber ]]` | If OPTIONNAME is enabled |\n| ---                  | ---                      |\n| `[[ ! EXPR ]]`       | Not                      |\n| `[[ X && Y ]]`       | And                      |\n| `[[ X || Y ]]`       | Or                       |\n\n### File conditions\n\n| Condition               | Description             |\n| ----------------------- | ----------------------- |\n| `[[ -e FILE ]]`         | Exists                  |\n| `[[ -r FILE ]]`         | Readable                |\n| `[[ -h FILE ]]`         | Symlink                 |\n| `[[ -d FILE ]]`         | Directory               |\n| `[[ -w FILE ]]`         | Writable                |\n| `[[ -s FILE ]]`         | Size is > 0 bytes       |\n| `[[ -f FILE ]]`         | File                    |\n| `[[ -x FILE ]]`         | Executable              |\n| ---                     | ---                     |\n| `[[ FILE1 -nt FILE2 ]]` | 1 is more recent than 2 |\n| `[[ FILE1 -ot FILE2 ]]` | 2 is more recent than 1 |\n| `[[ FILE1 -ef FILE2 ]]` | Same files              |\n\n### Example\n\n```bash\n# String\nif [[ -z \"$string\" ]]; then\n  echo \"String is empty\"\nelif [[ -n \"$string\" ]]; then\n  echo \"String is not empty\"\nelse\n  echo \"This never happens\"\nfi\n```\n\n```bash\n# Combinations\nif [[ X && Y ]]; then\n  ...\nfi\n```\n\n```bash\n# Equal\nif [[ \"$A\" == \"$B\" ]]\n```\n\n```bash\n# Regex\nif [[ \"A\" =~ . ]]\n```\n\n```bash\nif (( $a < $b )); then\n   echo \"$a is smaller than $b\"\nfi\n```\n\n```bash\nif [[ -e \"file.txt\" ]]; then\n  echo \"file exists\"\nfi\n```\n\n## Arrays\n\n### Defining arrays\n\n```bash\nFruits=('Apple' 'Banana' 'Orange')\n```\n\n```bash\nFruits[0]=\"Apple\"\nFruits[1]=\"Banana\"\nFruits[2]=\"Orange\"\n```\n\n### Working with arrays\n\n```bash\necho \"${Fruits[0]}\"           # Element #0\necho \"${Fruits[-1]}\"          # Last element\necho \"${Fruits[@]}\"           # All elements, space-separated\necho \"${#Fruits[@]}\"          # Number of elements\necho \"${#Fruits}\"             # String length of the 1st element\necho \"${#Fruits[3]}\"          # String length of the Nth element\necho \"${Fruits[@]:3:2}\"       # Range (from position 3, length 2)\necho \"${!Fruits[@]}\"          # Keys of all elements, space-separated\n```\n\n### Operations\n\n```bash\nFruits=(\"${Fruits[@]}\" \"Watermelon\")    # Push\nFruits+=('Watermelon')                  # Also Push\nFruits=( \"${Fruits[@]/Ap*/}\" )          # Remove by regex match\nunset Fruits[2]                         # Remove one item\nFruits=(\"${Fruits[@]}\")                 # Duplicate\nFruits=(\"${Fruits[@]}\" \"${Veggies[@]}\") # Concatenate\nwords=($(< datafile))                   # From file (split by IFS)\n```\n\n### Iteration\n\n```bash\nfor i in \"${arrayName[@]}\"; do\n  echo \"$i\"\ndone\n```\n\n## Dictionaries\n{: .-three-column}\n\n### Defining\n\n```bash\ndeclare -A sounds\n```\n\n```bash\nsounds[dog]=\"bark\"\nsounds[cow]=\"moo\"\nsounds[bird]=\"tweet\"\nsounds[wolf]=\"howl\"\n```\n\nDeclares `sound` as a Dictionary object (aka associative array).\n\n### Working with dictionaries\n\n```bash\necho \"${sounds[dog]}\" # Dog's sound\necho \"${sounds[@]}\"   # All values\necho \"${!sounds[@]}\"  # All keys\necho \"${#sounds[@]}\"  # Number of elements\nunset sounds[dog]     # Delete dog\n```\n\n### Iteration\n\n#### Iterate over values\n\n```bash\nfor val in \"${sounds[@]}\"; do\n  echo \"$val\"\ndone\n```\n\n#### Iterate over keys\n\n```bash\nfor key in \"${!sounds[@]}\"; do\n  echo \"$key\"\ndone\n```\n\n## Options\n\n### Options\n\n```bash\nset -o noclobber  # Avoid overlay files (echo \"hi\" > foo)\nset -o errexit    # Used to exit upon error, avoiding cascading errors\nset -o pipefail   # Unveils hidden failures\nset -o nounset    # Exposes unset variables\n```\n\n### Glob options\n\n```bash\nshopt -s nullglob    # Non-matching globs are removed  ('*.foo' => '')\nshopt -s failglob    # Non-matching globs throw errors\nshopt -s nocaseglob  # Case insensitive globs\nshopt -s dotglob     # Wildcards match dotfiles (\"*.sh\" => \".foo.sh\")\nshopt -s globstar    # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b/c.rb')\n```\n\nSet `GLOBIGNORE` as a colon-separated list of patterns to be removed from glob\nmatches.\n\n## History\n\n### Commands\n\n| Command               | Description                               |\n| --------------------- | ----------------------------------------- |\n| `history`             | Show history                              |\n| `shopt -s histverify` | Don't execute expanded result immediately |\n\n### Expansions\n\n| Expression   | Description                                          |\n| ------------ | ---------------------------------------------------- |\n| `!$`         | Expand last parameter of most recent command         |\n| `!*`         | Expand all parameters of most recent command         |\n| `!-n`        | Expand `n`th most recent command                     |\n| `!n`         | Expand `n`th command in history                      |\n| `!<command>` | Expand most recent invocation of command `<command>` |\n\n### Operations\n\n| Code                 | Description                                                           |\n| -------------------- | --------------------------------------------------------------------- |\n| `!!`                 | Execute last command again                                            |\n| `!!:s/<FROM>/<TO>/`  | Replace first occurrence of `<FROM>` to `<TO>` in most recent command |\n| `!!:gs/<FROM>/<TO>/` | Replace all occurrences of `<FROM>` to `<TO>` in most recent command  |\n| `!$:t`               | Expand only basename from last parameter of most recent command       |\n| `!$:h`               | Expand only directory from last parameter of most recent command      |\n\n`!!` and `!$` can be replaced with any valid expansion.\n\n### Slices\n\n| Code     | Description                                                                              |\n| -------- | ---------------------------------------------------------------------------------------- |\n| `!!:n`   | Expand only `n`th token from most recent command (command is `0`; first argument is `1`) |\n| `!^`     | Expand first argument from most recent command                                           |\n| `!$`     | Expand last token from most recent command                                               |\n| `!!:n-m` | Expand range of tokens from most recent command                                          |\n| `!!:n-$` | Expand `n`th token to last from most recent command                                      |\n\n`!!` can be replaced with any valid expansion i.e. `!cat`, `!-2`, `!42`, etc.\n\n## Miscellaneous\n\n### Numeric calculations\n\n```bash\n$((a + 200))      # Add 200 to $a\n```\n\n```bash\n$(($RANDOM%200))  # Random number 0..199\n```\n\n```bash\ndeclare -i count  # Declare as type integer\ncount+=1          # Increment\n```\n\n### Subshells\n\n```bash\n(cd somedir; echo \"I'm now in $PWD\")\npwd # still in first directory\n```\n\n### Redirection\n\n```bash\npython hello.py > output.txt            # stdout to (file)\npython hello.py >> output.txt           # stdout to (file), append\npython hello.py 2> error.log            # stderr to (file)\npython hello.py 2>&1                    # stderr to stdout\npython hello.py 2>/dev/null             # stderr to (null)\npython hello.py >output.txt 2>&1        # stdout and stderr to (file), equivalent to &>\npython hello.py &>/dev/null             # stdout and stderr to (null)\necho \"$0: warning: too many users\" >&2  # print diagnostic message to stderr\n```\n\n```bash\npython hello.py < foo.txt      # feed foo.txt to stdin for python\ndiff <(ls -r) <(ls)            # Compare two stdout without files\n```\n\n### Inspecting commands\n\n```bash\ncommand -V cd\n#=> \"cd is a function/alias/whatever\"\n```\n\n### Trap errors\n\n```bash\ntrap 'echo Error at about $LINENO' ERR\n```\n\nor\n\n```bash\ntraperr() {\n  echo \"ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}\"\n}\n\nset -o errtrace\ntrap traperr ERR\n```\n\n### Case/switch\n\n```bash\ncase \"$1\" in\n  start | up)\n    vagrant up\n    ;;\n\n  *)\n    echo \"Usage: $0 {start|stop|ssh}\"\n    ;;\nesac\n```\n\n### Source relative\n\n```bash\nsource \"${0%/*}/../share/foo.sh\"\n```\n\n### printf\n\n```bash\nprintf \"Hello %s, I'm %s\" Sven Olga\n#=> \"Hello Sven, I'm Olga\n\nprintf \"1 + 1 = %d\" 2\n#=> \"1 + 1 = 2\"\n\nprintf \"This is how you print a float: %f\" 2\n#=> \"This is how you print a float: 2.000000\"\n\nprintf '%s\\n' '#!/bin/bash' 'echo hello' >file\n# format string is applied to each group of arguments\nprintf '%i+%i=%i\\n' 1 2 3  4 5 9\n```\n\n### Transform strings\n\n| Command option | Description                                         |\n| -------------- | --------------------------------------------------- |\n| `-c`           | Operations apply to characters not in the given set |\n| `-d`           | Delete characters                                   |\n| `-s`           | Replaces repeated characters with single occurrence |\n| `-t`           | Truncates                                           |\n| `[:upper:]`    | All upper case letters                              |\n| `[:lower:]`    | All lower case letters                              |\n| `[:digit:]`    | All digits                                          |\n| `[:space:]`    | All whitespace                                      |\n| `[:alpha:]`    | All letters                                         |\n| `[:alnum:]`    | All letters and digits                              |\n\n#### Example\n\n```bash\necho \"Welcome To Devhints\" | tr '[:lower:]' '[:upper:]'\nWELCOME TO DEVHINTS\n```\n\n### Directory of script\n\n```bash\ndir=${0%/*}\n```\n\n### Getting options\n\n```bash\nwhile [[ \"$1\" =~ ^- && ! \"$1\" == \"--\" ]]; do case $1 in\n  -V | --version )\n    echo \"$version\"\n    exit\n    ;;\n  -s | --string )\n    shift; string=$1\n    ;;\n  -f | --flag )\n    flag=1\n    ;;\nesac; shift; done\nif [[ \"$1\" == '--' ]]; then shift; fi\n```\n\n### Heredoc\n\n```sh\ncat <<END\nhello world\nEND\n```\n\nHeredoc allows a section of your source code to be treated as a file. See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Documents).\n\n### Herestring\n\n```sh\ntr '[:lower:]' '[:upper:]' <<< \"Will be uppercased, even $variable\"\n```\n\nHerestring allows a string to be treated as a standard input (stdin). See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Strings).\n\n### Process substitution\n\n```sh \n# loop on myfunc output lines\nwhile read -r line; do\n  echo \"$line\"\ndone < <(myfunc)\n\n# compare content of two folders\ndiff <(ls \"$dir1\") <(ls \"$dir2\")\n```\n\nProcess substitution allows the input (or output) of a command to be treated as a file. See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html).\n\n### Reading input\n\n```bash\necho -n \"Proceed? [y/n]: \"\nread -r ans\necho \"$ans\"\n```\n\nThe `-r` option disables a peculiar legacy behavior with backslashes.\n\n```bash\nread -n 1 ans    # Just one character\n```\n\n### Special variables\n\n| Expression         | Description                            |\n| ------------------ | -------------------------------------- |\n| `$?`               | Exit status of last task               |\n| `$!`               | PID of last background task            |\n| `$$`               | PID of shell                           |\n| `$0`               | Filename of the shell script           |\n| `$_`               | Last argument of the previous command  |\n| `${PIPESTATUS[n]}` | return value of piped commands (array) |\n\nSee [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).\n\n### Go to previous directory\n\n```bash\npwd # /home/user/foo\ncd bar/\npwd # /home/user/foo/bar\ncd -\npwd # /home/user/foo\n```\n\n### Check for command's result\n\n```bash\nif ping -c 1 google.com; then\n  echo \"It appears you have a working internet connection\"\nfi\n```\n\n### Grep check\n\n```bash\nif grep -q 'foo' ~/.bash_history; then\n  echo \"You appear to have typed 'foo' in the past\"\nfi\n```\n\n## Also see\n{: .-one-column}\n\n- [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_\n- [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_\n- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_\n- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_\n- [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_"}

field_body:
## Getting started
{: .-three-column}

### Introduction
{: .-intro}

This is a quick reference to getting started with Bash scripting.

- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_
- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_
- [Bash Hackers Wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(wiki.bash-hackers.org)_

### Example

```bash
#!/usr/bin/env bash

name="John"
echo "Hello $name!"
```

### Variables

```bash
name="John"
echo $name  # see below
echo "$name"
echo "${name}!"
```

Generally quote your variables unless they contain wildcards to expand or command fragments.

```bash
wildcard="*.txt"
options="iv"
cp -$options $wildcard /tmp
```

### String quotes

```bash
name="John"
echo "Hi $name"  #=> Hi John
echo 'Hi $name'  #=> Hi $name
```

### Shell execution

```bash
echo "I'm in $(pwd)"
echo "I'm in `pwd`"  # obsolescent
# Same
```

See [Command substitution](https://web.archive.org/web/20230326081741/https://wiki.bash-hackers.org/syntax/expansion/cmdsubst)

### Conditional execution

```bash
git commit && git push
git commit || echo "Commit failed"
```

### Functions
{: id='functions-example'}

```bash
get_name() {
  echo "John"
}

echo "You are $(get_name)"
```

See: [Functions](#functions)

### Conditionals
{: id='conditionals-example'}

```bash
if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
fi
```

See: [Conditionals](#conditionals)

### Strict mode

```bash
set -euo pipefail
IFS=$'\n\t'
```

See: [Unofficial bash strict mode](http://redsymbol.net/articles/unofficial-bash-strict-mode/)

### Brace expansion

```bash
echo {A,B}.js
```

| Expression             | Description           |
| ---------------------- | --------------------- |
| `{A,B}`                | Same as `A B`         |
| `{A,B}.js`             | Same as `A.js B.js`   |
| `{1..5}`               | Same as `1 2 3 4 5`   |
| <code>&lcub;{1..3},{7..9}}</code> | Same as `1 2 3 7 8 9` |

See: [Brace expansion](https://web.archive.org/web/20230207192110/https://wiki.bash-hackers.org/syntax/expansion/brace)

## Parameter expansions
{: .-three-column}

### Basics

```bash
name="John"
echo "${name}"
echo "${name/J/j}"    #=> "john" (substitution)
echo "${name:0:2}"    #=> "Jo" (slicing)
echo "${name::2}"     #=> "Jo" (slicing)
echo "${name::-1}"    #=> "Joh" (slicing)
echo "${name:(-1)}"   #=> "n" (slicing from right)
echo "${name:(-2):1}" #=> "h" (slicing from right)
echo "${food:-Cake}"  #=> $food or "Cake"
```

```bash
length=2
echo "${name:0:length}"  #=> "Jo"
```

See: [Parameter expansion](https://web.archive.org/web/20230408142504/https://wiki.bash-hackers.org/syntax/pe)

```bash
str="/path/to/foo.cpp"
echo "${str%.cpp}"    # /path/to/foo
echo "${str%.cpp}.o"  # /path/to/foo.o
echo "${str%/*}"      # /path/to

echo "${str##*.}"     # cpp (extension)
echo "${str##*/}"     # foo.cpp (basepath)

echo "${str#*/}"      # path/to/foo.cpp
echo "${str##*/}"     # foo.cpp

echo "${str/foo/bar}" # /path/to/bar.cpp
```

```bash
str="Hello world"
echo "${str:6:5}"    # "world"
echo "${str: -5:5}"  # "world"
```

```bash
src="/path/to/foo.cpp"
base=${src##*/}   #=> "foo.cpp" (basepath)
dir=${src%$base}  #=> "/path/to/" (dirpath)
dir=${src%/*}     #=> "/path/to" (dirpath)
```

### Prefix name expansion

```bash
prefix_a=one
prefix_b=two
echo ${!prefix_*}  # all variables names starting with `prefix_`
prefix_a prefix_b
```

### Indirection

```bash
name=joe
pointer=name
echo ${!pointer}
joe
```

### Substitution

| Code              | Description         |
| ----------------- | ------------------- |
| `${foo%suffix}`   | Remove suffix       |
| `${foo#prefix}`   | Remove prefix       |
| ---               | ---                 |
| `${foo%%suffix}`  | Remove long suffix  |
| `${foo/%suffix}`  | Remove long suffix  |
| `${foo##prefix}`  | Remove long prefix  |
| `${foo/#prefix}`  | Remove long prefix  |
| ---               | ---                 |
| `${foo/from/to}`  | Replace first match |
| `${foo//from/to}` | Replace all         |
| ---               | ---                 |
| `${foo/%from/to}` | Replace suffix      |
| `${foo/#from/to}` | Replace prefix      |

### Comments

```bash
# Single line comment
```

```bash
: '
This is a
multi line
comment
'
```

### Substrings

| Expression      | Description                    |
| --------------- | ------------------------------ |
| `${foo:0:3}`    | Substring _(position, length)_ |
| `${foo:(-3):3}` | Substring from the right       |

### Length

| Expression | Description      |
| ---------- | ---------------- |
| `${#foo}`  | Length of `$foo` |

### Manipulation

```bash
str="HELLO WORLD!"
echo "${str,}"   #=> "hELLO WORLD!" (lowercase 1st letter)
echo "${str,,}"  #=> "hello world!" (all lowercase)

str="hello world!"
echo "${str^}"   #=> "Hello world!" (uppercase 1st letter)
echo "${str^^}"  #=> "HELLO WORLD!" (all uppercase)
```

### Default values

| Expression        | Description                                              |
| ----------------- | -------------------------------------------------------- |
| `${foo:-val}`     | `$foo`, or `val` if unset (or null)                      |
| `${foo:=val}`     | Set `$foo` to `val` if unset (or null)                   |
| `${foo:+val}`     | `val` if `$foo` is set (and not null)                    |
| `${foo:?message}` | Show error message and exit if `$foo` is unset (or null) |

Omitting the `:` removes the (non)nullity checks, e.g. `${foo-val}` expands to `val` if unset otherwise `$foo`.

## Loops
{: .-three-column}

### Basic for loop

```bash
for i in /etc/rc.*; do
  echo "$i"
done
```

### C-like for loop

```bash
for ((i = 0 ; i < 100 ; i++)); do
  echo "$i"
done
```

### Ranges

```bash
for i in {1..5}; do
    echo "Welcome $i"
done
```

#### With step size

```bash
for i in {5..50..5}; do
    echo "Welcome $i"
done
```

### Reading lines

```bash
while read -r line; do
  echo "$line"
done <file.txt
```

### Forever

```bash
while true; do
  ···
done
```

## Functions
{: .-three-column}

### Defining functions

```bash
myfunc() {
    echo "hello $1"
}
```

```bash
# Same as above (alternate syntax)
function myfunc {
    echo "hello $1"
}
```

```bash
myfunc "John"
```

### Returning values

```bash
myfunc() {
    local myresult='some value'
    echo "$myresult"
}
```

```bash
result=$(myfunc)
```

### Raising errors

```bash
myfunc() {
  return 1
}
```

```bash
if myfunc; then
  echo "success"
else
  echo "failure"
fi
```

### Arguments

| Expression | Description                                    |
| ---------- | ---------------------------------------------- |
| `$#`       | Number of arguments                            |
| `$*`       | All positional arguments (as a single word)    |
| `$@`       | All positional arguments (as separate strings) |
| `$1`       | First argument                                 |
| `$_`       | Last argument of the previous command          |

**Note**: `$@` and `$*` must be quoted in order to perform as described.
Otherwise, they do exactly the same thing (arguments as separate strings).

See [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).

## Conditionals
{: .-three-column}

### Conditions

Note that `[[` is actually a command/program that returns either `0` (true) or `1` (false). Any program that obeys the same logic (like all base utils, such as `grep(1)` or `ping(1)`) can be used as condition, see examples.

| Condition                | Description           |
| ------------------------ | --------------------- |
| `[[ -z STRING ]]`        | Empty string          |
| `[[ -n STRING ]]`        | Not empty string      |
| `[[ STRING == STRING ]]` | Equal                 |
| `[[ STRING != STRING ]]` | Not Equal             |
| ---                      | ---                   |
| `[[ NUM -eq NUM ]]`      | Equal                 |
| `[[ NUM -ne NUM ]]`      | Not equal             |
| `[[ NUM -lt NUM ]]`      | Less than             |
| `[[ NUM -le NUM ]]`      | Less than or equal    |
| `[[ NUM -gt NUM ]]`      | Greater than          |
| `[[ NUM -ge NUM ]]`      | Greater than or equal |
| ---                      | ---                   |
| `[[ STRING =~ STRING ]]` | Regexp                |
| ---                      | ---                   |
| `(( NUM < NUM ))`        | Numeric conditions    |

#### More conditions

| Condition            | Description              |
| -------------------- | ------------------------ |
| `[[ -o noclobber ]]` | If OPTIONNAME is enabled |
| ---                  | ---                      |
| `[[ ! EXPR ]]`       | Not                      |
| `[[ X && Y ]]`       | And                      |
| `[[ X || Y ]]`       | Or                       |

### File conditions

| Condition               | Description             |
| ----------------------- | ----------------------- |
| `[[ -e FILE ]]`         | Exists                  |
| `[[ -r FILE ]]`         | Readable                |
| `[[ -h FILE ]]`         | Symlink                 |
| `[[ -d FILE ]]`         | Directory               |
| `[[ -w FILE ]]`         | Writable                |
| `[[ -s FILE ]]`         | Size is > 0 bytes       |
| `[[ -f FILE ]]`         | File                    |
| `[[ -x FILE ]]`         | Executable              |
| ---                     | ---                     |
| `[[ FILE1 -nt FILE2 ]]` | 1 is more recent than 2 |
| `[[ FILE1 -ot FILE2 ]]` | 2 is more recent than 1 |
| `[[ FILE1 -ef FILE2 ]]` | Same files              |

### Example

```bash
# String
if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
else
  echo "This never happens"
fi
```

```bash
# Combinations
if [[ X && Y ]]; then
  ...
fi
```

```bash
# Equal
if [[ "$A" == "$B" ]]
```

```bash
# Regex
if [[ "A" =~ . ]]
```

```bash
if (( $a < $b )); then
   echo "$a is smaller than $b"
fi
```

```bash
if [[ -e "file.txt" ]]; then
  echo "file exists"
fi
```

## Arrays

### Defining arrays

```bash
Fruits=('Apple' 'Banana' 'Orange')
```

```bash
Fruits[0]="Apple"
Fruits[1]="Banana"
Fruits[2]="Orange"
```

### Working with arrays

```bash
echo "${Fruits[0]}"           # Element #0
echo "${Fruits[-1]}"          # Last element
echo "${Fruits[@]}"           # All elements, space-separated
echo "${#Fruits[@]}"          # Number of elements
echo "${#Fruits}"             # String length of the 1st element
echo "${#Fruits[3]}"          # String length of the Nth element
echo "${Fruits[@]:3:2}"       # Range (from position 3, length 2)
echo "${!Fruits[@]}"          # Keys of all elements, space-separated
```

### Operations

```bash
Fruits=("${Fruits[@]}" "Watermelon")    # Push
Fruits+=('Watermelon')                  # Also Push
Fruits=( "${Fruits[@]/Ap*/}" )          # Remove by regex match
unset Fruits[2]                         # Remove one item
Fruits=("${Fruits[@]}")                 # Duplicate
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
words=($(< datafile))                   # From file (split by IFS)
```

### Iteration

```bash
for i in "${arrayName[@]}"; do
  echo "$i"
done
```

## Dictionaries
{: .-three-column}

### Defining

```bash
declare -A sounds
```

```bash
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"
```

Declares `sound` as a Dictionary object (aka associative array).

### Working with dictionaries

```bash
echo "${sounds[dog]}" # Dog's sound
echo "${sounds[@]}"   # All values
echo "${!sounds[@]}"  # All keys
echo "${#sounds[@]}"  # Number of elements
unset sounds[dog]     # Delete dog
```

### Iteration

#### Iterate over values

```bash
for val in "${sounds[@]}"; do
  echo "$val"
done
```

#### Iterate over keys

```bash
for key in "${!sounds[@]}"; do
  echo "$key"
done
```

## Options

### Options

```bash
set -o noclobber  # Avoid overlay files (echo "hi" > foo)
set -o errexit    # Used to exit upon error, avoiding cascading errors
set -o pipefail   # Unveils hidden failures
set -o nounset    # Exposes unset variables
```

### Glob options

```bash
shopt -s nullglob    # Non-matching globs are removed  ('*.foo' => '')
shopt -s failglob    # Non-matching globs throw errors
shopt -s nocaseglob  # Case insensitive globs
shopt -s dotglob     # Wildcards match dotfiles ("*.sh" => ".foo.sh")
shopt -s globstar    # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b/c.rb')
```

Set `GLOBIGNORE` as a colon-separated list of patterns to be removed from glob
matches.

## History

### Commands

| Command               | Description                               |
| --------------------- | ----------------------------------------- |
| `history`             | Show history                              |
| `shopt -s histverify` | Don't execute expanded result immediately |

### Expansions

| Expression   | Description                                          |
| ------------ | ---------------------------------------------------- |
| `!$`         | Expand last parameter of most recent command         |
| `!*`         | Expand all parameters of most recent command         |
| `!-n`        | Expand `n`th most recent command                     |
| `!n`         | Expand `n`th command in history                      |
| `!<command>` | Expand most recent invocation of command `<command>` |

### Operations

| Code                 | Description                                                           |
| -------------------- | --------------------------------------------------------------------- |
| `!!`                 | Execute last command again                                            |
| `!!:s/<FROM>/<TO>/`  | Replace first occurrence of `<FROM>` to `<TO>` in most recent command |
| `!!:gs/<FROM>/<TO>/` | Replace all occurrences of `<FROM>` to `<TO>` in most recent command  |
| `!$:t`               | Expand only basename from last parameter of most recent command       |
| `!$:h`               | Expand only directory from last parameter of most recent command      |

`!!` and `!$` can be replaced with any valid expansion.

### Slices

| Code     | Description                                                                              |
| -------- | ---------------------------------------------------------------------------------------- |
| `!!:n`   | Expand only `n`th token from most recent command (command is `0`; first argument is `1`) |
| `!^`     | Expand first argument from most recent command                                           |
| `!$`     | Expand last token from most recent command                                               |
| `!!:n-m` | Expand range of tokens from most recent command                                          |
| `!!:n-$` | Expand `n`th token to last from most recent command                                      |

`!!` can be replaced with any valid expansion i.e. `!cat`, `!-2`, `!42`, etc.

## Miscellaneous

### Numeric calculations

```bash
$((a + 200))      # Add 200 to $a
```

```bash
$(($RANDOM%200))  # Random number 0..199
```

```bash
declare -i count  # Declare as type integer
count+=1          # Increment
```

### Subshells

```bash
(cd somedir; echo "I'm now in $PWD")
pwd # still in first directory
```

### Redirection

```bash
python hello.py > output.txt            # stdout to (file)
python hello.py >> output.txt           # stdout to (file), append
python hello.py 2> error.log            # stderr to (file)
python hello.py 2>&1                    # stderr to stdout
python hello.py 2>/dev/null             # stderr to (null)
python hello.py >output.txt 2>&1        # stdout and stderr to (file), equivalent to &>
python hello.py &>/dev/null             # stdout and stderr to (null)
echo "$0: warning: too many users" >&2  # print diagnostic message to stderr
```

```bash
python hello.py < foo.txt      # feed foo.txt to stdin for python
diff <(ls -r) <(ls)            # Compare two stdout without files
```

### Inspecting commands

```bash
command -V cd
#=> "cd is a function/alias/whatever"
```

### Trap errors

```bash
trap 'echo Error at about $LINENO' ERR
```

or

```bash
traperr() {
  echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
}

set -o errtrace
trap traperr ERR
```

### Case/switch

```bash
case "$1" in
  start | up)
    vagrant up
    ;;

  *)
    echo "Usage: $0 {start|stop|ssh}"
    ;;
esac
```

### Source relative

```bash
source "${0%/*}/../share/foo.sh"
```

### printf

```bash
printf "Hello %s, I'm %s" Sven Olga
#=> "Hello Sven, I'm Olga

printf "1 + 1 = %d" 2
#=> "1 + 1 = 2"

printf "This is how you print a float: %f" 2
#=> "This is how you print a float: 2.000000"

printf '%s\n' '#!/bin/bash' 'echo hello' >file
# format string is applied to each group of arguments
printf '%i+%i=%i\n' 1 2 3  4 5 9
```

### Transform strings

| Command option | Description                                         |
| -------------- | --------------------------------------------------- |
| `-c`           | Operations apply to characters not in the given set |
| `-d`           | Delete characters                                   |
| `-s`           | Replaces repeated characters with single occurrence |
| `-t`           | Truncates                                           |
| `[:upper:]`    | All upper case letters                              |
| `[:lower:]`    | All lower case letters                              |
| `[:digit:]`    | All digits                                          |
| `[:space:]`    | All whitespace                                      |
| `[:alpha:]`    | All letters                                         |
| `[:alnum:]`    | All letters and digits                              |

#### Example

```bash
echo "Welcome To Devhints" | tr '[:lower:]' '[:upper:]'
WELCOME TO DEVHINTS
```

### Directory of script

```bash
dir=${0%/*}
```

### Getting options

```bash
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
  -V | --version )
    echo "$version"
    exit
    ;;
  -s | --string )
    shift; string=$1
    ;;
  -f | --flag )
    flag=1
    ;;
esac; shift; done
if [[ "$1" == '--' ]]; then shift; fi
```

### Heredoc

```sh
cat <<END
hello world
END
```

Heredoc allows a section of your source code to be treated as a file. See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Documents).

### Herestring

```sh
tr '[:lower:]' '[:upper:]' <<< "Will be uppercased, even $variable"
```

Herestring allows a string to be treated as a standard input (stdin). See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Strings).

### Process substitution

```sh 
# loop on myfunc output lines
while read -r line; do
  echo "$line"
done < <(myfunc)

# compare content of two folders
diff <(ls "$dir1") <(ls "$dir2")
```

Process substitution allows the input (or output) of a command to be treated as a file. See [Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html).

### Reading input

```bash
echo -n "Proceed? [y/n]: "
read -r ans
echo "$ans"
```

The `-r` option disables a peculiar legacy behavior with backslashes.

```bash
read -n 1 ans    # Just one character
```

### Special variables

| Expression         | Description                            |
| ------------------ | -------------------------------------- |
| `$?`               | Exit status of last task               |
| `$!`               | PID of last background task            |
| `$$`               | PID of shell                           |
| `$0`               | Filename of the shell script           |
| `$_`               | Last argument of the previous command  |
| `${PIPESTATUS[n]}` | return value of piped commands (array) |

See [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).

### Go to previous directory

```bash
pwd # /home/user/foo
cd bar/
pwd # /home/user/foo/bar
cd -
pwd # /home/user/foo
```

### Check for command's result

```bash
if ping -c 1 google.com; then
  echo "It appears you have a working internet connection"
fi
```

### Grep check

```bash
if grep -q 'foo' ~/.bash_history; then
  echo "You appear to have typed 'foo' in the past"
fi
```

## Also see
{: .-one-column}

- [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_
- [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_
- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_
- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_
- [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_


id: backbone
git_filename: ./backbone.md
format: md
field_title: Backbone.js
field_category: JavaScript libraries
field_updated: 2018-12-06
field_updated___timezone: UTC
data:
{"title": "Backbone.js", "updated": "2018-12-06", "category": "JavaScript libraries", "body": "### Binding events\n\n```js\n.on('event', callback)\n.on('event', callback, context)\n```\n\n```js\n.on({\n  'event1': callback,\n  'event2': callback\n})\n```\n\n```js\n.on('all', callback)\n```\n\n```js\n.once('event', callback)   // Only happens once\n```\n\n### Unbinding events\n\n```js\nobject.off('change', onChange)    // just the `onChange` callback\nobject.off('change')              // all 'change' callbacks\nobject.off(null, onChange)        // `onChange` callback for all events\nobject.off(null, null, context)   // all callbacks for `context` all events\nobject.off()                      // all\n```\n\n### Events\n\n```js\nobject.trigger('event')\n```\n\n```js\nview.listenTo(object, event, callback)\nview.stopListening()\n```\n\n### List of events\n\n  * Collection:\n    * `add` (model, collection, options)\n    * `remove` (model, collection, options)\n    * `reset` (collection, options)\n    * `sort` (collection, options)\n\n  * Model:\n    * `change` (model, options)\n    * `change:[attr]` (model, value, options)\n    * `destroy` (model, collection, options)\n    * `error` (model, xhr, options)\n\n  * Model and collection:\n    * `request` (model, xhr, options)\n    * `sync` (model, resp, options)\n\n  * Router:\n    * `route:[name]` (params)\n    * `route` (router, route, params)\n\n## Views\n\n### Defining\n\n```js\n// All attributes are optional\nvar View = Backbone.View.extend({\n  model: doc,\n```\n\n```js\n  tagName: 'div',\n  className: 'document-item',\n  id: \"document-\" + doc.id,\n  attributes: { href: '#' },\n```\n\n```js\n  el: 'body',\n```\n\n```js\n  events: {\n    'click button.save': 'save',\n    'click .cancel': function() { \u00b7\u00b7\u00b7 },\n    'click': 'onclick'\n  },\n```\n\n```js\n  constructor: function() { \u00b7\u00b7\u00b7 },\n  render: function() { \u00b7\u00b7\u00b7 }\n})\n```\n### Instantiating\n\n```js\nview = new View()\nview = new View({ el: \u00b7\u00b7\u00b7 })\n```\n\n### Methods\n\n```js\nview.$el.show()\nview.$('input')\n```\n\n```js\nview.remove()\n```\n\n```js\nview.delegateEvents()\nview.undelegateEvents()\n```\n\n## Models\n\n### Defining\n\n```js\n// All attributes are optional\nvar Model = Backbone.Model.extend({\n  defaults: {\n    'author': 'unknown'\n  },\n  idAttribute: '_id',\n  parse: function() { \u00b7\u00b7\u00b7 }\n})\n```\n\n### Instantiating\n\n```js\nvar obj = new Model({ title: 'Lolita', author: 'Nabokov' })\n```\n\n```js\nvar obj = new Model({ collection: \u00b7\u00b7\u00b7 })\n```\n\n### Methods\n\n```js\nobj.id\nobj.cid   // \u2192 'c38' (client-side ID)\n```\n\n```js\nobj.clone()\n```\n\n```js\nobj.hasChanged('title')\nobj.changedAttributes()  // false, or hash\nobj.previousAttributes() // false, or hash\nobj.previous('title')\n```\n\n```js\nobj.isNew()\n```\n\n```js\nobj.set({ title: 'A Study in Pink' })\nobj.set({ title: 'A Study in Pink' }, { validate: true, silent: true })\nobj.unset('title')\n```\n\n```js\nobj.get('title')\nobj.has('title')\nobj.escape('title')     /* Like .get() but HTML-escaped */\n```\n\n```js\nobj.clear()\nobj.clear({ silent: true })\n```\n\n```js\nobj.save()\nobj.save({ attributes })\nobj.save(null, {\n  silent: true, patch: true, wait: true,\n  success: callback, error: callback\n})\n```\n\n```js\nobj.destroy()\nobj.destroy({\n  wait: true,\n  success: callback, error: callback\n})\n```\n\n```js\nobj.toJSON()\n```\n\n```js\nobj.fetch()\nobj.fetch({ success: callback, error: callback })\n```\n\n### Validation\n\n```js\nvar Model = Backbone.Model.extend({\n  validate: function(attrs, options) {\n    if (attrs.end < attrs.start) {\n      return \"Can't end before it starts\"\n    }\n  }\n})\n```\n{: data-line=\"2\"}\n\n```js\nobj.validationError  //=> \"Can't end before it starts\"\nobj.isValid()\nobj.on('invalid', function (model, error) { \u00b7\u00b7\u00b7 })\n```\n\n```js\n// Triggered on:\nobj.save()\nobj.set({ \u00b7\u00b7\u00b7 }, { validate: true })\n```\n\n### Custom URLs\n\n```js\nvar Model = Backbone.Model.extend({\n  // Single URL (string or function)\n  url: '/account',\n  url: function() { return '/account' },\n```\n\n```js\n  // Both of these two work the same way\n  url: function() { return '/books/' + this.id }),\n  urlRoot: '/books'\n})\n```\n\n```js\nvar obj = new Model({ url: \u00b7\u00b7\u00b7 })\nvar obj = new Model({ urlRoot: \u00b7\u00b7\u00b7 })\n```\n\n## References\n{: .-one-column}\n\n- [Backbone website](http://backbonejs.org/) _(backbonejs.org)_\n- [Backbone patterns](http://ricostacruz.com/backbone-patterns/) _(ricostacruz.com)_"}

field_body:
### Binding events

```js
.on('event', callback)
.on('event', callback, context)
```

```js
.on({
  'event1': callback,
  'event2': callback
})
```

```js
.on('all', callback)
```

```js
.once('event', callback)   // Only happens once
```

### Unbinding events

```js
object.off('change', onChange)    // just the `onChange` callback
object.off('change')              // all 'change' callbacks
object.off(null, onChange)        // `onChange` callback for all events
object.off(null, null, context)   // all callbacks for `context` all events
object.off()                      // all
```

### Events

```js
object.trigger('event')
```

```js
view.listenTo(object, event, callback)
view.stopListening()
```

### List of events

  * Collection:
    * `add` (model, collection, options)
    * `remove` (model, collection, options)
    * `reset` (collection, options)
    * `sort` (collection, options)

  * Model:
    * `change` (model, options)
    * `change:[attr]` (model, value, options)
    * `destroy` (model, collection, options)
    * `error` (model, xhr, options)

  * Model and collection:
    * `request` (model, xhr, options)
    * `sync` (model, resp, options)

  * Router:
    * `route:[name]` (params)
    * `route` (router, route, params)

## Views

### Defining

```js
// All attributes are optional
var View = Backbone.View.extend({
  model: doc,
```

```js
  tagName: 'div',
  className: 'document-item',
  id: "document-" + doc.id,
  attributes: { href: '#' },
```

```js
  el: 'body',
```

```js
  events: {
    'click button.save': 'save',
    'click .cancel': function() { ··· },
    'click': 'onclick'
  },
```

```js
  constructor: function() { ··· },
  render: function() { ··· }
})
```
### Instantiating

```js
view = new View()
view = new View({ el: ··· })
```

### Methods

```js
view.$el.show()
view.$('input')
```

```js
view.remove()
```

```js
view.delegateEvents()
view.undelegateEvents()
```

## Models

### Defining

```js
// All attributes are optional
var Model = Backbone.Model.extend({
  defaults: {
    'author': 'unknown'
  },
  idAttribute: '_id',
  parse: function() { ··· }
})
```

### Instantiating

```js
var obj = new Model({ title: 'Lolita', author: 'Nabokov' })
```

```js
var obj = new Model({ collection: ··· })
```

### Methods

```js
obj.id
obj.cid   // → 'c38' (client-side ID)
```

```js
obj.clone()
```

```js
obj.hasChanged('title')
obj.changedAttributes()  // false, or hash
obj.previousAttributes() // false, or hash
obj.previous('title')
```

```js
obj.isNew()
```

```js
obj.set({ title: 'A Study in Pink' })
obj.set({ title: 'A Study in Pink' }, { validate: true, silent: true })
obj.unset('title')
```

```js
obj.get('title')
obj.has('title')
obj.escape('title')     /* Like .get() but HTML-escaped */
```

```js
obj.clear()
obj.clear({ silent: true })
```

```js
obj.save()
obj.save({ attributes })
obj.save(null, {
  silent: true, patch: true, wait: true,
  success: callback, error: callback
})
```

```js
obj.destroy()
obj.destroy({
  wait: true,
  success: callback, error: callback
})
```

```js
obj.toJSON()
```

```js
obj.fetch()
obj.fetch({ success: callback, error: callback })
```

### Validation

```js
var Model = Backbone.Model.extend({
  validate: function(attrs, options) {
    if (attrs.end < attrs.start) {
      return "Can't end before it starts"
    }
  }
})
```
{: data-line="2"}

```js
obj.validationError  //=> "Can't end before it starts"
obj.isValid()
obj.on('invalid', function (model, error) { ··· })
```

```js
// Triggered on:
obj.save()
obj.set({ ··· }, { validate: true })
```

### Custom URLs

```js
var Model = Backbone.Model.extend({
  // Single URL (string or function)
  url: '/account',
  url: function() { return '/account' },
```

```js
  // Both of these two work the same way
  url: function() { return '/books/' + this.id }),
  urlRoot: '/books'
})
```

```js
var obj = new Model({ url: ··· })
var obj = new Model({ urlRoot: ··· })
```

## References
{: .-one-column}

- [Backbone website](http://backbonejs.org/) _(backbonejs.org)_
- [Backbone patterns](http://ricostacruz.com/backbone-patterns/) _(ricostacruz.com)_


id: awscli
git_filename: ./awscli.md
format: md
field_title: AWS CLI
field_category: Devops
data:
{"title": "AWS CLI", "category": "Devops", "body": "### EC2\n\n```\naws ec2 describe-instances\naws ec2 start-instances --instance-ids i-12345678c\naws ec2 terminate-instances --instance-ids i-12345678c\n```\n\n### S3\n\n```\naws s3 ls s3://mybucket\naws s3 rm s3://mybucket/folder --recursive\naws s3 cp myfolder s3://mybucket/folder --recursive\naws s3 sync myfolder s3://mybucket/folder --exclude *.tmp\n```\n\n### ECS\n\n```\naws ecs create-cluster\n  --cluster-name=NAME\n  --generate-cli-skeleton\n\naws ecs create-service\n```\n\n### Homebrew\n\n```\nbrew install awscli\naws configure\n```\n\n### Configuration profiles\n\n```\naws configure --profile project1\naws configure --profile project2\n```\n\n## Elastic Beanstalk\n\n### Configuration\n\n* .elasticbeanstalk/config.yml - application config\n* .elasticbeanstalk/dev-env.env.yml - environment config\n\n```\neb config\n```\n\nSee: <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options.html>\n\n## ebextensions\n\n* <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html>\n* <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html>\n\n## Also see\n\n* [AWS CLI](https://aws.amazon.com/cli/)\n* [Documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)\n* [All commands](https://docs.aws.amazon.com/cli/latest/reference/#available-services)"}

field_body:
### EC2

```
aws ec2 describe-instances
aws ec2 start-instances --instance-ids i-12345678c
aws ec2 terminate-instances --instance-ids i-12345678c
```

### S3

```
aws s3 ls s3://mybucket
aws s3 rm s3://mybucket/folder --recursive
aws s3 cp myfolder s3://mybucket/folder --recursive
aws s3 sync myfolder s3://mybucket/folder --exclude *.tmp
```

### ECS

```
aws ecs create-cluster
  --cluster-name=NAME
  --generate-cli-skeleton

aws ecs create-service
```

### Homebrew

```
brew install awscli
aws configure
```

### Configuration profiles

```
aws configure --profile project1
aws configure --profile project2
```

## Elastic Beanstalk

### Configuration

* .elasticbeanstalk/config.yml - application config
* .elasticbeanstalk/dev-env.env.yml - environment config

```
eb config
```

See: <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options.html>

## ebextensions

* <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html>
* <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html>

## Also see

* [AWS CLI](https://aws.amazon.com/cli/)
* [Documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)
* [All commands](https://docs.aws.amazon.com/cli/latest/reference/#available-services)


id: awesome-redux
git_filename: ./awesome-redux.md
format: md
field_title: Awesome Redux
field_category: React
field_updated: 2017-11-19
field_updated___timezone: UTC
data:
{"title": "Awesome Redux", "category": "React", "updated": "2017-11-19", "body": "### redux-actions\n\nCreate action creators in flux standard action format.\n{: .-setup}\n\n```js\nincrement = createAction('INCREMENT', amount => amount)\nincrement = createAction('INCREMENT')  // same\n```\n\n```js\nincrement(42) === { type: 'INCREMENT', payload: 42 }\n```\n\n```js\n// Errors are handled for you:\nerr = new Error()\nincrement(err) === { type: 'INCREMENT', payload: err, error: true }\n```\n\n[redux-actions](https://www.npmjs.com/package/redux-actions)\n{: .-crosslink}\n\n### flux-standard-action\n\nA standard for flux action objects. An action may have an `error`, `payload` and `meta` and nothing else.\n{: .-setup}\n\n```js\n{ type: 'ADD_TODO', payload: { text: 'Work it' } }\n{ type: 'ADD_TODO', payload: new Error(), error: true }\n```\n\n[flux-standard-action](https://github.com/acdlite/flux-standard-action)\n{: .-crosslink}\n\n### redux-multi\n\nDispatch multiple actions in one action creator.\n{: .-setup}\n\n```js\nstore.dispatch([\n  { type: 'INCREMENT', payload: 2 },\n  { type: 'INCREMENT', payload: 3 }\n])\n```\n\n[redux-multi](https://github.com/ashaffer/redux-multi)\n{: .-crosslink}\n\n### reduce-reducers\nCombines reducers (like *combineReducers()*), but without namespacing magic.\n{: .-setup}\n\n```js\nre = reduceReducers(\n  (state, action) => state + action.number,\n  (state, action) => state + action.number\n)\n\nre(10, { number: 2 })  //=> 14\n```\n\n[reduce-reducers](https://www.npmjs.com/package/reduce-reducers)\n{: .-crosslink}\n\n### redux-logger\n\nLogs actions to your console.\n{: .-setup}\n\n```js\n// Nothing to see here\n```\n\n[redux-logger](https://github.com/evgenyrodionov/redux-logger)\n{: .-crosslink}\n\nAsync\n-----\n\n### redux-promise\n\nPass promises to actions. Dispatches a flux-standard-action.\n{: .-setup}\n\n```js\nincrement = createAction('INCREMENT')  // redux-actions\nincrement(Promise.resolve(42))\n```\n\n[redux-promise](https://github.com/acdlite/redux-promise)\n{: .-crosslink}\n\n### redux-promises\n\nSorta like that, too. Works by letting you pass *thunks* (functions) to `dispatch()`. Also has 'idle checking'.\n{: .-setup}\n\n```js\nfetchData = (url) => (dispatch) => {\n  dispatch({ type: 'FETCH_REQUEST' })\n  fetch(url)\n    .then((data) => dispatch({ type: 'FETCH_DONE', data })\n    .catch((error) => dispatch({ type: 'FETCH_ERROR', error })\n})\n\nstore.dispatch(fetchData('/posts'))\n```\n\n```js\n// That's actually shorthand for:\nfetchData('/posts')(store.dispatch)\n```\n\n[redux-promises](https://www.npmjs.com/package/redux-promises)\n{: .-crosslink}\n\n### redux-effects\n\nPass side effects declaratively to keep your actions pure.\n{: .-setup}\n\n```js\n{\n  type: 'EFFECT_COMPOSE',\n  payload: {\n    type: 'FETCH'\n    payload: {url: '/some/thing', method: 'GET'}\n  },\n  meta: {\n    steps: [ [success, failure] ]\n  }\n}\n```\n\n[redux-effects](https://www.npmjs.com/package/redux-effects)\n{: .-crosslink}\n\n### redux-thunk\n\nPass \"thunks\" to as actions. Extremely similar to redux-promises, but has support for getState.\n{: .-setup}\n\n```js\nfetchData = (url) => (dispatch, getState) => {\n  dispatch({ type: 'FETCH_REQUEST' })\n  fetch(url)\n    .then((data) => dispatch({ type: 'FETCH_DONE', data })\n    .catch((error) => dispatch({ type: 'FETCH_ERROR', error })\n})\n\nstore.dispatch(fetchData('/posts'))\n```\n\n```js\n// That's actually shorthand for:\nfetchData('/posts')(store.dispatch, store.getState)\n```\n\n```js\n// Optional: since fetchData returns a promise, it can be chained\n// for server-side rendering\nstore.dispatch(fetchPosts()).then(() => {\n  ReactDOMServer.renderToString(<MyApp store={store} />)\n})\n```\n\n[redux-thunk](https://www.npmjs.com/package/redux-thunk)\n{: .-crosslink}"}

field_body:
### redux-actions

Create action creators in flux standard action format.
{: .-setup}

```js
increment = createAction('INCREMENT', amount => amount)
increment = createAction('INCREMENT')  // same
```

```js
increment(42) === { type: 'INCREMENT', payload: 42 }
```

```js
// Errors are handled for you:
err = new Error()
increment(err) === { type: 'INCREMENT', payload: err, error: true }
```

[redux-actions](https://www.npmjs.com/package/redux-actions)
{: .-crosslink}

### flux-standard-action

A standard for flux action objects. An action may have an `error`, `payload` and `meta` and nothing else.
{: .-setup}

```js
{ type: 'ADD_TODO', payload: { text: 'Work it' } }
{ type: 'ADD_TODO', payload: new Error(), error: true }
```

[flux-standard-action](https://github.com/acdlite/flux-standard-action)
{: .-crosslink}

### redux-multi

Dispatch multiple actions in one action creator.
{: .-setup}

```js
store.dispatch([
  { type: 'INCREMENT', payload: 2 },
  { type: 'INCREMENT', payload: 3 }
])
```

[redux-multi](https://github.com/ashaffer/redux-multi)
{: .-crosslink}

### reduce-reducers
Combines reducers (like *combineReducers()*), but without namespacing magic.
{: .-setup}

```js
re = reduceReducers(
  (state, action) => state + action.number,
  (state, action) => state + action.number
)

re(10, { number: 2 })  //=> 14
```

[reduce-reducers](https://www.npmjs.com/package/reduce-reducers)
{: .-crosslink}

### redux-logger

Logs actions to your console.
{: .-setup}

```js
// Nothing to see here
```

[redux-logger](https://github.com/evgenyrodionov/redux-logger)
{: .-crosslink}

Async
-----

### redux-promise

Pass promises to actions. Dispatches a flux-standard-action.
{: .-setup}

```js
increment = createAction('INCREMENT')  // redux-actions
increment(Promise.resolve(42))
```

[redux-promise](https://github.com/acdlite/redux-promise)
{: .-crosslink}

### redux-promises

Sorta like that, too. Works by letting you pass *thunks* (functions) to `dispatch()`. Also has 'idle checking'.
{: .-setup}

```js
fetchData = (url) => (dispatch) => {
  dispatch({ type: 'FETCH_REQUEST' })
  fetch(url)
    .then((data) => dispatch({ type: 'FETCH_DONE', data })
    .catch((error) => dispatch({ type: 'FETCH_ERROR', error })
})

store.dispatch(fetchData('/posts'))
```

```js
// That's actually shorthand for:
fetchData('/posts')(store.dispatch)
```

[redux-promises](https://www.npmjs.com/package/redux-promises)
{: .-crosslink}

### redux-effects

Pass side effects declaratively to keep your actions pure.
{: .-setup}

```js
{
  type: 'EFFECT_COMPOSE',
  payload: {
    type: 'FETCH'
    payload: {url: '/some/thing', method: 'GET'}
  },
  meta: {
    steps: [ [success, failure] ]
  }
}
```

[redux-effects](https://www.npmjs.com/package/redux-effects)
{: .-crosslink}

### redux-thunk

Pass "thunks" to as actions. Extremely similar to redux-promises, but has support for getState.
{: .-setup}

```js
fetchData = (url) => (dispatch, getState) => {
  dispatch({ type: 'FETCH_REQUEST' })
  fetch(url)
    .then((data) => dispatch({ type: 'FETCH_DONE', data })
    .catch((error) => dispatch({ type: 'FETCH_ERROR', error })
})

store.dispatch(fetchData('/posts'))
```

```js
// That's actually shorthand for:
fetchData('/posts')(store.dispatch, store.getState)
```

```js
// Optional: since fetchData returns a promise, it can be chained
// for server-side rendering
store.dispatch(fetchPosts()).then(() => {
  ReactDOMServer.renderToString(<MyApp store={store} />)
})
```

[redux-thunk](https://www.npmjs.com/package/redux-thunk)
{: .-crosslink}


id: atom
git_filename: ./atom.md
format: md
field_title: Atom
field_category: Apps
field_updated: 2021-09-10
field_updated___timezone: UTC
data:
{"title": "Atom", "category": "Apps", "updated": "2021-09-10", "body": "## Shortcuts\n{: .-three-column}\n\n### Tree\n\n| Shortcut | Description         |\n| -------- | ------------------- |\n| `\u2318\\`     | Toggle tree         |\n| `\u2318\u21e7\\`    | Reveal current file |\n{: .-shortcuts}\n\n### Comments\n\n| Shortcut | Description     |\n| -------- | --------------- |\n| `\u2318/`     | Toggle comments |\n{: .-shortcuts}\n\n### View\n\n| Shortcut             | Description                                     |\n| --------             | ----------------------                          |\n| `\u2318k` `\u2190,\u2192,\u2191,\u2193`       | Split pane to the left, right, up, or down      |\n| ---                  | ---                                             |\n| `\u2318\u2325=`                | Grow pane                                       |\n| `\u2318\u2325-`                | Shrink pane                                     |\n| ---                  | ---                                             |\n| `^\u21e7\u2190`/`^\u21e7\u2192`          | Move tab to left/right                          |\n{: .-shortcuts}\n\n### Bracket matcher\n\n| Shortcut | Description                    |\n| -------- | ------------------------------ |\n| `^m`     | Go to matching bracket         |\n| `^\u232b`     | Remove brackets from selection |\n| `^\u2318m`    | Select inside brackets         |\n| `\u2325\u2318.`    | Close tag                      |\n{: .-shortcuts}\n\n### Symbols view\n\n| Shortcut | Description                      |\n| -------- | -------------------------------- |\n| `\u2325\u2318\u2193`    | Jump to declaration under cursor |\n| `^\u21e7r`    | Show tags                        |\n{: .-shortcuts}\n\nSymbols view enables Ctags support for Atom.\n\nSee: [Symbols view](https://atom.io/packages/symbols-view)\n\n### Git\n\n| Shortcut | Description                    |\n| -------- | ------------------------------ |\n| `^\u21e79` | Show Git pane |\n| `^\u21e78` | Show GitHub pane |\n{: .-shortcuts}\n\n### Editing\n\n| Shortcut | Description    |\n| -------- | -------------- |\n| `\u2318d`     | Select word    |\n| `\u2318l`     | Select line    |\n| ---      | ---            |\n| `^\u2318\u2191`     | Move line up   |\n| `^\u2318\u2193`     | Move line down |\n| ---      | ---            |\n| `\u2318\u23ce`     | New line below |\n| `\u2318\u21e7\u23ce`    | New line above |\n| ---      | ---            |\n| `^\u21e7k`    | Delete line    |\n| `\u2318\u21e7d`    | Duplicate line |\n{: .-shortcuts}\n\n### Project\n\n| Shortcut | Description             |\n| -------- | ----------------------- |\n| `\u2318\u21e7p`    | Command palette         |\n| `\u2318\u21e7o`    | Add project folder      |\n| ---      | ---                     |\n| `\u2318n`     | New file                |\n| `\u2318\u21e7n`    | New window              |\n| ---      | ---                     |\n| `\u2318f`     | Find in file            |\n| `\u2318\u21e7f`    | Find in project         |\n| `\u2318t`     | Search files in project |\n{: .-shortcuts}\n\n## Notes\n\n### \u2318\n\n- For Windows and Linux, `\u2318` is the `Control` key.\n- For macOS, it's the `Command` key.\n\n### \u2325\n\n- For Windows and Linux, `\u2325` is the `Alt` key.\n- For macOS, it's the `Option` key."}

field_body:
## Shortcuts
{: .-three-column}

### Tree

| Shortcut | Description         |
| -------- | ------------------- |
| `⌘\`     | Toggle tree         |
| `⌘⇧\`    | Reveal current file |
{: .-shortcuts}

### Comments

| Shortcut | Description     |
| -------- | --------------- |
| `⌘/`     | Toggle comments |
{: .-shortcuts}

### View

| Shortcut             | Description                                     |
| --------             | ----------------------                          |
| `⌘k` `←,→,↑,↓`       | Split pane to the left, right, up, or down      |
| ---                  | ---                                             |
| `⌘⌥=`                | Grow pane                                       |
| `⌘⌥-`                | Shrink pane                                     |
| ---                  | ---                                             |
| `^⇧←`/`^⇧→`          | Move tab to left/right                          |
{: .-shortcuts}

### Bracket matcher

| Shortcut | Description                    |
| -------- | ------------------------------ |
| `^m`     | Go to matching bracket         |
| `^⌫`     | Remove brackets from selection |
| `^⌘m`    | Select inside brackets         |
| `⌥⌘.`    | Close tag                      |
{: .-shortcuts}

### Symbols view

| Shortcut | Description                      |
| -------- | -------------------------------- |
| `⌥⌘↓`    | Jump to declaration under cursor |
| `^⇧r`    | Show tags                        |
{: .-shortcuts}

Symbols view enables Ctags support for Atom.

See: [Symbols view](https://atom.io/packages/symbols-view)

### Git

| Shortcut | Description                    |
| -------- | ------------------------------ |
| `^⇧9` | Show Git pane |
| `^⇧8` | Show GitHub pane |
{: .-shortcuts}

### Editing

| Shortcut | Description    |
| -------- | -------------- |
| `⌘d`     | Select word    |
| `⌘l`     | Select line    |
| ---      | ---            |
| `^⌘↑`     | Move line up   |
| `^⌘↓`     | Move line down |
| ---      | ---            |
| `⌘⏎`     | New line below |
| `⌘⇧⏎`    | New line above |
| ---      | ---            |
| `^⇧k`    | Delete line    |
| `⌘⇧d`    | Duplicate line |
{: .-shortcuts}

### Project

| Shortcut | Description             |
| -------- | ----------------------- |
| `⌘⇧p`    | Command palette         |
| `⌘⇧o`    | Add project folder      |
| ---      | ---                     |
| `⌘n`     | New file                |
| `⌘⇧n`    | New window              |
| ---      | ---                     |
| `⌘f`     | Find in file            |
| `⌘⇧f`    | Find in project         |
| `⌘t`     | Search files in project |
{: .-shortcuts}

## Notes

### ⌘

- For Windows and Linux, `⌘` is the `Control` key.
- For macOS, it's the `Command` key.

### ⌥

- For Windows and Linux, `⌥` is the `Alt` key.
- For macOS, it's the `Option` key.


id: arel
git_filename: ./arel.md
format: md
field_title: Arel
field_category: Rails
data:
{"title": "Arel", "category": "Rails", "body": "### About\n{: .-intro}\n\nArel is an SQL abstraction library built into Ruby on Rails.\n\n* <https://github.com/rails/arel>\n\n### Tables\n\n```rb\nusers = Arel::Table.new(:users)\nusers = User.arel_table  # ActiveRecord model\n```\n\n### Fields\n\n```rb\nusers[:name]\nusers[:id]\n```\n\n### `where` (restriction)\n\n```rb\nusers.where(users[:name].eq('amy'))\n# SELECT * FROM users WHERE users.name = 'amy'\n```\n\n### `select` (projection)\n\n```rb\nusers.project(users[:id])\n# SELECT users.id FROM users\n```\n\n### `join`\n#### basic join\nIn ActiveRecord (without Arel), if `:photos` is the name of the association, use `joins`\n```rb\nusers.joins(:photos)\n```\n\nIn Arel, if `photos` is defined as the Arel table,\n```rb\nphotos = Photo.arel_table\nusers.join(photos) \nusers.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id]))\n```\n\n#### join with conditions\n```rb\nusers.joins(:photos).merge(Photo.where(published: true))\n```\n\nIf the simpler version doesn't help and you want to add more SQL statements to it:\n```rb\nusers.join(\n   users.join(photos, Arel::Nodes::OuterJoin)\n   .on(photos[:user_id].eq(users[:id]).and(photos[:published].eq(true)))\n)\n```\n\n#### advanced join\nmultiple `joins` with the same table but different meanings and/or conditions\n```rb\ncreators = User.arel_table.alias('creators')\nupdaters = User.arel_table.alias('updaters')\nphotos = Photo.arel_table\n\nphotos_with_credits = photos\n.join(photos.join(creators, Arel::Nodes::OuterJoin).on(photos[:created_by_id].eq(creators[:id])))\n.join(photos.join(updaters, Arel::Nodes::OuterJoin).on(photos[:assigned_id].eq(updaters[:id])))\n.project(photos[:name], photos[:created_at], creators[:name].as('creator'), updaters[:name].as('editor'))\n\nphotos_with_credits.to_sql\n# => \"SELECT `photos`.`name`, `photos`.`created_at`, `creators`.`name` AS creator, `updaters`.`name` AS editor FROM `photos` INNER JOIN (SELECT FROM `photos` LEFT OUTER JOIN `users` `creators` ON `photos`.`created_by_id` = `creators`.`id`) INNER JOIN (SELECT FROM `photos` LEFT OUTER JOIN `users` `updaters` ON `photos`.`updated_by_id` = `updaters`.`id`)\"\n\n# after the request is done, you can use the attributes you named\n# it's as if every Photo record you got has \"creator\" and \"editor\" fields, containing creator name and editor name\nphotos_with_credits.map{|x|\n  \"#{photo.name} - copyright #{photo.created_at.year} #{photo.creator}, edited by #{photo.editor}\"\n}.join('; ')\n```\n\n### `limit` / `offset`\n\n```rb\nusers.take(5) # => SELECT * FROM users LIMIT 5\nusers.skip(4) # => SELECT * FROM users OFFSET 4\n```\n\n### Aggregates\n\n```rb\nusers.project(users[:age].sum) # .average .minimum .maximum\nusers.project(users[:id].count)\nusers.project(users[:id].count.as('user_count'))\n```\n\n### `order`\n\n```rb\nusers.order(users[:name])\nusers.order(users[:name], users[:age].desc)\nusers.reorder(users[:age])\n```\n\n### With ActiveRecord\n\n```rb\nUser.arel_table\nUser.where(id: 1).arel\n```\n\n### Clean code with arel\n\nMost of the clever stuff should be in scopes, e.g. the code above could become:\n```rb\nphotos_with_credits = Photo.with_creator.with_editor\n```\n\nYou can store requests in variables then add SQL segments:\n```rb\nall_time      = photos_with_credits.count\nthis_month    = photos_with_credits.where(photos[:created_at].gteq(Date.today.beginning_of_month))\nrecent_photos = photos_with_credits.where(photos[:created_at].gteq(Date.today.beginning_of_month)).limit(5)\n```"}

field_body:
### About
{: .-intro}

Arel is an SQL abstraction library built into Ruby on Rails.

* <https://github.com/rails/arel>

### Tables

```rb
users = Arel::Table.new(:users)
users = User.arel_table  # ActiveRecord model
```

### Fields

```rb
users[:name]
users[:id]
```

### `where` (restriction)

```rb
users.where(users[:name].eq('amy'))
# SELECT * FROM users WHERE users.name = 'amy'
```

### `select` (projection)

```rb
users.project(users[:id])
# SELECT users.id FROM users
```

### `join`
#### basic join
In ActiveRecord (without Arel), if `:photos` is the name of the association, use `joins`
```rb
users.joins(:photos)
```

In Arel, if `photos` is defined as the Arel table,
```rb
photos = Photo.arel_table
users.join(photos) 
users.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id]))
```

#### join with conditions
```rb
users.joins(:photos).merge(Photo.where(published: true))
```

If the simpler version doesn't help and you want to add more SQL statements to it:
```rb
users.join(
   users.join(photos, Arel::Nodes::OuterJoin)
   .on(photos[:user_id].eq(users[:id]).and(photos[:published].eq(true)))
)
```

#### advanced join
multiple `joins` with the same table but different meanings and/or conditions
```rb
creators = User.arel_table.alias('creators')
updaters = User.arel_table.alias('updaters')
photos = Photo.arel_table

photos_with_credits = photos
.join(photos.join(creators, Arel::Nodes::OuterJoin).on(photos[:created_by_id].eq(creators[:id])))
.join(photos.join(updaters, Arel::Nodes::OuterJoin).on(photos[:assigned_id].eq(updaters[:id])))
.project(photos[:name], photos[:created_at], creators[:name].as('creator'), updaters[:name].as('editor'))

photos_with_credits.to_sql
# => "SELECT `photos`.`name`, `photos`.`created_at`, `creators`.`name` AS creator, `updaters`.`name` AS editor FROM `photos` INNER JOIN (SELECT FROM `photos` LEFT OUTER JOIN `users` `creators` ON `photos`.`created_by_id` = `creators`.`id`) INNER JOIN (SELECT FROM `photos` LEFT OUTER JOIN `users` `updaters` ON `photos`.`updated_by_id` = `updaters`.`id`)"

# after the request is done, you can use the attributes you named
# it's as if every Photo record you got has "creator" and "editor" fields, containing creator name and editor name
photos_with_credits.map{|x|
  "#{photo.name} - copyright #{photo.created_at.year} #{photo.creator}, edited by #{photo.editor}"
}.join('; ')
```

### `limit` / `offset`

```rb
users.take(5) # => SELECT * FROM users LIMIT 5
users.skip(4) # => SELECT * FROM users OFFSET 4
```

### Aggregates

```rb
users.project(users[:age].sum) # .average .minimum .maximum
users.project(users[:id].count)
users.project(users[:id].count.as('user_count'))
```

### `order`

```rb
users.order(users[:name])
users.order(users[:name], users[:age].desc)
users.reorder(users[:age])
```

### With ActiveRecord

```rb
User.arel_table
User.where(id: 1).arel
```

### Clean code with arel

Most of the clever stuff should be in scopes, e.g. the code above could become:
```rb
photos_with_credits = Photo.with_creator.with_editor
```

You can store requests in variables then add SQL segments:
```rb
all_time      = photos_with_credits.count
this_month    = photos_with_credits.where(photos[:created_at].gteq(Date.today.beginning_of_month))
recent_photos = photos_with_credits.where(photos[:created_at].gteq(Date.today.beginning_of_month)).limit(5)
```


id: applinks
git_filename: ./applinks.md
format: md
field_title: Applinks
field_category: HTML
data:
{"title": "Applinks", "category": "HTML", "body": "### About\n\n- <http://applinks.org/>\n\n### Applinks\n\n    <meta property=\"al:ios:url\" content=\"applinks://docs\" />\n    <meta property=\"al:ios:app_store_id\" content=\"12345\" />\n    <meta property=\"al:ios:app_name\" content=\"App Links\" />\n\n    <meta property=\"al:android:url\" content=\"applinks://docs\" />\n    <meta property=\"al:android:app_name\" content=\"App Links\" />\n    <meta property=\"al:android:package\" content=\"org.applinks\" />\n\n    <meta property=\"al:web:url\" content=\"http://applinks.org/documentation\" />\n\n### Device types\n\n * `ios`\n * `ipad`\n * `iphone`\n * `android`\n * `windows_phone`\n * `web`\n\n### Reference\n\n * [applinks.org](http://applinks.org/documentation/)"}

field_body:
### About

- <http://applinks.org/>

### Applinks

    <meta property="al:ios:url" content="applinks://docs" />
    <meta property="al:ios:app_store_id" content="12345" />
    <meta property="al:ios:app_name" content="App Links" />

    <meta property="al:android:url" content="applinks://docs" />
    <meta property="al:android:app_name" content="App Links" />
    <meta property="al:android:package" content="org.applinks" />

    <meta property="al:web:url" content="http://applinks.org/documentation" />

### Device types

 * `ios`
 * `ipad`
 * `iphone`
 * `android`
 * `windows_phone`
 * `web`

### Reference

 * [applinks.org](http://applinks.org/documentation/)


id: applescript
git_filename: ./applescript.md
format: md
field_title: AppleScript
field_category: macOS
field_prism_languages: applescript
field_updated: 2018-12-06
field_updated___timezone: UTC
data:
{"title": "AppleScript", "updated": "2018-12-06", "category": "macOS", "prism_languages": ["applescript"], "body": "### Running\n\n```applescript\nosascript -e \"...\"\n```\n\n```applescript\ndisplay notification \"X\" with title \"Y\"\n```\n\n### Comments\n\n```applescript\n-- This is a single line comment\n```\n\n```applescript\n# This is another single line comment\n```\n\n```applescript\n(*\nThis is\na multi\nline comment\n*)\n```\n\n### Say\n\n```applescript\n-- default voice\nsay \"Hi I am a Mac\"\n```\n\n```applescript\n-- specified voice\nsay \"Hi I am a Mac\" using \"Zarvox\"\n```\n\n### Beep\n\n```applescript\n-- beep once\nbeep\n```\n\n```applescript\n-- beep 10 times\nbeep 10\n```\n\n### Delay\n\n```applescript\n-- delay for 5 seconds\ndelay 5\n```\n\n### Handlers\n\n```applescript\non doubleNumber(n)\n\treturn n * 2\nend doubleNumber\n\nset doubledValue to my doubleNumber(2)\n```"}

field_body:
### Running

```applescript
osascript -e "..."
```

```applescript
display notification "X" with title "Y"
```

### Comments

```applescript
-- This is a single line comment
```

```applescript
# This is another single line comment
```

```applescript
(*
This is
a multi
line comment
*)
```

### Say

```applescript
-- default voice
say "Hi I am a Mac"
```

```applescript
-- specified voice
say "Hi I am a Mac" using "Zarvox"
```

### Beep

```applescript
-- beep once
beep
```

```applescript
-- beep 10 times
beep 10
```

### Delay

```applescript
-- delay for 5 seconds
delay 5
```

### Handlers

```applescript
on doubleNumber(n)
	return n * 2
end doubleNumber

set doubledValue to my doubleNumber(2)
```


id: appcache
git_filename: ./appcache.md
format: md
field_title: Appcache
field_category: HTML
data:
{"title": "Appcache", "category": "HTML", "body": "### Format\n\n```\nCACHE MANIFEST\n# version\n\nCACHE:\nhttps://www.google.com/jsapi\n/assets/app.js\n/assets/bg.png\n\nNETWORK:\n*\n```\n\nNote that Appcache is deprecated!\n\nSee: [Using the application cache](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache) _(developer.mozilla.org)_"}

field_body:
### Format

```
CACHE MANIFEST
# version

CACHE:
https://www.google.com/jsapi
/assets/app.js
/assets/bg.png

NETWORK:
*
```

Note that Appcache is deprecated!

See: [Using the application cache](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache) _(developer.mozilla.org)_


id: ansible
git_filename: ./ansible.md
format: md
field_title: Ansible
field_category: Ansible
data:
{"title": "Ansible", "category": "Ansible", "body": "{% raw %}\n\n## Getting started\n\n### About\n{: .-intro}\n\n- <https://www.ansible.com/>\n\n### Hosts\n\n    $ sudo mkdir /etc/ansible\n    $ sudo vim /etc/ansible/hosts\n\n    [example]\n    192.0.2.101\n    192.0.2.102\n\n### Running a playbook\n\n    $ ansible-playbook playbook.yml\n\n## Playbook files\n\n### Tasks\n\n    - hosts: all\n      user: root\n      sudo: no\n      vars:\n        aaa: bbb\n      tasks:\n        - ...\n      handlers:\n        - ...\n\n### Includes\n\n    tasks:\n      - include: db.yml\n    handlers:\n      - include: db.yml user=timmy\n\n### Handlers\n\n    handlers:\n      - name: start apache2\n        action: service name=apache2 state=started\n\n    tasks:\n      - name: install apache\n        action: apt pkg=apache2 state=latest\n        notify:\n          - start apache2\n\n### Vars\n\n    - host: lol\n      vars_files:\n        - vars.yml\n      vars:\n        project_root: /etc/xyz\n      tasks:\n        - name: Create the SSH directory.\n          file: state=directory path=${project_root}/home/.ssh/\n          only_if: \"$vm == 0\"\n\n### Roles\n\n    - host: xxx\n      roles:\n        - db\n        - { role:ruby, sudo_user:$user }\n        - web\n\n    # Uses:\n    # roles/db/tasks/*.yml\n    # roles/db/handlers/*.yml\n\n### Task: Failures\n\n    - name: my task\n      command: ...\n      register: result\n      failed_when: \"'FAILED' in result.stderr\"\n\n      ignore_errors: yes\n\n      changed_when: \"result.rc != 2\"\n\n### Env vars\n\n    vars:\n      local_home: \"{{ lookup('env','HOME') }}\"\n\n{% endraw %}"}

field_body:
{% raw %}

## Getting started

### About
{: .-intro}

- <https://www.ansible.com/>

### Hosts

    $ sudo mkdir /etc/ansible
    $ sudo vim /etc/ansible/hosts

    [example]
    192.0.2.101
    192.0.2.102

### Running a playbook

    $ ansible-playbook playbook.yml

## Playbook files

### Tasks

    - hosts: all
      user: root
      sudo: no
      vars:
        aaa: bbb
      tasks:
        - ...
      handlers:
        - ...

### Includes

    tasks:
      - include: db.yml
    handlers:
      - include: db.yml user=timmy

### Handlers

    handlers:
      - name: start apache2
        action: service name=apache2 state=started

    tasks:
      - name: install apache
        action: apt pkg=apache2 state=latest
        notify:
          - start apache2

### Vars

    - host: lol
      vars_files:
        - vars.yml
      vars:
        project_root: /etc/xyz
      tasks:
        - name: Create the SSH directory.
          file: state=directory path=${project_root}/home/.ssh/
          only_if: "$vm == 0"

### Roles

    - host: xxx
      roles:
        - db
        - { role:ruby, sudo_user:$user }
        - web

    # Uses:
    # roles/db/tasks/*.yml
    # roles/db/handlers/*.yml

### Task: Failures

    - name: my task
      command: ...
      register: result
      failed_when: "'FAILED' in result.stderr"

      ignore_errors: yes

      changed_when: "result.rc != 2"

### Env vars

    vars:
      local_home: "{{ lookup('env','HOME') }}"

{% endraw %}


id: ansible-roles
git_filename: ./ansible-roles.md
format: md
field_title: Ansible roles
field_category: Ansible
data:
{"title": "Ansible roles", "category": "Ansible", "body": "### Structure\n\n    roles/\n      common/\n        tasks/\n        handlers/\n        files/              # 'copy' will refer to this\n        templates/          # 'template' will refer to this\n        meta/               # Role dependencies here\n        vars/\n        defaults/\n          main.yml\n\n### References\n\n * http://www.ansibleworks.com/docs/playbooks_roles.html"}

field_body:
### Structure

    roles/
      common/
        tasks/
        handlers/
        files/              # 'copy' will refer to this
        templates/          # 'template' will refer to this
        meta/               # Role dependencies here
        vars/
        defaults/
          main.yml

### References

 * http://www.ansibleworks.com/docs/playbooks_roles.html


id: ansible-modules
git_filename: ./ansible-modules.md
format: md
field_title: Ansible modules
field_category: Ansible
field_prism_languages: yaml
field_updated: 2017-10-03
field_updated___timezone: UTC
data:
{"title": "Ansible modules", "category": "Ansible", "prism_languages": ["yaml"], "updated": "2017-10-03", "body": "{% raw %}\n\n## Format\n\n### Basic file\n\n```yaml\n---\n- hosts: production\n  remote_user: root\n  tasks:\n  - \u00b7\u00b7\u00b7\n```\n\nPlace your modules inside `tasks`.\n\n### Task formats\n\n#### One-line\n\n```yaml\n- apt: pkg=vim state=present\n```\n\n#### Map\n\n```yaml\n- apt:\n    pkg: vim\n    state: present\n```\n\n#### Foldable scalar\n\n```yaml\n- apt: >\n    pkg=vim\n    state=present\n```\n\nDefine your tasks in any of these formats. One-line format is preferred for short declarations, while maps are preferred for longer.\n\n## Modules\n\n### Aptitude\n\n#### Packages\n\n```yaml\n- apt:\n    pkg: nodejs\n    state: present # absent | latest\n    update_cache: yes\n    force: no\n```\n\n#### Deb files\n\n```yaml\n- apt:\n    deb: \"https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb\"\n```\n\n#### Repositories\n\n```yaml\n- apt_repository:\n    repo: \"deb https://\u00b7\u00b7\u00b7 raring main\"\n    state: present\n```\n\n#### Repository keys\n\n```yaml\n- apt_key:\n    id: AC40B2F7\n    url: \"http://\u00b7\u00b7\u00b7\"\n    state: present\n```\n\n### git\n\n```yaml\n- git:\n    repo: git://github.com/\n    dest: /srv/checkout\n    version: master\n    depth: 10\n    bare: yes\n```\n\nSee: [git module](https://devdocs.io/ansible/git_module)\n\n### git_config\n\n```yaml\n- git_config:\n    name: user.email\n    scope: global # local | system\n    value: hi@example.com\n```\n\nSee: [git_config module](https://devdocs.io/ansible/git_config_module)\n\n### user\n\n```yaml\n- user:\n    state: present\n    name: git\n    system: yes\n    shell: /bin/sh\n    groups: admin\n    comment: \"Git Version Control\"\n```\n\nSee: [user module](https://devdocs.io/ansible/user_module)\n\n### service\n\n```yaml\n- service:\n    name: nginx\n    state: started\n    enabled: yes     # optional\n```\n\nSee: [service module](https://devdocs.io/ansible/service_module)\n\n## Shell\n\n### shell\n\n```yaml\n- shell: apt-get install nginx -y\n```\n\n#### Extra options\n\n```yaml\n- shell: echo hello\n  args:\n    creates: /path/file  # skip if this exists\n    removes: /path/file  # skip if this is missing\n    chdir: /path         # cd here before running\n```\n\n#### Multiline example\n\n```yaml\n- shell: |\n    echo \"hello there\"\n    echo \"multiple lines\"\n```\n\nSee: [shell module](https://devdocs.io/ansible/shell_module)\n\n### script\n\n```yaml\n- script: /x/y/script.sh\n  args:\n    creates: /path/file  # skip if this exists\n    removes: /path/file  # skip if this is missing\n    chdir: /path         # cd here before running\n```\n\nSee: [script module](https://devdocs.io/ansible/script_module)\n\n## Files\n\n### file\n\n```yaml\n- file:\n    path: /etc/dir\n    state: directory # file | link | hard | touch | absent\n\n    # Optional:\n    owner: bin\n    group: wheel\n    mode: 0644\n    recurse: yes  # mkdir -p\n    force: yes    # ln -nfs\n```\n\nSee: [file module](https://devdocs.io/ansible/file_module)\n\n### copy\n\n```yaml\n- copy:\n    src: /app/config/nginx.conf\n    dest: /etc/nginx/nginx.conf\n\n    # Optional:\n    owner: user\n    group: user\n    mode: 0644\n    backup: yes\n```\n\nSee: [copy module](https://devdocs.io/ansible/copy_module)\n\n### template\n\n```yaml\n- template:\n    src: config/redis.j2\n    dest: /etc/redis.conf\n\n    # Optional:\n    owner: user\n    group: user\n    mode: 0644\n    backup: yes\n```\n\nSee: [template module](https://devdocs.io/ansible/template_module)\n\n## Local actions\n\n### local_action\n\n```yaml\n- name: do something locally\n  local_action: shell echo hello\n```\n\n### debug\n\n```yaml\n- debug:\n    msg: \"Hello {{ var }}\"\n```\n\nSee: [debug module](https://devdocs.io/ansible/debug_module)\n{% endraw %}"}

field_body:
{% raw %}

## Format

### Basic file

```yaml
---
- hosts: production
  remote_user: root
  tasks:
  - ···
```

Place your modules inside `tasks`.

### Task formats

#### One-line

```yaml
- apt: pkg=vim state=present
```

#### Map

```yaml
- apt:
    pkg: vim
    state: present
```

#### Foldable scalar

```yaml
- apt: >
    pkg=vim
    state=present
```

Define your tasks in any of these formats. One-line format is preferred for short declarations, while maps are preferred for longer.

## Modules

### Aptitude

#### Packages

```yaml
- apt:
    pkg: nodejs
    state: present # absent | latest
    update_cache: yes
    force: no
```

#### Deb files

```yaml
- apt:
    deb: "https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb"
```

#### Repositories

```yaml
- apt_repository:
    repo: "deb https://··· raring main"
    state: present
```

#### Repository keys

```yaml
- apt_key:
    id: AC40B2F7
    url: "http://···"
    state: present
```

### git

```yaml
- git:
    repo: git://github.com/
    dest: /srv/checkout
    version: master
    depth: 10
    bare: yes
```

See: [git module](https://devdocs.io/ansible/git_module)

### git_config

```yaml
- git_config:
    name: user.email
    scope: global # local | system
    value: hi@example.com
```

See: [git_config module](https://devdocs.io/ansible/git_config_module)

### user

```yaml
- user:
    state: present
    name: git
    system: yes
    shell: /bin/sh
    groups: admin
    comment: "Git Version Control"
```

See: [user module](https://devdocs.io/ansible/user_module)

### service

```yaml
- service:
    name: nginx
    state: started
    enabled: yes     # optional
```

See: [service module](https://devdocs.io/ansible/service_module)

## Shell

### shell

```yaml
- shell: apt-get install nginx -y
```

#### Extra options

```yaml
- shell: echo hello
  args:
    creates: /path/file  # skip if this exists
    removes: /path/file  # skip if this is missing
    chdir: /path         # cd here before running
```

#### Multiline example

```yaml
- shell: |
    echo "hello there"
    echo "multiple lines"
```

See: [shell module](https://devdocs.io/ansible/shell_module)

### script

```yaml
- script: /x/y/script.sh
  args:
    creates: /path/file  # skip if this exists
    removes: /path/file  # skip if this is missing
    chdir: /path         # cd here before running
```

See: [script module](https://devdocs.io/ansible/script_module)

## Files

### file

```yaml
- file:
    path: /etc/dir
    state: directory # file | link | hard | touch | absent

    # Optional:
    owner: bin
    group: wheel
    mode: 0644
    recurse: yes  # mkdir -p
    force: yes    # ln -nfs
```

See: [file module](https://devdocs.io/ansible/file_module)

### copy

```yaml
- copy:
    src: /app/config/nginx.conf
    dest: /etc/nginx/nginx.conf

    # Optional:
    owner: user
    group: user
    mode: 0644
    backup: yes
```

See: [copy module](https://devdocs.io/ansible/copy_module)

### template

```yaml
- template:
    src: config/redis.j2
    dest: /etc/redis.conf

    # Optional:
    owner: user
    group: user
    mode: 0644
    backup: yes
```

See: [template module](https://devdocs.io/ansible/template_module)

## Local actions

### local_action

```yaml
- name: do something locally
  local_action: shell echo hello
```

### debug

```yaml
- debug:
    msg: "Hello {{ var }}"
```

See: [debug module](https://devdocs.io/ansible/debug_module)
{% endraw %}


id: ansible-guide
git_filename: ./ansible-guide.md
format: md
field_title: Ansible quickstart
field_category: Ansible
data:
{"title": "Ansible quickstart", "category": "Ansible", "description": "A quick guide to getting started with your first Ansible playbook.\n", "body": "### Install Ansible\n\n```bash\n$ brew install ansible            # OSX\n$ [sudo] apt install ansible      # elsewhere\n```\n\nAnsible is available as a package in most OS's.\n\nSee: [Installation](http://docs.ansible.com/ansible/latest/intro_installation.html)\n\n### Start your project\n\n```bash\n~$ mkdir setup\n~$ cd setup\n```\n\nMake a folder for your Ansible files.\n\nSee: [Getting started](http://docs.ansible.com/ansible/latest/intro_getting_started.html)\n\n## Creating your files\n\n### Inventory file\n\n#### ~/setup/hosts\n\n```dosini\n[sites]\n127.0.0.1\n192.168.0.1\n192.168.0.2\n192.168.0.3\n```\n\nThis is a list of hosts you want to manage, grouped into groups. (Hint: try\nusing `localhost ansible_connection=local` to deploy to your local machine.)\n\nSee: [Intro to Inventory](http://docs.ansible.com/ansible/latest/intro_inventory.html)\n\n### Playbook\n\n#### ~/setup/playbook.yml\n\n```yaml\n- hosts: 127.0.0.1\n  user: root\n  tasks:\n    - name: install nginx\n      apt: pkg=nginx state=present\n\n    - name: start nginx every bootup\n      service: name=nginx state=started enabled=yes\n\n    - name: do something in the shell\n      shell: echo hello > /tmp/abc.txt\n\n    - name: install bundler\n      gem: name=bundler state=latest\n```\n\nSee: [Intro to Playbooks](http://docs.ansible.com/ansible/latest/playbooks_intro.html)\n\n## Running\n\n### Running ansible-playbook\n\n```\n~/setup$ ls\nhosts\nplaybook.yml\n```\n\n#### Running the playbook\n\n```\n~/setup$ ansible-playbook -i hosts playbook.yml\nPLAY [all] ********************************************************************\n\nGATHERING FACTS ***************************************************************\nok: [127.0.0.1]\n\nTASK: [install nginx] *********************************************************\nok: [127.0.0.1]\n\nTASK: start nginx every bootup] ***********************************************\nok: [127.0.0.1]\n...\n```\n\n## Read more\n\n* [Getting started with Ansible](http://lowendbox.com/blog/getting-started-with-ansible/) _(lowendbox.com)_\n* [Getting started](http://docs.ansible.com/ansible/latest/intro_getting_started.html) _(docs.ansible.com)_\n* [Intro to Inventory](http://docs.ansible.com/ansible/latest/intro_inventory.html) _(docs.ansible.com)_\n* [Intro to Playbooks](http://docs.ansible.com/ansible/latest/playbooks_intro.html) _(docs.ansible.com)_\n* [Ansible Tutorial for Beginners: Playbook & Examples](https://spacelift.io/blog/ansible-tutorial) _(spacelift.io)_\n* [Working with Ansible Playbooks \u2013 Tips & Tricks with Examples](https://spacelift.io/blog/ansible-playbooks) _(spacelift.io)_"}

field_body:
### Install Ansible

```bash
$ brew install ansible            # OSX
$ [sudo] apt install ansible      # elsewhere
```

Ansible is available as a package in most OS's.

See: [Installation](http://docs.ansible.com/ansible/latest/intro_installation.html)

### Start your project

```bash
~$ mkdir setup
~$ cd setup
```

Make a folder for your Ansible files.

See: [Getting started](http://docs.ansible.com/ansible/latest/intro_getting_started.html)

## Creating your files

### Inventory file

#### ~/setup/hosts

```dosini
[sites]
127.0.0.1
192.168.0.1
192.168.0.2
192.168.0.3
```

This is a list of hosts you want to manage, grouped into groups. (Hint: try
using `localhost ansible_connection=local` to deploy to your local machine.)

See: [Intro to Inventory](http://docs.ansible.com/ansible/latest/intro_inventory.html)

### Playbook

#### ~/setup/playbook.yml

```yaml
- hosts: 127.0.0.1
  user: root
  tasks:
    - name: install nginx
      apt: pkg=nginx state=present

    - name: start nginx every bootup
      service: name=nginx state=started enabled=yes

    - name: do something in the shell
      shell: echo hello > /tmp/abc.txt

    - name: install bundler
      gem: name=bundler state=latest
```

See: [Intro to Playbooks](http://docs.ansible.com/ansible/latest/playbooks_intro.html)

## Running

### Running ansible-playbook

```
~/setup$ ls
hosts
playbook.yml
```

#### Running the playbook

```
~/setup$ ansible-playbook -i hosts playbook.yml
PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [install nginx] *********************************************************
ok: [127.0.0.1]

TASK: start nginx every bootup] ***********************************************
ok: [127.0.0.1]
...
```

## Read more

* [Getting started with Ansible](http://lowendbox.com/blog/getting-started-with-ansible/) _(lowendbox.com)_
* [Getting started](http://docs.ansible.com/ansible/latest/intro_getting_started.html) _(docs.ansible.com)_
* [Intro to Inventory](http://docs.ansible.com/ansible/latest/intro_inventory.html) _(docs.ansible.com)_
* [Intro to Playbooks](http://docs.ansible.com/ansible/latest/playbooks_intro.html) _(docs.ansible.com)_
* [Ansible Tutorial for Beginners: Playbook & Examples](https://spacelift.io/blog/ansible-tutorial) _(spacelift.io)_
* [Working with Ansible Playbooks – Tips & Tricks with Examples](https://spacelift.io/blog/ansible-playbooks) _(spacelift.io)_


id: ansible-examples
git_filename: ./ansible-examples.md
format: md
field_title: Ansible examples
field_category: Ansible
data:
{"title": "Ansible examples", "category": "Ansible", "body": "### Examples\n\n * [Ruby installation](https://github.com/chelsea/ansible-example-ruby/blob/master/roles/webserver/tasks/main.yml) _(github.com)_\n * [Postgres installation](https://github.com/chelsea/ansible-example-ruby/blob/master/roles/db/tasks/main.yml)  _(github.com)_\n * [GitLab installation](https://github.com/tingtun/ansible-playbook-gitlab) _(github.com)_"}

field_body:
### Examples

 * [Ruby installation](https://github.com/chelsea/ansible-example-ruby/blob/master/roles/webserver/tasks/main.yml) _(github.com)_
 * [Postgres installation](https://github.com/chelsea/ansible-example-ruby/blob/master/roles/db/tasks/main.yml)  _(github.com)_
 * [GitLab installation](https://github.com/tingtun/ansible-playbook-gitlab) _(github.com)_


id: ansi
git_filename: ./ansi.md
format: md
field_title: Ansi codes
field_category: CLI
field_intro: Quick reference to ANSI color codes.
data:
{"title": "Ansi codes", "category": "CLI", "intro": "Quick reference to ANSI color codes.\n", "body": "### Format\n\n```\n\\033[#m\n```\n\n### ANSI codes\n\n```\n0      clear\n1      bold\n4      underline\n5      blink\n\n30-37  fg color\n40-47  bg color\n\n1K     clear line (to beginning of line)\n2K     clear line (entire line)\n2J     clear screen\n0;0H   move cursor to 0;0\n\n1A     move up 1 line\n```\n\n### Colors\n\n```\n0      black\n1      red\n2      green\n3      yellow\n4      blue\n5      magenta\n6      cyan\n7      white\n```\n\n### Bash utilities\n\n```sh\nhide_cursor() { printf \"\\e[?25l\"; }\nshow_cursor() { printf \"\\e[?25h\"; }\n```"}

field_body:
### Format

```
\033[#m
```

### ANSI codes

```
0      clear
1      bold
4      underline
5      blink

30-37  fg color
40-47  bg color

1K     clear line (to beginning of line)
2K     clear line (entire line)
2J     clear screen
0;0H   move cursor to 0;0

1A     move up 1 line
```

### Colors

```
0      black
1      red
2      green
3      yellow
4      blue
5      magenta
6      cyan
7      white
```

### Bash utilities

```sh
hide_cursor() { printf "\e[?25l"; }
show_cursor() { printf "\e[?25h"; }
```


id: animated_gif
git_filename: ./animated_gif.md
format: md
field_title: Animated GIFs
field_category: CLI
data:
{"title": "Animated GIFs", "category": "CLI", "body": "## Animated GIFs\n{: .-one-column}\n\n### Convert MP4 to GIF\n\n```bash\nmkdir -p gif\nmplayer -ao null -vo gif89a:outdir=gif $INPUT\nmogrify -format gif *.png\ngifsicle --colors=256 --delay=4 --loopcount=0 --dither -O3 gif/*.gif > ${INPUT%.*}.gif\nrm -rf gif\n```\n\nYou'll need `mplayer`, `imagemagick` and `gifsicle`. This converts frames to .png, then turns them into an animated gif.\n\n### A given range\n\n```bash\nmplayer -ao null -ss 0:02:06 -endpos 0:05:00 -vo gif89a:outdir=gif videofile.mp4\n```\n\nSee `-ss` and `-endpos`."}

field_body:
## Animated GIFs
{: .-one-column}

### Convert MP4 to GIF

```bash
mkdir -p gif
mplayer -ao null -vo gif89a:outdir=gif $INPUT
mogrify -format gif *.png
gifsicle --colors=256 --delay=4 --loopcount=0 --dither -O3 gif/*.gif > ${INPUT%.*}.gif
rm -rf gif
```

You'll need `mplayer`, `imagemagick` and `gifsicle`. This converts frames to .png, then turns them into an animated gif.

### A given range

```bash
mplayer -ao null -ss 0:02:06 -endpos 0:05:00 -vo gif89a:outdir=gif videofile.mp4
```

See `-ss` and `-endpos`.


id: angularjs
git_filename: ./angularjs.md
format: md
field_title: Angular.js
field_category: JavaScript libraries
field_tags: Archived
data:
{"title": "Angular.js", "category": "JavaScript libraries", "tags": ["Archived"], "archived": "This describes an older version of Angular.", "body": "### About\n{: .-intro}\n\n * <https://github.com/angular/angular-seed>\n * <https://angularjs.org/>\n\n### ng-app\n\n```html\n \u00a0 \u00a0<html ng-app=\"nameApp\">\n```\n\n### Lists (ng-repeat)\n```html\n    <ul ng-controller=\"MyListCtrl\">\n      <li ng-repeat=\"phone in phones\">\n        {{phone.name}}\n      </li>\n \u00a0 \u00a0</ul>\n```\n\n### Model (ng-model)\n\n```html\n    <select ng-model=\"orderProp\">\n      <option value=\"name\">Alphabetical</option>\n      <option value=\"age\">Newest</option>\n \u00a0 \u00a0</select>\n```\n\n### Defining a module\n```js\n \u00a0 \u00a0App = angular.module('myApp', []);\n\n    App.controller('MyListCtrl', function ($scope) {\n      $scope.phones = [ ... ];\n \u00a0 \u00a0});\n```\n\n### Controller with protection from minification\n```js\n \u00a0 \u00a0App.controller('Name', [\n      '$scope',\n      '$http',\n      function ($scope, $http) {\n      }\n    ]);\n\n    a.c 'name', [\n      '$scope'\n      '$http'\n      ($scope, $http) ->\n \u00a0 \u00a0]\n```\n\n### Service\n```js\n \u00a0 \u00a0App.service('NameService', function($http){\n      return {\n        get: function(){\n          return $http.get(url);\n        }\n      }\n \u00a0 \u00a0});\n```\nIn controller you call with parameter and will use promises to return data from server.\n\n```js\n \u00a0 \u00a0App.controller('controllerName',\n    function(NameService){\n      NameService.get()\n      .then(function(){})\n \u00a0 \u00a0})\n```\n\n### Directive\n```js\n \u00a0 \u00a0App.directive('name', function(){\n      return {\n        template: '<h1>Hello</h1>'\n      }\n \u00a0 \u00a0});\n```\n\nIn HTML will use `<name></name>` to render your template `<h1>Hello</h1>`\n\n### HTTP\n```js\n    App.controller('PhoneListCtrl', function ($scope, $http) {\n        $http.get('/data.json').success(function (data) {\n            $scope.phones = data;\n        })\n \u00a0 \u00a0});\n```"}

field_body:
### About
{: .-intro}

 * <https://github.com/angular/angular-seed>
 * <https://angularjs.org/>

### ng-app

```html
    <html ng-app="nameApp">
```

### Lists (ng-repeat)
```html
    <ul ng-controller="MyListCtrl">
      <li ng-repeat="phone in phones">
        {{phone.name}}
      </li>
    </ul>
```

### Model (ng-model)

```html
    <select ng-model="orderProp">
      <option value="name">Alphabetical</option>
      <option value="age">Newest</option>
    </select>
```

### Defining a module
```js
    App = angular.module('myApp', []);

    App.controller('MyListCtrl', function ($scope) {
      $scope.phones = [ ... ];
    });
```

### Controller with protection from minification
```js
    App.controller('Name', [
      '$scope',
      '$http',
      function ($scope, $http) {
      }
    ]);

    a.c 'name', [
      '$scope'
      '$http'
      ($scope, $http) ->
    ]
```

### Service
```js
    App.service('NameService', function($http){
      return {
        get: function(){
          return $http.get(url);
        }
      }
    });
```
In controller you call with parameter and will use promises to return data from server.

```js
    App.controller('controllerName',
    function(NameService){
      NameService.get()
      .then(function(){})
    })
```

### Directive
```js
    App.directive('name', function(){
      return {
        template: '<h1>Hello</h1>'
      }
    });
```

In HTML will use `<name></name>` to render your template `<h1>Hello</h1>`

### HTTP
```js
    App.controller('PhoneListCtrl', function ($scope, $http) {
        $http.get('/data.json').success(function (data) {
            $scope.phones = data;
        })
    });
```


id: analytics
git_filename: ./analytics.md
format: md
field_title: Analytics libraries
field_category: Analytics
data:
{"title": "Analytics libraries", "category": "Analytics", "body": "### Mixpanel\n\n```js\nmixpanel.identify('284');\nmixpanel.people.set({ $email: 'hi@gmail.com' });\nmixpanel.register({ age: 28, gender: 'male' }); /* set common properties */\n```\n\n[mixpanel](./mixpanel)\n{: .-crosslink}\n\n### Google Analytics's analytics.js\n\n```js\nga('create', 'UA-XXXX-Y', 'auto');\nga('create', 'UA-XXXX-Y', { userId: 'USER_ID' });\n```\n\n```js\nga('send', 'pageview');\nga('send', 'pageview', { 'dimension15': 'My custom dimension' });\n```\n\n[analytics.js](./analytics.js)\n{: .-crosslink}"}

field_body:
### Mixpanel

```js
mixpanel.identify('284');
mixpanel.people.set({ $email: 'hi@gmail.com' });
mixpanel.register({ age: 28, gender: 'male' }); /* set common properties */
```

[mixpanel](./mixpanel)
{: .-crosslink}

### Google Analytics's analytics.js

```js
ga('create', 'UA-XXXX-Y', 'auto');
ga('create', 'UA-XXXX-Y', { userId: 'USER_ID' });
```

```js
ga('send', 'pageview');
ga('send', 'pageview', { 'dimension15': 'My custom dimension' });
```

[analytics.js](./analytics.js)
{: .-crosslink}


id: analytics.js
git_filename: ./analytics.js.md
format: md
field_title: Google Analytics's analytics.js
field_category: Analytics
field_intro: Google Analytics's analytics.js is deprecated.
field_updated: 2017-10-29
field_updated___timezone: UTC
data:
{"title": "Google Analytics's analytics.js", "category": "Analytics", "updated": "2017-10-29", "intro": "Google Analytics's analytics.js is deprecated.\n", "body": "### Page view\n\n```js\nga('create', 'UA-XXXX-Y', 'auto')\nga('create', 'UA-XXXX-Y', { userId: 'USER_ID' })\n```\n\n```js\nga('send', 'pageview')\nga('send', 'pageview', { 'dimension15': 'My custom dimension' })\n```\n\n### Events\n\n```js\nga('send', 'event', 'button',  'click', {color: 'red'});\n```\n\n```js\nga('send', 'event', 'button',  'click', 'nav buttons',  4);\n/*                  ^category  ^action  ^label          ^value */\n```\n\n### Exceptions\n\n```js\nga('send', 'exception', {\n  exDescription: 'DatabaseError',\n  exFatal: false,\n  appName: 'myapp',\n  appVersion: '0.1.2'\n})\n```"}

field_body:
### Page view

```js
ga('create', 'UA-XXXX-Y', 'auto')
ga('create', 'UA-XXXX-Y', { userId: 'USER_ID' })
```

```js
ga('send', 'pageview')
ga('send', 'pageview', { 'dimension15': 'My custom dimension' })
```

### Events

```js
ga('send', 'event', 'button',  'click', {color: 'red'});
```

```js
ga('send', 'event', 'button',  'click', 'nav buttons',  4);
/*                  ^category  ^action  ^label          ^value */
```

### Exceptions

```js
ga('send', 'exception', {
  exDescription: 'DatabaseError',
  exFatal: false,
  appName: 'myapp',
  appVersion: '0.1.2'
})
```


id: adb
git_filename: ./adb.md
format: md
field_title: adb (Android Debug Bridge)
field_category: CLI
field_updated: 2018-03-06
field_updated___timezone: UTC
data:
{"title": "adb (Android Debug Bridge)", "category": "CLI", "weight": -1, "authors": [{"github": "ZackNeyland"}], "updated": "2018-03-06", "body": "### Device Basics\n\n| Command                           | Description                                 |\n| ---                               | ---                                         |\n| `adb devices`                     | Lists connected devices                     |\n| `adb devices -l`                  | Lists connected devices and kind            |\n| ---                               | ---                                         |\n| `adb root`                        | Restarts adbd with root permissions         |\n| `adb start-server`                | Starts the adb server                       |\n| `adb kill-server`                 | Kills the adb server                        |\n| `adb remount`                     | Remounts file system with read/write access |\n| `adb reboot`                      | Reboots the device                          |\n| `adb reboot bootloader`           | Reboots the device into fastboot            |\n| `adb disable-verity`              | Reboots the device into fastboot            |\n\n`wait-for-device` can be specified after `adb` to ensure that the command will run once the device is connected.\n\n`-s` can be used to send the commands to a specific device when multiple are connected.\n\n#### Examples\n\n```\n$ adb wait-for-device devices\n List of devices attached\n somedevice-1234 device\n someotherdevice-1234 device\n```\n\n```\n$ adb -s somedevice-1234 root\n```\n\n### Logcat\n\n| Command                              | Description                            |\n| ---                                  | ---                                    |\n| `adb logcat`                         | Starts printing log messages to stdout |\n| `adb logcat -g`                      | Displays current log buffer sizes      |\n| `adb logcat -G <size>`               | Sets the buffer size (K or M)          |\n| `adb logcat -c`                      | Clears the log buffers                 |\n| `adb logcat *:V`                     | Enables ALL log messages (verbose)     |\n| `adb logcat -f <filename>`           | Dumps to specified file                |\n\n#### Examples\n```\n$ adb logcat -G 16M\n$ adb logcat *:V > output.log\n```\n\n### File Management\n\n| Command                              | Description                       |\n| ---                                  | ---                               |\n| `adb push <local> <remote>` | Copies the local to the device at remote   |\n| `adb pull <remote> <local>` | Copies the remote from the device to local |\n\n#### Examples\n\n```\n$ echo \"This is a test\" > test.txt\n$ adb push  test.txt /sdcard/test.txt\n$ adb pull /sdcard/test.txt pulledTest.txt\n```\n\n### Remote Shell\n\n| Command                                | Description                                                           |\n| ---                                    | ---                                                                   |\n| `adb shell <command>`                  | Runs the specified command on device (most unix commands work here)   |\n| `adb shell wm size`                    | Displays the current screen resolution                                |\n| `adb shell wm size WxH`                | Sets the resolution to WxH                                            |\n| `adb shell pm list packages`           | Lists all installed packages                                          |\n| `adb shell pm list packages -3`        | Lists all installed 3rd-party packages                                |\n| `adb shell monkey -p app.package.name` | Starts the specified package                                          |"}

field_body:
### Device Basics

| Command                           | Description                                 |
| ---                               | ---                                         |
| `adb devices`                     | Lists connected devices                     |
| `adb devices -l`                  | Lists connected devices and kind            |
| ---                               | ---                                         |
| `adb root`                        | Restarts adbd with root permissions         |
| `adb start-server`                | Starts the adb server                       |
| `adb kill-server`                 | Kills the adb server                        |
| `adb remount`                     | Remounts file system with read/write access |
| `adb reboot`                      | Reboots the device                          |
| `adb reboot bootloader`           | Reboots the device into fastboot            |
| `adb disable-verity`              | Reboots the device into fastboot            |

`wait-for-device` can be specified after `adb` to ensure that the command will run once the device is connected.

`-s` can be used to send the commands to a specific device when multiple are connected.

#### Examples

```
$ adb wait-for-device devices
 List of devices attached
 somedevice-1234 device
 someotherdevice-1234 device
```

```
$ adb -s somedevice-1234 root
```

### Logcat

| Command                              | Description                            |
| ---                                  | ---                                    |
| `adb logcat`                         | Starts printing log messages to stdout |
| `adb logcat -g`                      | Displays current log buffer sizes      |
| `adb logcat -G <size>`               | Sets the buffer size (K or M)          |
| `adb logcat -c`                      | Clears the log buffers                 |
| `adb logcat *:V`                     | Enables ALL log messages (verbose)     |
| `adb logcat -f <filename>`           | Dumps to specified file                |

#### Examples
```
$ adb logcat -G 16M
$ adb logcat *:V > output.log
```

### File Management

| Command                              | Description                       |
| ---                                  | ---                               |
| `adb push <local> <remote>` | Copies the local to the device at remote   |
| `adb pull <remote> <local>` | Copies the remote from the device to local |

#### Examples

```
$ echo "This is a test" > test.txt
$ adb push  test.txt /sdcard/test.txt
$ adb pull /sdcard/test.txt pulledTest.txt
```

### Remote Shell

| Command                                | Description                                                           |
| ---                                    | ---                                                                   |
| `adb shell <command>`                  | Runs the specified command on device (most unix commands work here)   |
| `adb shell wm size`                    | Displays the current screen resolution                                |
| `adb shell wm size WxH`                | Sets the resolution to WxH                                            |
| `adb shell pm list packages`           | Lists all installed packages                                          |
| `adb shell pm list packages -3`        | Lists all installed 3rd-party packages                                |
| `adb shell monkey -p app.package.name` | Starts the specified package                                          |


id: activeadmin
git_filename: ./activeadmin.md
format: md
field_title: ActiveAdmin
field_category: Ruby
data:
{"title": "ActiveAdmin", "category": "Ruby", "body": "### Listing scopes\n\nAllows you to filter listings by a certain scope.\n{: .-setup}\n\n```ruby\nscope :draft\nscope :for_approval\n```\n\n```ruby\nscope :public, if: ->{ current_admin_user.can?(...) }\nscope \"Unapproved\", :pending\nscope(\"Published\") { |books| books.where(:published: true) }\n```\n\n### Sidebar filters\n\n```ruby\nfilter :email\nfilter :username\n```\n\n### Custom actions\n\nYou can define custom actions for models.\n{: .-setup}\n\n```ruby\nbefore_filter only: [:show, :edit, :publish] do\n  @post = Post.find(params[:id])\nend\n```\n\n#### Make the route\n\n```ruby\nmember_action :publish, method: :put do\n  @post.publish!\n  redirect_to admin_posts_path, notice: \"The post '#{@post}' has been published!\"\nend\n```\n\n#### Link it in the index\n\n```ruby\nindex do\n  column do |post|\n    link_to 'Publish', publish_admin_post_path(post), method: :put\n  end\nend\n```\n\n#### And link it in show/edit\n\n```ruby\naction_item only: [:edit, :show] do\n  @post = Post.find(params[:id])\n  link_to 'Publish', publish_admin_post_path(post), method: :put\nend\n```\n\n### Columns\n\n```ruby\ncolumn :foo\n```\n\n```ruby\ncolumn :title, sortable: :name do |post|\n  strong post.title\nend\n```\n\n### Other helpers\n\n```ruby\nstatus_tag \"Done\"           # Gray\nstatus_tag \"Finished\", :ok  # Green\nstatus_tag \"You\", :warn     # Orange\nstatus_tag \"Failed\", :error # Red\n```\n\n### Disabling 'new post'\n\n```ruby\nActiveAdmin.register Post do\n  actions :index, :edit\n  # or: config.clear_action_items!\nend\n```"}

field_body:
### Listing scopes

Allows you to filter listings by a certain scope.
{: .-setup}

```ruby
scope :draft
scope :for_approval
```

```ruby
scope :public, if: ->{ current_admin_user.can?(...) }
scope "Unapproved", :pending
scope("Published") { |books| books.where(:published: true) }
```

### Sidebar filters

```ruby
filter :email
filter :username
```

### Custom actions

You can define custom actions for models.
{: .-setup}

```ruby
before_filter only: [:show, :edit, :publish] do
  @post = Post.find(params[:id])
end
```

#### Make the route

```ruby
member_action :publish, method: :put do
  @post.publish!
  redirect_to admin_posts_path, notice: "The post '#{@post}' has been published!"
end
```

#### Link it in the index

```ruby
index do
  column do |post|
    link_to 'Publish', publish_admin_post_path(post), method: :put
  end
end
```

#### And link it in show/edit

```ruby
action_item only: [:edit, :show] do
  @post = Post.find(params[:id])
  link_to 'Publish', publish_admin_post_path(post), method: :put
end
```

### Columns

```ruby
column :foo
```

```ruby
column :title, sortable: :name do |post|
  strong post.title
end
```

### Other helpers

```ruby
status_tag "Done"           # Gray
status_tag "Finished", :ok  # Green
status_tag "You", :warn     # Orange
status_tag "Failed", :error # Red
```

### Disabling 'new post'

```ruby
ActiveAdmin.register Post do
  actions :index, :edit
  # or: config.clear_action_items!
end
```


id: absinthe
git_filename: ./absinthe.md
format: md
field_title: Absinthe
field_category: Hidden
field_tags: WIP
field_intro: [Absinthe](http://absinthe-graphql.org/) allows you to write GraphQL servers in Elixir.
field_updated: 2017-10-10
field_updated___timezone: UTC
data:
{"title": "Absinthe", "category": "Hidden", "tags": ["WIP"], "updated": "2017-10-10", "intro": "[Absinthe](http://absinthe-graphql.org/) allows you to write GraphQL servers in Elixir.\n", "body": "## Introduction\n\n### Concepts\n\n- `Schema` - The root. Defines what queries you can do, and what types they return.\n- `Resolver` - Functions that return data.\n- `Type` - A type definition describing the shape of the data you'll return.\n\n### Plug\n\n#### web/router.ex\n\n```elixir\ndefmodule Blog.Web.Router do\n  use Phoenix.Router\n\n  forward \"/\", Absinthe.Plug,\n    schema: Blog.Schema\nend\n```\n{: data-line=\"4,5\"}\n\nAbsinthe is a Plug, and you pass it one **Schema**.\n\nSee: [Our first query](http://absinthe-graphql.org/tutorial/our-first-query/)\n\n## Main concepts\n{: .-three-column}\n\n### Schema\n\n#### web/schema.ex\n\n```elixir\ndefmodule Blog.Schema do\n  use Absinthe.Schema\n  import_types Blog.Schema.Types\n\n  query do\n    @desc \"Get a list of blog posts\"\n    field :posts, list_of(:post) do\n      resolve &Blog.PostResolver.all/2\n    end\n  end\nend\n```\n{: data-line=\"5,6,7,8,9,10\"}\n\nThis schema will account for `{ posts { \u00b7\u00b7\u00b7 } }`. It returns a **Type** of `:post`, and delegates to a **Resolver**.\n\n### Resolver\n\n#### web/resolvers/post_resolver.ex\n\n```elixir\ndefmodule Blog.PostResolver do\n  def all(_args, _info) do\n    {:ok, Blog.Repo.all(Blog.Post)}\n  end\nend\n```\n{: data-line=\"3\"}\n\nThis is the function that the schema delegated the `posts` query to.\n\n### Type\n\n#### web/schema/types.ex\n\n```elixir\ndefmodule Blog.Schema.Types do\n  use Absinthe.Schema.Notation\n\n  @desc \"A blog post\"\n  object :post do\n    field :id, :id\n    field :title, :string\n    field :body, :string\n  end\nend\n```\n{: data-line=\"4,5,6,7,8,9\"}\n\nThis defines a type `:post`, which is used by the resolver.\n\n## Schema\n\n### Query arguments\n\n#### GraphQL query\n\n```\n{ user(id: \"1\") { \u00b7\u00b7\u00b7 } }\n```\n\n#### web/schema.ex\n\n```elixir\nquery do\n  field :user, type: :user do\n    arg :id, non_null(:id)\n    resolve &Blog.UserResolver.find/2\n  end\nend\n```\n{: data-line=\"3\"}\n\n#### Resolver\n\n```elixir\ndef find(%{id: id} = args, _info) do\n  \u00b7\u00b7\u00b7\nend\n```\n{: data-line=\"1\"}\n\nSee: [Query arguments](http://absinthe-graphql.org/tutorial/query-arguments/)\n\n### Mutations\n\n#### GraphQL query\n\n```\n{\n  mutation CreatePost {\n    post(title: \"Hello\") { id }\n  }\n}\n```\n\n#### web/schema.ex\n\n```elixir\nmutation do\n  @desc \"Create a post\"\n  field :post, type: :post do\n    arg :title, non_null(:string)\n    resolve &Blog.PostResolver.create/2\n  end\nend\n```\n{: data-line=\"1\"}\n\nSee: [Mutations](http://absinthe-graphql.org/tutorial/mutations/)\n\n## References\n\n  - [Absinthe website](http://absinthe-graphql.org/) _(absinthe-graphql.org)_\n  - [GraphQL cheatsheet](./graphql) _(devhints.io)_"}

field_body:
## Introduction

### Concepts

- `Schema` - The root. Defines what queries you can do, and what types they return.
- `Resolver` - Functions that return data.
- `Type` - A type definition describing the shape of the data you'll return.

### Plug

#### web/router.ex

```elixir
defmodule Blog.Web.Router do
  use Phoenix.Router

  forward "/", Absinthe.Plug,
    schema: Blog.Schema
end
```
{: data-line="4,5"}

Absinthe is a Plug, and you pass it one **Schema**.

See: [Our first query](http://absinthe-graphql.org/tutorial/our-first-query/)

## Main concepts
{: .-three-column}

### Schema

#### web/schema.ex

```elixir
defmodule Blog.Schema do
  use Absinthe.Schema
  import_types Blog.Schema.Types

  query do
    @desc "Get a list of blog posts"
    field :posts, list_of(:post) do
      resolve &Blog.PostResolver.all/2
    end
  end
end
```
{: data-line="5,6,7,8,9,10"}

This schema will account for `{ posts { ··· } }`. It returns a **Type** of `:post`, and delegates to a **Resolver**.

### Resolver

#### web/resolvers/post_resolver.ex

```elixir
defmodule Blog.PostResolver do
  def all(_args, _info) do
    {:ok, Blog.Repo.all(Blog.Post)}
  end
end
```
{: data-line="3"}

This is the function that the schema delegated the `posts` query to.

### Type

#### web/schema/types.ex

```elixir
defmodule Blog.Schema.Types do
  use Absinthe.Schema.Notation

  @desc "A blog post"
  object :post do
    field :id, :id
    field :title, :string
    field :body, :string
  end
end
```
{: data-line="4,5,6,7,8,9"}

This defines a type `:post`, which is used by the resolver.

## Schema

### Query arguments

#### GraphQL query

```
{ user(id: "1") { ··· } }
```

#### web/schema.ex

```elixir
query do
  field :user, type: :user do
    arg :id, non_null(:id)
    resolve &Blog.UserResolver.find/2
  end
end
```
{: data-line="3"}

#### Resolver

```elixir
def find(%{id: id} = args, _info) do
  ···
end
```
{: data-line="1"}

See: [Query arguments](http://absinthe-graphql.org/tutorial/query-arguments/)

### Mutations

#### GraphQL query

```
{
  mutation CreatePost {
    post(title: "Hello") { id }
  }
}
```

#### web/schema.ex

```elixir
mutation do
  @desc "Create a post"
  field :post, type: :post do
    arg :title, non_null(:string)
    resolve &Blog.PostResolver.create/2
  end
end
```
{: data-line="1"}

See: [Mutations](http://absinthe-graphql.org/tutorial/mutations/)

## References

  - [Absinthe website](http://absinthe-graphql.org/) _(absinthe-graphql.org)_
  - [GraphQL cheatsheet](./graphql) _(devhints.io)_


id: README
git_filename: ./README.md
format: md
data:
{"body": "<h1 align='center'>Devhints</h1>\n\n<blockquote align='center'>\nTL;DR for developer documentation - a ridiculous collection of cheatsheets\n</blockquote>\n\n<br>\n\n<p align='center'>\n<a href='https://devhints.io/'><img src='.github/images/screenshot.png' width=600></a>\n<br>\n\u2728 <b><a href='https://devhints.io/'>devhints.io</a></b> \u2728\n</p>\n\n<br>\n\n---\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for developer notes.\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rstacruz/cheatsheets)\n\n<h2 align='center'>Similar projects</h1>\n\n- [Command Line Interface Pages](https://github.com/command-line-interface-pages)\n- [tldr-pages](https://github.com/tldr-pages/tldr)\n- [Cheat](https://github.com/cheat/cheat)\n- [Eg](https://github.com/srsudar/eg)"}

field_body:
<h1 align='center'>Devhints</h1>

<blockquote align='center'>
TL;DR for developer documentation - a ridiculous collection of cheatsheets
</blockquote>

<br>

<p align='center'>
<a href='https://devhints.io/'><img src='.github/images/screenshot.png' width=600></a>
<br>
✨ <b><a href='https://devhints.io/'>devhints.io</a></b> ✨
</p>

<br>

---

See [CONTRIBUTING.md](CONTRIBUTING.md) for developer notes.

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rstacruz/cheatsheets)

<h2 align='center'>Similar projects</h1>

- [Command Line Interface Pages](https://github.com/command-line-interface-pages)
- [tldr-pages](https://github.com/tldr-pages/tldr)
- [Cheat](https://github.com/cheat/cheat)
- [Eg](https://github.com/srsudar/eg)


id: CONTRIBUTING
git_filename: ./CONTRIBUTING.md
format: md
data:
{"body": "# Developer notes\n\n## Runtimes\n\nRequires Node.js, Ruby, Yarn v1.\n\nSee `.ruby-version` and `.node-version` for supported versions.\n\n## Gitpod\n\nThis repository supports contribution using [gitpod](https://gitpod.io) which is online IDE using [Theia](https://github.com/eclipse-theia/theia).\n\nTo open-up the environment simple natigate on https://gitpod.io/#https://github.com/rstacruz/cheatsheets\n\nOr using a button:<br>\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rstacruz/cheatsheets)\n\n### Preview built website\n\nTo preview the website you need to first build it then you can navigate to file that you are trying to contribute and preview directly.\n\n<img src='.github/images/gitpod_preview_tut.png' width=828 height=459/>\n\n## Starting a local instance\n\nThis starts Jekyll and Parcel. This requires recent versions of [Node.js], [Yarn], [Ruby] and [Bundler] installed.\n\n```bash\nyarn install\nbundle install\nenv PORT=4001 yarn run dev\n```\n\n[node.js]: https://nodejs.org/en/download/package-manager/\n[ruby]: https://www.ruby-lang.org/en/documentation/installation/\n[yarn]: https://yarnpkg.com/en/docs/install\n[bundler]: https://bundler.io/\n\n### Docker\n\nYou can also run a local instance using Docker. This is the preferred method, especially for Windows.\nYou only need to install Docker ([macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/), [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/), [Arch Linux](https://www.archlinux.org/packages/community/x86_64/docker/), [other](https://www.docker.com/community-edition#download)).\n\nFirst time setup:\n\n```bash\n# Build images (takes ~12mins)\ndocker-compose build\n\n# First-time setup\ndocker-compose run --rm web bundle install && docker-compose run --rm web yarn install\n```\n\nStarting the server:\n\n```bash\ndocker-compose up\n```\n\n## CSS classes\n\nSee <https://devhints.io/cheatsheet-styles> for a reference on styling.\n\n## JavaScript\n\nWhen updating JavaScript, be sure Parcel is running (`yarn dev` takes care of this).\n\nThis auto-updates `/assets/packed/` and `_includes/2017/critical/` with sources in `_parcel/`.\n\nBefore committing, run `yarn parcel:build` first.\n\n## JavaScript tests\n\nThere are also automated tests:\n\n```\nyarn run test --watch\n```\n\n## Frontmatter\n\nEach sheet supports these metadata:\n\n```yml\n---\ntitle: React.js\n# Optional:\ncategory: React\nupdated: 2020-06-14\nads: false # Add this to disable ads\nweight: -5 # lower number = higher in related posts list\ndeprecated: true # Don't show in related posts\ndeprecated_by: /enzyme # Point to latest version\nprism_languages: [vim] # Extra syntax highlighting\nintro: |\n  This is some *Markdown* at the beginning of the article.\ntags:\n  - WIP\n  - Featured\n\n# Special pages:\n# (don't set these for cheatsheets)\ntype: home # home | article | error\nog_type: website # opengraph type\n---\n\n```\n\n## Prism languages\n\nFor supported prism languages:\n\n- <https://github.com/PrismJS/prism/tree/gh-pages/components>\n\n## Setting up redirects\n\nThis example sets up a redirect from `es2015` to `es6`:\n\n```yml\n# /es2015.md\n---\ntitle: ES2015\ncategory: Hidden\nredirect_to: /es6\n---\n\n```\n\n## Localizations\n\nSee `_data/content.yml` for chrome strings.\n\n## Forking\n\nSo you want to fork this repo? Sure, here's what you need to know to whitelabel this:\n\n- It's all GitHub pages, so the branch has to be `gh-pages`.\n- All other GitHub pages gotchas apply (CNAME, etc).\n- Edit everything in `_data/` - this holds all 'config' for the site: ad IDs, strings, etc.\n- Edit `_config.yml` as well, lots of things may not apply to you.\n\n## CloudFlare purging\n\nThe site devhints.io is backed by CloudFlare. Updates will take 2 days to propagate to the website by default. To make sure recent changes will propagate, use this helper script. It will give instructions on how manual selective cache purging can be done.\n\n```bash\n./_support/cf-purge.sh\n```\n\n## SEO description\n\nThere are multiple ways to set meta description.\n\n### Keywords (and intro)\n\nSet `keywords` (and optionally `intro`). This is the easiest and the preferred\nway for now.\n\n```\nReact cheatsheet - devhints.io\n------------------------------\nhttps://devhints.io/react \u25bc\nReact.Component \u00b7 render() \u00b7 componentDidMount() \u00b7 props/state \u00b7 React is a\nJavaScript library for building web...\n```\n\n### Description (and intro)\n\nSet `description` (and optionally `intro`)\n\n```\nReact cheatsheet - devhints.io\n------------------------------\nhttps://devhints.io/react \u25bc\nOne-page reference to React and its API. React is a JavaScript library for\nbuilding web user interfaces...\n```\n\n### Intro only\n\nIf you left out `description` or `keywords`, a default description will be added."}

field_body:
# Developer notes

## Runtimes

Requires Node.js, Ruby, Yarn v1.

See `.ruby-version` and `.node-version` for supported versions.

## Gitpod

This repository supports contribution using [gitpod](https://gitpod.io) which is online IDE using [Theia](https://github.com/eclipse-theia/theia).

To open-up the environment simple natigate on https://gitpod.io/#https://github.com/rstacruz/cheatsheets

Or using a button:<br>
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rstacruz/cheatsheets)

### Preview built website

To preview the website you need to first build it then you can navigate to file that you are trying to contribute and preview directly.

<img src='.github/images/gitpod_preview_tut.png' width=828 height=459/>

## Starting a local instance

This starts Jekyll and Parcel. This requires recent versions of [Node.js], [Yarn], [Ruby] and [Bundler] installed.

```bash
yarn install
bundle install
env PORT=4001 yarn run dev
```

[node.js]: https://nodejs.org/en/download/package-manager/
[ruby]: https://www.ruby-lang.org/en/documentation/installation/
[yarn]: https://yarnpkg.com/en/docs/install
[bundler]: https://bundler.io/

### Docker

You can also run a local instance using Docker. This is the preferred method, especially for Windows.
You only need to install Docker ([macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/), [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/), [Arch Linux](https://www.archlinux.org/packages/community/x86_64/docker/), [other](https://www.docker.com/community-edition#download)).

First time setup:

```bash
# Build images (takes ~12mins)
docker-compose build

# First-time setup
docker-compose run --rm web bundle install && docker-compose run --rm web yarn install
```

Starting the server:

```bash
docker-compose up
```

## CSS classes

See <https://devhints.io/cheatsheet-styles> for a reference on styling.

## JavaScript

When updating JavaScript, be sure Parcel is running (`yarn dev` takes care of this).

This auto-updates `/assets/packed/` and `_includes/2017/critical/` with sources in `_parcel/`.

Before committing, run `yarn parcel:build` first.

## JavaScript tests

There are also automated tests:

```
yarn run test --watch
```

## Frontmatter

Each sheet supports these metadata:

```yml
---
title: React.js
# Optional:
category: React
updated: 2020-06-14
ads: false # Add this to disable ads
weight: -5 # lower number = higher in related posts list
deprecated: true # Don't show in related posts
deprecated_by: /enzyme # Point to latest version
prism_languages: [vim] # Extra syntax highlighting
intro: |
  This is some *Markdown* at the beginning of the article.
tags:
  - WIP
  - Featured

# Special pages:
# (don't set these for cheatsheets)
type: home # home | article | error
og_type: website # opengraph type
---

```

## Prism languages

For supported prism languages:

- <https://github.com/PrismJS/prism/tree/gh-pages/components>

## Setting up redirects

This example sets up a redirect from `es2015` to `es6`:

```yml
# /es2015.md
---
title: ES2015
category: Hidden
redirect_to: /es6
---

```

## Localizations

See `_data/content.yml` for chrome strings.

## Forking

So you want to fork this repo? Sure, here's what you need to know to whitelabel this:

- It's all GitHub pages, so the branch has to be `gh-pages`.
- All other GitHub pages gotchas apply (CNAME, etc).
- Edit everything in `_data/` - this holds all 'config' for the site: ad IDs, strings, etc.
- Edit `_config.yml` as well, lots of things may not apply to you.

## CloudFlare purging

The site devhints.io is backed by CloudFlare. Updates will take 2 days to propagate to the website by default. To make sure recent changes will propagate, use this helper script. It will give instructions on how manual selective cache purging can be done.

```bash
./_support/cf-purge.sh
```

## SEO description

There are multiple ways to set meta description.

### Keywords (and intro)

Set `keywords` (and optionally `intro`). This is the easiest and the preferred
way for now.

```
React cheatsheet - devhints.io
------------------------------
https://devhints.io/react ▼
React.Component · render() · componentDidMount() · props/state · React is a
JavaScript library for building web...
```

### Description (and intro)

Set `description` (and optionally `intro`)

```
React cheatsheet - devhints.io
------------------------------
https://devhints.io/react ▼
One-page reference to React and its API. React is a JavaScript library for
building web user interfaces...
```

### Intro only

If you left out `description` or `keywords`, a default description will be added.


id: AGENTS
git_filename: ./AGENTS.md
format: md
data:
{"body": "# Agent guidelines for devhints.io\n\n## Commands\n\n- **Dev server**: `pnpm dev` (requires Ruby for markdown caching)\n- **Build**: `pnpm build`\n- **Test**: `pnpm test` (runs Vitest in watch mode)\n- **Run single test**: `pnpm vitest run <file-path>` or `pnpm vitest <file-path>` (watch mode)\n- **All tests (CI)**: `pnpm ci` (runs all linters, tests, and build)\n- **Lint**: `pnpm eslint:check` or `pnpm prettier:check`\n- **Format**: `pnpm format` (runs both ESLint and Prettier fixes)\n\n## Code style\n\n- **Package manager**: pnpm (v8.15.4+)\n- **Framework**: Astro with TypeScript (strict mode), Tailwind CSS\n- **Imports**: Use `~/` alias for `src/` directory; Prettier organizes imports automatically\n- **Types**: Use Zod schemas for runtime validation (see `SheetFrontmatter.ts`); TypeScript strict mode enabled\n- **Naming**: camelCase for variables/functions, PascalCase for components/types\n- **Error handling**: Distinguish operational (expected) vs unexpected errors; return error objects for operational errors\n- **Testing**: Vitest with globals enabled; use `it.each()` for repeated test cases; prefer object constants over helper functions\n\n## Markdown files\n\nConsult @_docs/writing-guidelines.md for formatting *.md files."}

field_body:
# Agent guidelines for devhints.io

## Commands

- **Dev server**: `pnpm dev` (requires Ruby for markdown caching)
- **Build**: `pnpm build`
- **Test**: `pnpm test` (runs Vitest in watch mode)
- **Run single test**: `pnpm vitest run <file-path>` or `pnpm vitest <file-path>` (watch mode)
- **All tests (CI)**: `pnpm ci` (runs all linters, tests, and build)
- **Lint**: `pnpm eslint:check` or `pnpm prettier:check`
- **Format**: `pnpm format` (runs both ESLint and Prettier fixes)

## Code style

- **Package manager**: pnpm (v8.15.4+)
- **Framework**: Astro with TypeScript (strict mode), Tailwind CSS
- **Imports**: Use `~/` alias for `src/` directory; Prettier organizes imports automatically
- **Types**: Use Zod schemas for runtime validation (see `SheetFrontmatter.ts`); TypeScript strict mode enabled
- **Naming**: camelCase for variables/functions, PascalCase for components/types
- **Error handling**: Distinguish operational (expected) vs unexpected errors; return error objects for operational errors
- **Testing**: Vitest with globals enabled; use `it.each()` for repeated test cases; prefer object constants over helper functions

## Markdown files

Consult @_docs/writing-guidelines.md for formatting *.md files.


id: 101
git_filename: ./101.md
format: md
field_title: 101
field_category: JavaScript libraries
field_updated: 2017-09-21
field_updated___timezone: UTC
data:
{"title": 101, "category": "JavaScript libraries", "updated": "2017-09-21", "intro": "[101](https://www.npmjs.com/package/101) is a JavaScript library for dealing with immutable data in a functional manner.\n", "body": "### Usage\n\n```js\nconst isObject = require('101/isObject')\nisObject({}) // \u2192 true\n```\n\nEvery function is exposed as a module.\n\nSee: [101](https://github.com/tjmehta/101)\n\n### Type checking\n\n```js\nisObject({})\nisString('str')\nisRegExp(/regexp/)\nisBoolean(true)\nisEmpty({})\nisfunction(x => x)\nisInteger(10)\nisNumber(10.1)\ninstanceOf(obj, 'string')\n```\n\n## Objects\n{: .-three-column}\n\n### Example\n{: .-prime}\n\n```js\nlet obj = {}\n```\n\n#### Update\n\n```js\nobj = put(obj, 'user.name', 'John')\n// \u2192 { user: { name: 'John' } }\n```\n\n#### Read\n\n```js\npluck(name, 'user.name')\n// \u2192 'John'\n```\n\n#### Delete\n\n```js\nobj = del(obj, 'user')\n// \u2192 { }\n```\n\n### Getting\n\n```js\npluck(state, 'user.profile.name')\n```\n\n```js\npick(state, ['user', 'ui'])\npick(state, /^_/)\n```\n\n`pluck` returns values, `pick` returns subsets of objects.\n\nSee:\n[pluck](https://github.com/tjmehta/101#pluck),\n[pick](https://github.com/tjmehta/101#pick)\n\n### Setting\n\n```js\nput(state, 'user.profile.name', 'john')\n```\n\nSee:\n[put](https://github.com/tjmehta/101#put)\n\n### Deleting\n\n```js\ndel(state, 'user.profile')\nomit(state, ['user', 'data'])\n```\n\n`omit` is like `del`, but supports multiple keys to be deleted.\n\nSee:\n[omit](https://github.com/tjmehta/101#omit),\n[del](https://github.com/tjmehta/101#del)\n\n### Keypath check\n\n```js\nhasKeypaths(state, ['user'])\nhasKeypaths(state, { 'user.profile.name': 'john' })\n```\n\nSee:\n[hasKeypaths](https://github.com/tjmehta/101#haskeypaths)\n\n### Get values\n\n```js\nvalues(state)\n```\n\n## Functions\n\n### Simple functions\n\n| `and(x, y)` | `x && y` |\n| `or(x, y)` | `x || y` |\n| `xor(x, y)` | `!(!x && !y) && !(x && y)` |\n| `equals(x, y)` | `x === y` |\n| `exists(x)` | `!!x` |\n| `not(x)` | `!x` |\n\nUseful for function composition.\n\nSee:\n[and](https://github.com/tjmehta/101#and),\n[equals](https://github.com/tjmehta/101#equals),\n[exists](https://github.com/tjmehta/101#exists)\n\n### Composition\n\n```js\ncompose(f, g)       // x => f(g(x))\ncurry(f)            // x => y => f(x, y)\nflip(f)             // f(x, y) --> f(y, x)\n```\n\nSee:\n[compose](https://github.com/tjmehta/101#compose),\n[curry](https://github.com/tjmehta/101#curry),\n[flip](https://github.com/tjmehta/101#flip)\n\n### And/or\n\n```js\npassAll(f, g)       // x => f(x) && g(x)\npassAny(f, g)       // x => f(x) || g(x)\n```\n\nSee:\n[passAll](https://github.com/tjmehta/101#passall),\n[passAny](https://github.com/tjmehta/101#passany)\n\n### Converge\n\n```js\nconverge(and, [pluck('a'), pluck('b')])(x)\n```\n\n```js\n// \u2192 and(pluck(x, 'a'), pluck(x, 'b'))\n```\n\nSee:\n[converge](https://github.com/tjmehta/101#converge)\n\n## Arrays\n\n### Finding\n\n```js\nfind(list, x => x.y === 2)\nfindIndex(list, x => ...)\nincludes(list, 'item')\nlast(list)\n```\n\n```js\nfind(list, hasProps('id'))\n```\n\n### Grouping\n\n```js\ngroupBy(list, 'id')\nindexBy(list, 'id')\n```\n\n## Examples\n\n### Function composition\n\n```js\nisFloat = passAll(isNumber, compose(isInteger, not))\n// n => isNumber(n) && not(isInteger(n))\n```\n\n```js\nfunction doStuff (object, options) { ... }\n\ndoStuffForce = curry(flip(doStuff))({ force: true })\n```\n\n## Reference\n\n- <https://github.com/tjmehta/101>"}

field_intro:
[101](https://www.npmjs.com/package/101) is a JavaScript library for dealing with immutable data in a functional manner.

field_body:
### Usage

```js
const isObject = require('101/isObject')
isObject({}) // → true
```

Every function is exposed as a module.

See: [101](https://github.com/tjmehta/101)

### Type checking

```js
isObject({})
isString('str')
isRegExp(/regexp/)
isBoolean(true)
isEmpty({})
isfunction(x => x)
isInteger(10)
isNumber(10.1)
instanceOf(obj, 'string')
```

## Objects
{: .-three-column}

### Example
{: .-prime}

```js
let obj = {}
```

#### Update

```js
obj = put(obj, 'user.name', 'John')
// → { user: { name: 'John' } }
```

#### Read

```js
pluck(name, 'user.name')
// → 'John'
```

#### Delete

```js
obj = del(obj, 'user')
// → { }
```

### Getting

```js
pluck(state, 'user.profile.name')
```

```js
pick(state, ['user', 'ui'])
pick(state, /^_/)
```

`pluck` returns values, `pick` returns subsets of objects.

See:
[pluck](https://github.com/tjmehta/101#pluck),
[pick](https://github.com/tjmehta/101#pick)

### Setting

```js
put(state, 'user.profile.name', 'john')
```

See:
[put](https://github.com/tjmehta/101#put)

### Deleting

```js
del(state, 'user.profile')
omit(state, ['user', 'data'])
```

`omit` is like `del`, but supports multiple keys to be deleted.

See:
[omit](https://github.com/tjmehta/101#omit),
[del](https://github.com/tjmehta/101#del)

### Keypath check

```js
hasKeypaths(state, ['user'])
hasKeypaths(state, { 'user.profile.name': 'john' })
```

See:
[hasKeypaths](https://github.com/tjmehta/101#haskeypaths)

### Get values

```js
values(state)
```

## Functions

### Simple functions

| `and(x, y)` | `x && y` |
| `or(x, y)` | `x || y` |
| `xor(x, y)` | `!(!x && !y) && !(x && y)` |
| `equals(x, y)` | `x === y` |
| `exists(x)` | `!!x` |
| `not(x)` | `!x` |

Useful for function composition.

See:
[and](https://github.com/tjmehta/101#and),
[equals](https://github.com/tjmehta/101#equals),
[exists](https://github.com/tjmehta/101#exists)

### Composition

```js
compose(f, g)       // x => f(g(x))
curry(f)            // x => y => f(x, y)
flip(f)             // f(x, y) --> f(y, x)
```

See:
[compose](https://github.com/tjmehta/101#compose),
[curry](https://github.com/tjmehta/101#curry),
[flip](https://github.com/tjmehta/101#flip)

### And/or

```js
passAll(f, g)       // x => f(x) && g(x)
passAny(f, g)       // x => f(x) || g(x)
```

See:
[passAll](https://github.com/tjmehta/101#passall),
[passAny](https://github.com/tjmehta/101#passany)

### Converge

```js
converge(and, [pluck('a'), pluck('b')])(x)
```

```js
// → and(pluck(x, 'a'), pluck(x, 'b'))
```

See:
[converge](https://github.com/tjmehta/101#converge)

## Arrays

### Finding

```js
find(list, x => x.y === 2)
findIndex(list, x => ...)
includes(list, 'item')
last(list)
```

```js
find(list, hasProps('id'))
```

### Grouping

```js
groupBy(list, 'id')
indexBy(list, 'id')
```

## Examples

### Function composition

```js
isFloat = passAll(isNumber, compose(isInteger, not))
// n => isNumber(n) && not(isInteger(n))
```

```js
function doStuff (object, options) { ... }

doStuffForce = curry(flip(doStuff))({ force: true })
```

## Reference

- <https://github.com/tjmehta/101>


id: wip_php
git_filename: ./wip/php.md
format: md
field_title: PHP
field_category: PHP
field_prism_languages: php
data:
{"title": "PHP", "category": "PHP", "prism_languages": ["php"], "body": "### Hello world\n\n#### hello.php\n\n```php\n<?php\nfunction greetMe($name): string\n{\n    return \"Hello, \" . $name . \"!\";\n}\n\n$message = greetMe($name);\necho $message;\n```\n\nAll PHP files start with `<?php`.\n\nSee: [PHP tags](https://php.net/manual/en/language.basic-syntax.phptags.php)\n\n### Objects\n\n```php\n<?php\n\n$fruitsArray = array(\n    \"apple\" => 20,\n    \"banana\" => 30\n);\necho $fruitsArray['banana'];\n```\n\nOr cast as object\n\n```php\n<?php\n\n$fruitsObject = (object) $fruits;\necho $fruitsObject->banana;\n``` \n\n### Inspecting objects\n\n```php\n<?php\nvar_dump($object)\n```\n\nPrints the contents of a variable for inspection.\n\nSee: [var_dump](https://php.net/var_dump)\n\n### Classes\n\n```php\nclass Person\n{\n    public $name = '';\n}\n\n$person = new Person();\n$person->name = 'bob';\n\necho $person->name;\n```\n\n### Getters and setters\n\n```php\nclass Person \n{\n    private $name = '';\n\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n        return $this;\n    }\n}\n\n$person = new Person();\n$person->setName('bob');\n\necho $person->getName();\n```\n\n### isset vs empty\n```php\n\n$options = [\n    'key' => 'value',\n    'blank' => '',\n    'nothing' => null,\n];\n\nvar_dump(isset($options['key']), empty($options['key'])); // true, false\nvar_dump(isset($options['blank']), empty($options['blank'])); // true, true\nvar_dump(isset($options['nothing']), empty($options['nothing'])); // false, true\n```"}

field_body:
### Hello world

#### hello.php

```php
<?php
function greetMe($name): string
{
    return "Hello, " . $name . "!";
}

$message = greetMe($name);
echo $message;
```

All PHP files start with `<?php`.

See: [PHP tags](https://php.net/manual/en/language.basic-syntax.phptags.php)

### Objects

```php
<?php

$fruitsArray = array(
    "apple" => 20,
    "banana" => 30
);
echo $fruitsArray['banana'];
```

Or cast as object

```php
<?php

$fruitsObject = (object) $fruits;
echo $fruitsObject->banana;
``` 

### Inspecting objects

```php
<?php
var_dump($object)
```

Prints the contents of a variable for inspection.

See: [var_dump](https://php.net/var_dump)

### Classes

```php
class Person
{
    public $name = '';
}

$person = new Person();
$person->name = 'bob';

echo $person->name;
```

### Getters and setters

```php
class Person 
{
    private $name = '';

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name)
    {
        $this->name = $name;
        return $this;
    }
}

$person = new Person();
$person->setName('bob');

echo $person->getName();
```

### isset vs empty
```php

$options = [
    'key' => 'value',
    'blank' => '',
    'nothing' => null,
];

var_dump(isset($options['key']), empty($options['key'])); // true, false
var_dump(isset($options['blank']), empty($options['blank'])); // true, true
var_dump(isset($options['nothing']), empty($options['nothing'])); // false, true
```


id: wip_intl-datetime
git_filename: ./wip/intl-datetime.md
format: md
field_title: Intl.DateTimeFormat
field_category: Hidden
field_tags: WIP
field_intro: `Intl.DateTimeFormat` is used to format date strings in JavaScript.
data:
{"title": "Intl.DateTimeFormat", "category": "Hidden", "tags": ["WIP"], "intro": "`Intl.DateTimeFormat` is used to format date strings in JavaScript.\n", "body": "### Parsing\n\n#### As local time\n\n```js\nconst date = new Date(2012, 11, 20, 3, 0, 0)\n```\n\n#### As UTC time\n\n```js\nconst date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))\n```\n\n#### From ISO strings\n\n```js\nconst date = new Date('2018-04-20T12:00:00Z')\n```\n\nNote that JavaScript doesn't \"store\" timezones in a date object. All these date objects, when expressed via `.toString()` or similar, will show the local timezone of the browser, regardless if you parsed UTC dates.\n\n### Formatting dates\n\n#### Default formatting\n\n```js\nconsole.log(new Intl.DateTimeFormat().format(date))\n// \u2192 '12/19/2012' (assuming America/Los_Angeles)\n```\n\n#### Custom locale\n\n```js\nconsole.log(new Intl.DateTimeFormat('en-GB').format(date))\n// \u2192 '19/12/2012' (date-first)\n```\n\n#### Custom timezone\n\n```js\nconsole.log(new Intl.DateTimeFormat('en-AU', {\n  timeZone: 'Australia/Sydney'\n}).format(date))\n// \u2192 '19/12/2012'\n```\n\n### Custom formats\n\n#### Time\n\n```js\nconsole.log(new Intl.DateTimeFormat('default', {\n  hour: 'numeric',\n  minute: 'numeric',\n  second: 'numeric'\n}).format(date))\n// \u2192 '2:00:00 pm'\n```\n\n#### Date\n\n```js\nconsole.log(new Intl.DateTimeFormat('en-US', {\n  year: 'numeric',\n  month: 'numeric',\n  day: 'numeric'\n}).format(date))\n// \u2192 '12/19/2012'\n```\n\nTo specify options without a locale, use `'default'` as a locale.\n\n### All options\n\n```js\n{\n  weekday: 'narrow' | 'short' | 'long',\n  era: 'narrow' | 'short' | 'long',\n  year: 'numeric' | '2-digit',\n  month: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',\n  day: 'numeric' | '2-digit',\n  hour: 'numeric' | '2-digit',\n  minute: 'numeric' | '2-digit',\n  second: 'numeric' | '2-digit',\n  timeZoneName: 'short' | 'long',\n\n  // Time zone to express it in\n  timeZone: 'Asia/Shanghai',\n  // Force 12-hour or 24-hour\n  hour12: true | false,\n\n  // Rarely-used options\n  hourCycle: 'h11' | 'h12' | 'h23' | 'h24',\n  formatMatcher: 'basic' | 'best fit'\n}\n```\n\n\n## References\n\n- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat>"}

field_body:
### Parsing

#### As local time

```js
const date = new Date(2012, 11, 20, 3, 0, 0)
```

#### As UTC time

```js
const date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
```

#### From ISO strings

```js
const date = new Date('2018-04-20T12:00:00Z')
```

Note that JavaScript doesn't "store" timezones in a date object. All these date objects, when expressed via `.toString()` or similar, will show the local timezone of the browser, regardless if you parsed UTC dates.

### Formatting dates

#### Default formatting

```js
console.log(new Intl.DateTimeFormat().format(date))
// → '12/19/2012' (assuming America/Los_Angeles)
```

#### Custom locale

```js
console.log(new Intl.DateTimeFormat('en-GB').format(date))
// → '19/12/2012' (date-first)
```

#### Custom timezone

```js
console.log(new Intl.DateTimeFormat('en-AU', {
  timeZone: 'Australia/Sydney'
}).format(date))
// → '19/12/2012'
```

### Custom formats

#### Time

```js
console.log(new Intl.DateTimeFormat('default', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
}).format(date))
// → '2:00:00 pm'
```

#### Date

```js
console.log(new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric'
}).format(date))
// → '12/19/2012'
```

To specify options without a locale, use `'default'` as a locale.

### All options

```js
{
  weekday: 'narrow' | 'short' | 'long',
  era: 'narrow' | 'short' | 'long',
  year: 'numeric' | '2-digit',
  month: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',
  day: 'numeric' | '2-digit',
  hour: 'numeric' | '2-digit',
  minute: 'numeric' | '2-digit',
  second: 'numeric' | '2-digit',
  timeZoneName: 'short' | 'long',

  // Time zone to express it in
  timeZone: 'Asia/Shanghai',
  // Force 12-hour or 24-hour
  hour12: true | false,

  // Rarely-used options
  hourCycle: 'h11' | 'h12' | 'h23' | 'h24',
  formatMatcher: 'basic' | 'best fit'
}
```


## References

- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat>


id: tests_keywords_test
git_filename: ./tests/keywords_test.md
format: md
field_title: Intro test
field_category: Hidden
field_updated: 2020-07-05
field_updated___timezone: UTC
field_body: ### Example test This page has keywords.
data:
{"title": "Intro test", "category": "Hidden", "updated": "2020-07-05", "keywords": ["Variables", "Functions", "Interpolation", "Brace expansions", "Loops", "Conditional execution", "Command substitution"], "body": "### Example test\nThis page has keywords."}


id: tests_basic
git_filename: ./tests/basic.md
format: md
field_title: Basic test
field_category: Hidden
field_body: ### Introduction This is a test cheatsheet. It's used as a reference for automated tests.
data:
{"title": "Basic test", "category": "Hidden", "body": "### Introduction\n\nThis is a test cheatsheet. It's used as a reference for automated tests."}


id: _includes_common_strftime_format
git_filename: ./_includes/common/strftime_format.md
format: md
data:
{"body": "## {{ include.title }}\n{: .-three-column}\n\n### Presets\n\n#### Date\n\n| Example         | Output                 |\n| ---             | ---                    |\n| `%m/%d/%Y`      | `06/05/2013`           |\n| `%A, %B %e, %Y` | `Sunday, June 5, 2013` |\n| `%b %e %a`      | `Jun 5 Sun`            |\n{: .-shortcuts}\n\n#### Time\n\n| Example         | Output                 |\n| ---             | ---                    |\n| `%H:%M`         | `23:05`                |\n| `%I:%M %p`      | `11:05 PM`             |\n{: .-shortcuts}\n\nUsed by Ruby, UNIX `date`, and many more.\n\n### Date\n\n| Symbol | Example                  | Area        |\n| ---    | ---                      | ---         |\n| `%a`   | `Sun`                    | **Weekday** |\n| `%A`   | `Sunday`                 |             |\n| `%w`   | `0`..`6` _(Sunday is 0)_ |             |\n| ---    | ---                      | ---         |\n| `%y`   | `13`                     | **Year**    |\n| `%Y`   | `2013`                   |             |\n| ---    | ---                      | ---         |\n| `%b`   | `Jan`                    | **Month**   |\n| `%B`   | `January`                |             |\n| `%m`   | `01`..`12`               |             |\n| ---    | ---                      | ---         |\n| `%d`   | `01`..`31`               | **Day**     |\n| `%e`   | `1`..`31`                |             |\n{: .-shortcuts}\n\n### Time\n\n| Symbol | Example      | Area                |\n| ---    | ---          | ---                 |\n| `%l`   | `1`          | Hour                |\n| `%H`   | `00`..`23`   | 24h Hour            |\n| `%I`   | `01`..`12`   | 12h Hour            |\n| --     | ---          | ---                 |\n| `%M`   | `00`..`59`   | Minute              |\n| `%S`   | `00`..`60`   | Second              |\n| ---    | ---          | ---                 |\n| `%p`   | `AM`         | AM or PM            |\n| `%Z`   | `+08`        | Time zone           |\n| ---    | ---          | ---                 |\n| `%j`   | `001`..`366` | Day of the year     |\n| `%%`   | `%`          | Literal % character |\n{: .-shortcuts}"}

field_body:
## {{ include.title }}
{: .-three-column}

### Presets

#### Date

| Example         | Output                 |
| ---             | ---                    |
| `%m/%d/%Y`      | `06/05/2013`           |
| `%A, %B %e, %Y` | `Sunday, June 5, 2013` |
| `%b %e %a`      | `Jun 5 Sun`            |
{: .-shortcuts}

#### Time

| Example         | Output                 |
| ---             | ---                    |
| `%H:%M`         | `23:05`                |
| `%I:%M %p`      | `11:05 PM`             |
{: .-shortcuts}

Used by Ruby, UNIX `date`, and many more.

### Date

| Symbol | Example                  | Area        |
| ---    | ---                      | ---         |
| `%a`   | `Sun`                    | **Weekday** |
| `%A`   | `Sunday`                 |             |
| `%w`   | `0`..`6` _(Sunday is 0)_ |             |
| ---    | ---                      | ---         |
| `%y`   | `13`                     | **Year**    |
| `%Y`   | `2013`                   |             |
| ---    | ---                      | ---         |
| `%b`   | `Jan`                    | **Month**   |
| `%B`   | `January`                |             |
| `%m`   | `01`..`12`               |             |
| ---    | ---                      | ---         |
| `%d`   | `01`..`31`               | **Day**     |
| `%e`   | `1`..`31`                |             |
{: .-shortcuts}

### Time

| Symbol | Example      | Area                |
| ---    | ---          | ---                 |
| `%l`   | `1`          | Hour                |
| `%H`   | `00`..`23`   | 24h Hour            |
| `%I`   | `01`..`12`   | 12h Hour            |
| --     | ---          | ---                 |
| `%M`   | `00`..`59`   | Minute              |
| `%S`   | `00`..`60`   | Second              |
| ---    | ---          | ---                 |
| `%p`   | `AM`         | AM or PM            |
| `%Z`   | `+08`        | Time zone           |
| ---    | ---          | ---                 |
| `%j`   | `001`..`366` | Day of the year     |
| `%%`   | `%`          | Literal % character |
{: .-shortcuts}


id: _includes_common_moment_format
git_filename: ./_includes/common/moment_format.md
format: md
data:
{"body": "## {{ include.title }}\n{: .-three-column}\n\n### Examples\n\n#### Date\n\n| Example                   | Output                 |\n| ------------------------- | ---------------------- |\n| `YYYY-MM-DD`              | 2014-01-01             |\n| `dddd, MMMM Do YYYY`      | Friday, May 16th 2014  |\n| `dddd [the] Do [of] MMMM` | Friday the 16th of May |\n\n#### Time\n\n| Example   | Output   |\n| --------- | -------- |\n| `hh:mm a` | 12:30 pm |\n\nUsed by [Moment.js](http://momentjs.com/docs/#/displaying/) and [date-fns/format](https://date-fns.org/v1.28.5/docs/format). Similar to Java [SimpleDateFormat](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html).\n\n### Date\n\n| Symbol | Example                 | Area             |\n| ---    | ---                     | ---              |\n| `d`    | `0`..`6`                | **Weekday**      |\n| `dd`   | `Su`                    |                  |\n| `ddd`  | `Sun`                   |                  |\n| `dddd` | `Sunday`                |                  |\n| ---    | ---                     | ---              |\n| `YY`   | `13`                    | **Year**         |\n| `YYYY` | `2013`                  |                  |\n| ---    | ---                     | ---              |\n| `M`    | `1`..`12` _(Jan is 1)_  | **Month**        |\n| `Mo`   | `1st`..`12th`           |                  |\n| `MM`   | `01`..`12` _(Jan is 1)_ |                  |\n| `MMM`  | `Jan`                   |                  |\n| `MMMM` | `January`               |                  |\n| ---    | ---                     | ---              |\n| `Q`    | `1`..`4`                | **Quarter**      |\n| `Qo`   | `1st`..`4th`            |                  |\n| ---    | ---                     | ---              |\n| `D`    | `1`..`31`               | **Day**          |\n| `Do`   | `1st`..`31st`           |                  |\n| `DD`   | `01`..`31`              |                  |\n| ---    | ---                     | ---              |\n| `DDD`  | `1`..`365`              | **Day of year**  |\n| `DDDo` | `1st`..`365th`          |                  |\n| `DDDD` | `001`..`365`            |                  |\n| ---    | ---                     | ---              |\n| `w`    | `1`..`53`               | **Week of year** |\n| `wo`   | `1st`..`53rd`           |                  |\n| `ww`   | `01`..`53`              |                  |\n{: .-shortcuts}\n\n### Time\n\n| Symbol | Example      | Area                       |\n| ---    | ---          | ---                        |\n| `H`    | `0`..`23`    | **24h hour**               |\n| `HH`   | `00`..`23`   |                            |\n| ---    | ---          | ---                        |\n| `h`    | `1`..`12`    | **12h hour**               |\n| `hh`   | `01`..`12`   |                            |\n| ---    | ---          | ---                        |\n| `m`    | `0`..`59`    | **Minutes**                |\n| `mm`   | `00`..`59`   |                            |\n| ---    | ---          | ---                        |\n| `s`    | `0`..`59`    | **Seconds**                |\n| `ss`   | `00`..`59`   |                            |\n| ---    | ---          | ---                        |\n| `a`    | `am`         | **AM/PM**                  |\n| `A`    | `AM`         |                            |\n| ---    | ---          | ---                        |\n| `Z`    | `+07:00`     | **Timezone offset**        |\n| `ZZ`   | `+0730`      |                            |\n| ---    | ---          | ---                        |\n| `S`    | `0`..`9`     | Deciseconds                |\n| `SS`   | `00`..`99`   | Centiseconds               |\n| `SSS`  | `000`..`999` | Milliseconds               |\n| ---    | ---          | ---                        |\n| `X`    |              | Unix timestamp             |\n| `x`    |              | Millisecond Unix timestamp |\n{: .-shortcuts}\n\n### Presets\n\n| Example | Output                           |\n| ------- | -------------------------------- |\n| `LT`    | 8:30 PM                          |\n| `LTS`   | 8:30:25 PM                       |\n| ---     | ---                              |\n| `LL`    | August 2 1985                    |\n| `ll`    | Aug 2 1985                       |\n| ---     | ---                              |\n| `LLL`   | August 2 1985 08:30 PM           |\n| `lll`   | Aug 2 1985 08:30 PM              |\n| ---     | ---                              |\n| `LLLL`  | Thursday, August 2 1985 08:30 PM |\n| `llll`  | Thu, Aug 2 1985 08:30 PM         |"}

field_body:
## {{ include.title }}
{: .-three-column}

### Examples

#### Date

| Example                   | Output                 |
| ------------------------- | ---------------------- |
| `YYYY-MM-DD`              | 2014-01-01             |
| `dddd, MMMM Do YYYY`      | Friday, May 16th 2014  |
| `dddd [the] Do [of] MMMM` | Friday the 16th of May |

#### Time

| Example   | Output   |
| --------- | -------- |
| `hh:mm a` | 12:30 pm |

Used by [Moment.js](http://momentjs.com/docs/#/displaying/) and [date-fns/format](https://date-fns.org/v1.28.5/docs/format). Similar to Java [SimpleDateFormat](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html).

### Date

| Symbol | Example                 | Area             |
| ---    | ---                     | ---              |
| `d`    | `0`..`6`                | **Weekday**      |
| `dd`   | `Su`                    |                  |
| `ddd`  | `Sun`                   |                  |
| `dddd` | `Sunday`                |                  |
| ---    | ---                     | ---              |
| `YY`   | `13`                    | **Year**         |
| `YYYY` | `2013`                  |                  |
| ---    | ---                     | ---              |
| `M`    | `1`..`12` _(Jan is 1)_  | **Month**        |
| `Mo`   | `1st`..`12th`           |                  |
| `MM`   | `01`..`12` _(Jan is 1)_ |                  |
| `MMM`  | `Jan`                   |                  |
| `MMMM` | `January`               |                  |
| ---    | ---                     | ---              |
| `Q`    | `1`..`4`                | **Quarter**      |
| `Qo`   | `1st`..`4th`            |                  |
| ---    | ---                     | ---              |
| `D`    | `1`..`31`               | **Day**          |
| `Do`   | `1st`..`31st`           |                  |
| `DD`   | `01`..`31`              |                  |
| ---    | ---                     | ---              |
| `DDD`  | `1`..`365`              | **Day of year**  |
| `DDDo` | `1st`..`365th`          |                  |
| `DDDD` | `001`..`365`            |                  |
| ---    | ---                     | ---              |
| `w`    | `1`..`53`               | **Week of year** |
| `wo`   | `1st`..`53rd`           |                  |
| `ww`   | `01`..`53`              |                  |
{: .-shortcuts}

### Time

| Symbol | Example      | Area                       |
| ---    | ---          | ---                        |
| `H`    | `0`..`23`    | **24h hour**               |
| `HH`   | `00`..`23`   |                            |
| ---    | ---          | ---                        |
| `h`    | `1`..`12`    | **12h hour**               |
| `hh`   | `01`..`12`   |                            |
| ---    | ---          | ---                        |
| `m`    | `0`..`59`    | **Minutes**                |
| `mm`   | `00`..`59`   |                            |
| ---    | ---          | ---                        |
| `s`    | `0`..`59`    | **Seconds**                |
| `ss`   | `00`..`59`   |                            |
| ---    | ---          | ---                        |
| `a`    | `am`         | **AM/PM**                  |
| `A`    | `AM`         |                            |
| ---    | ---          | ---                        |
| `Z`    | `+07:00`     | **Timezone offset**        |
| `ZZ`   | `+0730`      |                            |
| ---    | ---          | ---                        |
| `S`    | `0`..`9`     | Deciseconds                |
| `SS`   | `00`..`99`   | Centiseconds               |
| `SSS`  | `000`..`999` | Milliseconds               |
| ---    | ---          | ---                        |
| `X`    |              | Unix timestamp             |
| `x`    |              | Millisecond Unix timestamp |
{: .-shortcuts}

### Presets

| Example | Output                           |
| ------- | -------------------------------- |
| `LT`    | 8:30 PM                          |
| `LTS`   | 8:30:25 PM                       |
| ---     | ---                              |
| `LL`    | August 2 1985                    |
| `ll`    | Aug 2 1985                       |
| ---     | ---                              |
| `LLL`   | August 2 1985 08:30 PM           |
| `lll`   | Aug 2 1985 08:30 PM              |
| ---     | ---                              |
| `LLLL`  | Thursday, August 2 1985 08:30 PM |
| `llll`  | Thu, Aug 2 1985 08:30 PM         |


id: _docs_writing-guidelines
git_filename: ./_docs/writing-guidelines.md
format: md
data:
{"body": "# Cheatsheet guidelines\n\n## Content organisation\n\n- **Progressive complexity:** Start with basics, move to advanced\n- **Logical sections:** Group related functionality together\n- **H2 and H3:** Organise documents into H2 and H3 sections\n\nH2 content length:\n\n- Short H2s: 2-4 H3s (e.g., \"Installing\", \"Getting started\")\n- Medium H2s: 4-7 H3s (e.g., \"Components\", \"Lifecycle\")  \n- Long H2s: 7+ H3s (use column layouts)\n\nH3 content length:\n\n- Focused: One main concept + examples\n- Consistent: Similar depth within each H2\n- Self-contained: Each H3 should be understandable independently\n\n## Format\n\n- Documentation is in the format of Markdown with Kramdown class extensions\n- H3's can have the following class names:\n  - `{: .-prime}` - Visually highlighted section. Only use once per document at most.\n- PRE elements can have:\n  - `{: .-setup}` - Visually muted section. Used for sections with less importance. Deprecated, use sparingly.\n- H2's can have:\n  - `{: .-three-column}` - use if the H3's are short, and if there are at least 3 H3's in the H2.\n  - `{: .-two-column}` - the default\n\n## Writing guidelines\n\n- Aim for brevity\n- Sentence case headings, never Title Case\n- Omit explanations if they are obvious\n\n## Content priorities\n\n1. **Essential first**: Most commonly used 20% of functionality\n2. **Progressive disclosure**: Basic \u2192 intermediate \u2192 advanced\n3. **Practical examples**: Real-world use cases over theoretical\n4. **Quick reference**: Dense information for experienced developers\n5. **Learning path**: Logical progression for newcomers\n\n## H3 writing guidelines\n\n- Place documentation links in the end. (see next for example)\n- Prefer to write explanations *after* a pre/table. Example:\n\n  ````markdown\n  ### Setting default props\n  \n  ```jsx\n  Hello.defaultProps = {\n    color: 'blue'\n  }\n  ```\n  \n  Default properties are used if no properties are given.\n  \n  See: [defaultProps](https://reactjs.org/docs/react-component.html#defaultprops)\n  ````\n\n- When an example has multiple files, use H4 as filename markers. Example:\n\n  ````markdown\n  ### via Data Attributes\n  \n  #### index.html.erb\n  \n  ```html\n  <a\n    href=\"#\"\n    data-reflex=\"click->CounterReflex#increment\"\n    data-step=\"1\"\n    data-count=\"<%= @count.to_i %>\"\n    >Increment <%= @count.to_i %></a\n  >\n  ```\n  \n  #### counter_reflex.rb\n  \n  ```ruby\n  class CounterReflex < StimulusReflex::Reflex\n    def increment\n      @count = element.dataset[:count].to_i + element.dataset[:step].to_i\n    end\n  end\n  ```\n  \n  Trigger reflexes without writing any javascript with the `data-reflex` attribute.\n  \n  ````\n\n- When showing reference information, use tables for quick scanning. Example:\n\n  ````markdown\n  ### Primitives\n\n  | Sample                  | Type            |\n  | ---                     | ---             |\n  | `nil`                   | Nil/null        |\n  | `true` _/_ `false`      | Boolean         |\n  | ---                     | ---             |\n  | `23`                    | Integer         |\n  | `3.14`                  | Float           |\n  | ---                     | ---             |\n  | `\"hello\"`               | Binary string   |\n  | `:hello`                | Atom            |\n\n  These are the basic data types in Elixir.\n  ````\n\n- Use inline comments to explain results, equivalents, or provide context. Example:\n\n  ````markdown\n  ### Pattern matching\n\n  ```elixir\n  user = %{name: \"Tom\", age: 23}\n  %{name: username} = user  # \u2192 username = \"Tom\"\n  ```\n\n  ### Piping\n\n  ```elixir\n  source\n  |> transform(:hello)     # Step 1: transform the data\n  |> print()               # Step 2: output the result\n  ```\n\n  ```elixir\n  # Same as:\n  print(transform(source, :hello))\n  ```\n\n  ### Type conversions\n\n  ```elixir\n  Integer.parse(\"34\")      # \u2192 {34, \"\"}\n  Float.parse(\"34.1\")      # \u2192 {34.1, \"\"}\n  ```\n  ````\n\n```"}

field_body:
# Cheatsheet guidelines

## Content organisation

- **Progressive complexity:** Start with basics, move to advanced
- **Logical sections:** Group related functionality together
- **H2 and H3:** Organise documents into H2 and H3 sections

H2 content length:

- Short H2s: 2-4 H3s (e.g., "Installing", "Getting started")
- Medium H2s: 4-7 H3s (e.g., "Components", "Lifecycle")  
- Long H2s: 7+ H3s (use column layouts)

H3 content length:

- Focused: One main concept + examples
- Consistent: Similar depth within each H2
- Self-contained: Each H3 should be understandable independently

## Format

- Documentation is in the format of Markdown with Kramdown class extensions
- H3's can have the following class names:
  - `{: .-prime}` - Visually highlighted section. Only use once per document at most.
- PRE elements can have:
  - `{: .-setup}` - Visually muted section. Used for sections with less importance. Deprecated, use sparingly.
- H2's can have:
  - `{: .-three-column}` - use if the H3's are short, and if there are at least 3 H3's in the H2.
  - `{: .-two-column}` - the default

## Writing guidelines

- Aim for brevity
- Sentence case headings, never Title Case
- Omit explanations if they are obvious

## Content priorities

1. **Essential first**: Most commonly used 20% of functionality
2. **Progressive disclosure**: Basic → intermediate → advanced
3. **Practical examples**: Real-world use cases over theoretical
4. **Quick reference**: Dense information for experienced developers
5. **Learning path**: Logical progression for newcomers

## H3 writing guidelines

- Place documentation links in the end. (see next for example)
- Prefer to write explanations *after* a pre/table. Example:

  ````markdown
  ### Setting default props
  
  ```jsx
  Hello.defaultProps = {
    color: 'blue'
  }
  ```
  
  Default properties are used if no properties are given.
  
  See: [defaultProps](https://reactjs.org/docs/react-component.html#defaultprops)
  ````

- When an example has multiple files, use H4 as filename markers. Example:

  ````markdown
  ### via Data Attributes
  
  #### index.html.erb
  
  ```html
  <a
    href="#"
    data-reflex="click->CounterReflex#increment"
    data-step="1"
    data-count="<%= @count.to_i %>"
    >Increment <%= @count.to_i %></a
  >
  ```
  
  #### counter_reflex.rb
  
  ```ruby
  class CounterReflex < StimulusReflex::Reflex
    def increment
      @count = element.dataset[:count].to_i + element.dataset[:step].to_i
    end
  end
  ```
  
  Trigger reflexes without writing any javascript with the `data-reflex` attribute.
  
  ````

- When showing reference information, use tables for quick scanning. Example:

  ````markdown
  ### Primitives

  | Sample                  | Type            |
  | ---                     | ---             |
  | `nil`                   | Nil/null        |
  | `true` _/_ `false`      | Boolean         |
  | ---                     | ---             |
  | `23`                    | Integer         |
  | `3.14`                  | Float           |
  | ---                     | ---             |
  | `"hello"`               | Binary string   |
  | `:hello`                | Atom            |

  These are the basic data types in Elixir.
  ````

- Use inline comments to explain results, equivalents, or provide context. Example:

  ````markdown
  ### Pattern matching

  ```elixir
  user = %{name: "Tom", age: 23}
  %{name: username} = user  # → username = "Tom"
  ```

  ### Piping

  ```elixir
  source
  |> transform(:hello)     # Step 1: transform the data
  |> print()               # Step 2: output the result
  ```

  ```elixir
  # Same as:
  print(transform(source, :hello))
  ```

  ### Type conversions

  ```elixir
  Integer.parse("34")      # → {34, ""}
  Float.parse("34.1")      # → {34.1, ""}
  ```
  ````

```


id: .vscode_launch
git_filename: ./.vscode/launch.json
format: json
data:
{"version": "0.2.0", "configurations": [{"command": "./node_modules/.bin/astro dev", "name": "Development server", "request": "launch", "type": "node-terminal"}]}


id: .github_workflows_build
git_filename: ./.github/workflows/build.yml
format: yaml
data:
{"name": "Run tests", "true": {"push": {"branches": ["main", "master"]}, "pull_request": {"branches": ["main", "master"]}}, "jobs": {"build": {"runs-on": "ubuntu-latest", "steps": [{"uses": "actions/checkout@v4"}, {"uses": "ruby/setup-ruby@v1", "with": {"bundler-cache": true}}, {"uses": "actions/setup-node@v4", "with": {"node-version-file": ".node-version"}}, {"uses": "pnpm/action-setup@v3", "with": {"run_install": false}}, {"name": "Get pnpm store directory", "shell": "bash", "run": "echo \"STORE_PATH=$(pnpm store path --silent)\" >> $GITHUB_ENV\n"}, {"uses": "actions/cache@v4", "name": "Setup pnpm cache", "with": {"path": "${{ env.STORE_PATH }}", "key": "${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}", "restore-keys": "${{ runner.os }}-pnpm-store-\n"}}, {"name": "Install dependencies", "run": "pnpm install --frozen-lockfile"}, {"name": "Install playwright browsers", "run": "pnpm playwright install --with-deps chromium"}, {"name": "Run tests", "run": "pnpm run ci"}]}}}


