diff --git a/README.md b/README.md
index 4553291..3090956 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
# blog.bitbadger.solutions
-[![Build status](https://danieljsummers.visualstudio.com/The%20Bit%20Badger%20Blog/_apis/build/status/The%20Bit%20Badger%20Blog-CI)](https://danieljsummers.visualstudio.com/The%20Bit%20Badger%20Blog/_build/latest?definitionId=4)
+Why are you here? [The blog is over there!](https://bitbadger.solutions/blog) :)
-Why are you here? [The blog is over there!](https://blog.bitbadger.solutions) :)
-
-_(This is the source code repository for the Hexo version of the blog.)_
+_(This is the source code repository for the blog's theme.)_
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index 8502aeb..0000000
--- a/_config.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-# Hexo Configuration
-## Docs: https://hexo.io/docs/configuration.html
-## Source: https://github.com/hexojs/hexo/
-
-# Site
-title: The Bit Badger Blog
-subtitle: Technical Information from Bit Badger Solutions
-description:
-author: Daniel J. Summers
-language: en
-timezone: UTC
-
-# URL
-## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
-url: https://blog.bitbadger.solutions
-root: /
-permalink: :year/:title.html
-permalink_defaults:
-
-# Directory
-source_dir: source
-public_dir: public
-tag_dir: tag
-archive_dir: archives
-category_dir: category
-code_dir: downloads/code
-i18n_dir: :lang
-skip_render:
-
-# Writing
-new_post_name: :year/:title.md # File name of new posts
-default_layout: post
-titlecase: false # Transform title into titlecase
-external_link:
- enable: true # Open external links in new tab
-filename_case: 1
-render_drafts: false
-post_asset_folder: false
-relative_link: false
-future: true
-highlight:
- enable: true
- line_number: true
- auto_detect: false
- tab_replace:
-
-# Home page setting
-# path: Root path for your blogs index page. (default = '')
-# per_page: Posts displayed per page. (0 = disable pagination)
-# order_by: Posts order. (Order by date descending by default)
-index_generator:
- path: ''
- per_page: 6
- order_by: -date
-
-# Category & Tag
-default_category: uncategorized
-category_map:
- C++: c-plus-plus
- C#: c-sharp
- .NET: dot-net
- F#: f-sharp
-tag_map:
- c#: c-sharp
- .net: dot-net
- f#: f-sharp
-
-category_generator:
- per_page: 6
-
-tag_generator:
- per_page: 6
-
-# Date / Time format
-## Hexo uses Moment.js to parse and display date
-## You can customize the date format as defined in
-## http://momentjs.com/docs/#/displaying/format/
-date_format: YYYY-MM-DD
-time_format: HH:mm:ss
-
-# Pagination
-## Set per_page to 0 to disable pagination
-per_page: 10
-pagination_dir: page
-
-# Extensions
-## Plugins: https://hexo.io/plugins/
-## Themes: https://hexo.io/themes/
-theme: bit-badger
-
-# Feed
-feed:
- type: rss2
- path: feed.xml
- limit: 10
- content: true
-
-# Deployment
-## Docs: https://hexo.io/docs/deployment.html
-deploy:
- type:
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index d2e8cc9..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,3979 +0,0 @@
-{
- "name": "techblog-djsconsulting-com",
- "version": "4.2.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "techblog-djsconsulting-com",
- "version": "4.2.0",
- "dependencies": {
- "hexo": "^5.4.0",
- "hexo-generator-category": "^1.0.0",
- "hexo-generator-feed": "^3.0.0",
- "hexo-generator-index": "^2.0.0",
- "hexo-generator-tag": "^1.0.0",
- "hexo-renderer-ejs": "^1.0.0",
- "hexo-renderer-marked": "^4.0.0",
- "hexo-renderer-pug": "^1.0.0",
- "hexo-renderer-stylus": "^2.0.1",
- "hexo-server": "^2.0.0"
- },
- "devDependencies": {
- "pug": "^3.0.2"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
- "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
- },
- "node_modules/@babel/parser": {
- "version": "7.13.10",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz",
- "integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ==",
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
- "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.12.11",
- "lodash": "^4.17.19",
- "to-fast-properties": "^2.0.0"
- }
- },
- "node_modules/a-sync-waterfall": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
- "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="
- },
- "node_modules/abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
- },
- "node_modules/accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
- "dependencies": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/amdefine": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
- "engines": {
- "node": ">=0.4.2"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
- },
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
- },
- "node_modules/assert-never": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz",
- "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw=="
- },
- "node_modules/atob": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
- "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
- "bin": {
- "atob": "bin/atob.js"
- },
- "engines": {
- "node": ">= 4.5.0"
- }
- },
- "node_modules/babel-walk": {
- "version": "3.0.0-canary-5",
- "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
- "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
- "dependencies": {
- "@babel/types": "^7.9.6"
- },
- "engines": {
- "node": ">= 10.0.0"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "node_modules/basic-auth": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
- "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
- "dependencies": {
- "safe-buffer": "5.1.2"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/camel-case": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
- "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
- "dependencies": {
- "pascal-case": "^3.1.2",
- "tslib": "^2.0.3"
- }
- },
- "node_modules/chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/character-parser": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
- "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=",
- "dependencies": {
- "is-regex": "^1.0.3"
- }
- },
- "node_modules/chokidar": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
- "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
- "dependencies": {
- "anymatch": "~3.1.1",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.0",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.5.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.1"
- }
- },
- "node_modules/clipboard": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
- "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
- "optional": true,
- "dependencies": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "node_modules/command-exists": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
- "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
- },
- "node_modules/commander": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
- "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/compressible": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
- "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
- "dependencies": {
- "mime-db": ">= 1.43.0 < 2"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/compression": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
- "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
- "dependencies": {
- "accepts": "~1.3.5",
- "bytes": "3.0.0",
- "compressible": "~2.0.16",
- "debug": "2.6.9",
- "on-headers": "~1.0.2",
- "safe-buffer": "5.1.2",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/compression/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/compression/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "node_modules/connect": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
- "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
- "dependencies": {
- "debug": "2.6.9",
- "finalhandler": "1.1.2",
- "parseurl": "~1.3.3",
- "utils-merge": "1.0.1"
- },
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/connect/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/connect/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/constantinople": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
- "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==",
- "dependencies": {
- "@babel/parser": "^7.6.0",
- "@babel/types": "^7.6.1"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/css": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
- "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
- "dependencies": {
- "inherits": "^2.0.3",
- "source-map": "^0.6.1",
- "source-map-resolve": "^0.5.2",
- "urix": "^0.1.0"
- }
- },
- "node_modules/css-parse": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
- "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs="
- },
- "node_modules/css/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/cuid": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/cuid/-/cuid-2.1.8.tgz",
- "integrity": "sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg=="
- },
- "node_modules/debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
- "optional": true
- },
- "node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
- },
- "node_modules/doctypes": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
- "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk="
- },
- "node_modules/dom-serializer": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
- "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
- "dependencies": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "entities": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
- }
- },
- "node_modules/dom-serializer/node_modules/domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "dependencies": {
- "domelementtype": "^2.1.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/domelementtype": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
- "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ]
- },
- "node_modules/domhandler": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
- "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
- "dependencies": {
- "domelementtype": "^2.0.1"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/domutils": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz",
- "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==",
- "dependencies": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0"
- },
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
- }
- },
- "node_modules/domutils/node_modules/domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "dependencies": {
- "domelementtype": "^2.1.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
- },
- "node_modules/ejs": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
- "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
- "hasInstallScript": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/entities": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
- "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/finalhandler": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
- "dependencies": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.3",
- "statuses": "~1.5.0",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/finalhandler/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/finalhandler/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "node_modules/get-intrinsic": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
- "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/glob": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
- "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.2",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
- "optional": true,
- "dependencies": {
- "delegate": "^3.1.2"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hexo": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/hexo/-/hexo-5.4.0.tgz",
- "integrity": "sha512-4vMDle5GjpMeOVrx0NKoTZCqrmpJVg3wNiNNUVjcoFfcpYcMzQUCZHBtQqLl7BzjJ8x2gs002VQ5yv0ZKtj8Jg==",
- "dependencies": {
- "abbrev": "^1.1.1",
- "archy": "^1.0.0",
- "bluebird": "^3.5.2",
- "chalk": "^4.0.0",
- "hexo-cli": "^4.0.0",
- "hexo-front-matter": "^2.0.0",
- "hexo-fs": "^3.1.0",
- "hexo-i18n": "^1.0.0",
- "hexo-log": "^2.0.0",
- "hexo-util": "^2.4.0",
- "js-yaml": "^4.0.0",
- "micromatch": "^4.0.2",
- "moment": "^2.22.2",
- "moment-timezone": "^0.5.21",
- "nunjucks": "^3.2.1",
- "pretty-hrtime": "^1.0.3",
- "resolve": "^1.8.1",
- "strip-ansi": "^6.0.0",
- "text-table": "^0.2.0",
- "tildify": "^2.0.0",
- "titlecase": "^1.1.2",
- "warehouse": "^4.0.0"
- },
- "bin": {
- "hexo": "bin/hexo"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/hexo"
- }
- },
- "node_modules/hexo-front-matter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-front-matter/-/hexo-front-matter-2.0.0.tgz",
- "integrity": "sha512-IR3tjAyK2Ga/0a/WDAoNy5+n3ju2/mkuAsCDEeGgGLf5+7kkiOkkG/FrnueuYgz0h2MPfWDLBiDsSTCmB0sLCA==",
- "dependencies": {
- "js-yaml": "^3.13.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-front-matter/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/hexo-fs": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-3.1.0.tgz",
- "integrity": "sha512-SfoDH7zlU9Iop+bAfEONXezbNIkpVX1QqjNCBYpapilZR+xVOCfTEdlNixanrKBbLGPb2fXqrdDBFgrKuiVGQQ==",
- "dependencies": {
- "bluebird": "^3.5.1",
- "chokidar": "^3.0.0",
- "graceful-fs": "^4.1.11",
- "hexo-util": "^2.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-generator-category": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-category/-/hexo-generator-category-1.0.0.tgz",
- "integrity": "sha512-kmtwT1SHYL2ismbGnYQXNtqLFSeTdtHNbJIqno3LKROpCK8ybST5QVXF1bZI9LkFcXV/H8ilt8gfg4/dNNcQQQ==",
- "dependencies": {
- "hexo-pagination": "1.0.0"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-generator-feed": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-feed/-/hexo-generator-feed-3.0.0.tgz",
- "integrity": "sha512-Jo35VSRSNeMitS2JmjCq3OHAXXYU4+JIODujHtubdG/NRj2++b3Tgyz9pwTmROx6Yxr2php/hC8og5AGZHh8UQ==",
- "dependencies": {
- "hexo-util": "^2.1.0",
- "nunjucks": "^3.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-generator-index": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-index/-/hexo-generator-index-2.0.0.tgz",
- "integrity": "sha512-q/29Vj9BZs0dwBcF+s9IT8ymS4aYZsDwBEYDnh96C8tsX+KPY5v6TzCdttz58BchifaJpP/l9mi6u9rZuYqA0g==",
- "dependencies": {
- "hexo-pagination": "1.0.0",
- "timsort": "^0.3.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-generator-tag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-tag/-/hexo-generator-tag-1.0.0.tgz",
- "integrity": "sha512-JDoB2T1EncRlyGSjuAhkGxRfKkN8tq0i8tFlk9I4q2L6iYxPaUnFenhji0oxufTADC16/IchuPjmMk//dt8Msg==",
- "dependencies": {
- "hexo-pagination": "1.0.0"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-i18n": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-i18n/-/hexo-i18n-1.0.0.tgz",
- "integrity": "sha512-yw90JHr7ybUHN/QOkpHmlWJj1luVk5/v8CUU5NRA0n4TFp6av8NT7ujZ10GDawgnQEdMHnN5PUfAbNIVGR6axg==",
- "dependencies": {
- "sprintf-js": "^1.0.3"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-log": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-log/-/hexo-log-2.0.0.tgz",
- "integrity": "sha512-U7zdDae74pXcyhQEyNmpJdq3UI6zWKxQ7/zLoMr/d3CBRdIfB5yO8DWqKUnewfibYv0gODyTWUIhxQDWuwloow==",
- "dependencies": {
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-pagination": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-pagination/-/hexo-pagination-1.0.0.tgz",
- "integrity": "sha512-miEVFgxchPr2qNWxw0JWpJ9R/Yaf7HjHBZVjvCCcqfbsLyYtCvIfJDxcEwz1sDOC/fLzYPqNnhUI73uNxBHRSA==",
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-renderer-ejs": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-ejs/-/hexo-renderer-ejs-1.0.0.tgz",
- "integrity": "sha512-O925i69FG4NYO62oWORcPhRZZX0sPx1SXGKUS5DaR/lzajyiXH5i2sqnkj0ya0rNLXIy/D7Xmt7WbFyuQx/kKQ==",
- "dependencies": {
- "ejs": "^2.6.1"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-renderer-marked": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-marked/-/hexo-renderer-marked-4.0.0.tgz",
- "integrity": "sha512-Rc9tPqCEX+UjKhAHF2AmH4FcIqVSW7FTKH6kAhMWAn/WMxrCD3Al+99zKnnbgaLJ6TOCb1ckvB4BRkwk62ITxQ==",
- "dependencies": {
- "hexo-util": "^2.1.0",
- "marked": "^2.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-renderer-pug": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-pug/-/hexo-renderer-pug-1.0.0.tgz",
- "integrity": "sha512-lzTSZvPxInGsYJGpv8Z9TQ0n1ZWI6fuSbtyvRmX5tloWPQNNdBhlDIlOsSc2KYQ28QOGuti8GkJ0wPBqLeKf8A==",
- "dependencies": {
- "pug": "^2.0.1"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/hexo-renderer-stylus": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/hexo-renderer-stylus/-/hexo-renderer-stylus-2.0.1.tgz",
- "integrity": "sha512-1S4AG8RtzWqVrqKIYv2AJ4UYms5SHDjkdYS7IiGwgUejL24agbTktpAbnH2cG1JWZ15SRqYN0UGB9aAoSAgvEA==",
- "dependencies": {
- "nib": "^1.1.2",
- "stylus": "^0.54.8"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-server": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-server/-/hexo-server-2.0.0.tgz",
- "integrity": "sha512-GnxCU0hjepjmqMENcKOKxpzOajb9YrjQczWsZPXU25l5Ze+M9KJLSVljIRFR+ikDRIPDtXaUY2WgYrWPbNEGfg==",
- "dependencies": {
- "bluebird": "^3.5.5",
- "chalk": "^4.0.0",
- "compression": "^1.7.4",
- "connect": "^3.7.0",
- "mime": "^2.4.3",
- "morgan": "^1.9.1",
- "open": "^7.0.0",
- "serve-static": "^1.14.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo-util": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-2.4.0.tgz",
- "integrity": "sha512-IPQvAyn0cznYMU2gskMiZ6LZEvN7wHNusrJoYxrir4f7S7POpZeDTBswiko9R1qqd+/hu07wUYZdm4ceTTCEaA==",
- "dependencies": {
- "bluebird": "^3.5.2",
- "camel-case": "^4.0.0",
- "cross-spawn": "^7.0.0",
- "deepmerge": "^4.2.2",
- "highlight.js": "^10.0.0",
- "htmlparser2": "^4.0.0",
- "prismjs": "^1.17.1",
- "strip-indent": "^3.0.0",
- "striptags": "^3.1.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/hexo/node_modules/hexo-cli": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.2.0.tgz",
- "integrity": "sha512-NJQYKnD41KUlNZzEyi8wDzPeGhrjwLLTa05dtkwq+lJch+j9idZTh4dgn3w/82o6Q/zygn+ibO1XvihMfFdSfw==",
- "dependencies": {
- "abbrev": "^1.1.1",
- "bluebird": "^3.5.5",
- "chalk": "^4.0.0",
- "command-exists": "^1.2.8",
- "hexo-fs": "^3.0.1",
- "hexo-log": "^2.0.0",
- "hexo-util": "^2.0.0",
- "minimist": "^1.2.5",
- "resolve": "^1.11.0",
- "tildify": "^2.0.0"
- },
- "bin": {
- "hexo": "bin/hexo"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/highlight.js": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.6.0.tgz",
- "integrity": "sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/htmlparser2": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
- "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
- "dependencies": {
- "domelementtype": "^2.0.1",
- "domhandler": "^3.0.0",
- "domutils": "^2.0.0",
- "entities": "^2.0.0"
- }
- },
- "node_modules/http-errors": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
- "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
- "dependencies": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/http-errors/node_modules/depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
- "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-docker": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
- "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-expression": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz",
- "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==",
- "dependencies": {
- "acorn": "^7.1.1",
- "object-assign": "^4.1.1"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-plain-object": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
- "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-promise": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
- "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
- },
- "node_modules/is-regex": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
- "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-symbols": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "dependencies": {
- "is-docker": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
- },
- "node_modules/js-stringify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",
- "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds="
- },
- "node_modules/js-yaml": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
- "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/js-yaml/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
- },
- "node_modules/jsonparse": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
- "engines": [
- "node >= 0.2.0"
- ]
- },
- "node_modules/JSONStream": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
- "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
- "dependencies": {
- "jsonparse": "^1.2.0",
- "through": ">=2.2.7 <3"
- },
- "bin": {
- "JSONStream": "bin.js"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/jstransformer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
- "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=",
- "dependencies": {
- "is-promise": "^2.0.0",
- "promise": "^7.0.1"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lower-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
- "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "dependencies": {
- "tslib": "^2.0.3"
- }
- },
- "node_modules/marked": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz",
- "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==",
- "bin": {
- "marked": "bin/marked"
- },
- "engines": {
- "node": ">= 8.16.2"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "dependencies": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/mime": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
- "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/mime-db": {
- "version": "1.46.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
- "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.29",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
- "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
- "dependencies": {
- "mime-db": "1.46.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/min-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
- "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
- },
- "node_modules/mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "dependencies": {
- "minimist": "^1.2.5"
- },
- "bin": {
- "mkdirp": "bin/cmd.js"
- }
- },
- "node_modules/moment": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
- "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/moment-timezone": {
- "version": "0.5.33",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz",
- "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==",
- "dependencies": {
- "moment": ">= 2.9.0"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/morgan": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
- "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
- "dependencies": {
- "basic-auth": "~2.0.1",
- "debug": "2.6.9",
- "depd": "~2.0.0",
- "on-finished": "~2.3.0",
- "on-headers": "~1.0.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/morgan/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/morgan/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "node_modules/negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/nib": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/nib/-/nib-1.1.2.tgz",
- "integrity": "sha1-amnt5AgblcDe+L4CSkyK4MLLtsc=",
- "dependencies": {
- "stylus": "0.54.5"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/nib/node_modules/source-map": {
- "version": "0.1.43",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
- "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
- "dependencies": {
- "amdefine": ">=0.0.4"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/nib/node_modules/stylus": {
- "version": "0.54.5",
- "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
- "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
- "dependencies": {
- "css-parse": "1.7.x",
- "debug": "*",
- "glob": "7.0.x",
- "mkdirp": "0.5.x",
- "sax": "0.5.x",
- "source-map": "0.1.x"
- },
- "bin": {
- "stylus": "bin/stylus"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/no-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
- "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
- "dependencies": {
- "lower-case": "^2.0.2",
- "tslib": "^2.0.3"
- }
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/nunjucks": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz",
- "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
- "dependencies": {
- "a-sync-waterfall": "^1.0.0",
- "asap": "^2.0.3",
- "commander": "^5.1.0"
- },
- "bin": {
- "nunjucks-precompile": "bin/precompile"
- },
- "engines": {
- "node": ">= 6.9.0"
- },
- "peerDependencies": {
- "chokidar": "^3.3.0"
- },
- "peerDependenciesMeta": {
- "chokidar": {
- "optional": true
- }
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/open": {
- "version": "7.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
- "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
- "dependencies": {
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/pascal-case": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
- "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
- "dependencies": {
- "no-case": "^3.0.4",
- "tslib": "^2.0.3"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
- },
- "node_modules/picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pretty-hrtime": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
- "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/prismjs": {
- "version": "1.23.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
- "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
- "optionalDependencies": {
- "clipboard": "^2.0.0"
- }
- },
- "node_modules/promise": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
- "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
- "dependencies": {
- "asap": "~2.0.3"
- }
- },
- "node_modules/pug": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz",
- "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==",
- "dependencies": {
- "pug-code-gen": "^3.0.2",
- "pug-filters": "^4.0.0",
- "pug-lexer": "^5.0.1",
- "pug-linker": "^4.0.0",
- "pug-load": "^3.0.0",
- "pug-parser": "^6.0.0",
- "pug-runtime": "^3.0.1",
- "pug-strip-comments": "^2.0.0"
- }
- },
- "node_modules/pug-attrs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz",
- "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==",
- "dependencies": {
- "constantinople": "^4.0.1",
- "js-stringify": "^1.0.2",
- "pug-runtime": "^3.0.0"
- }
- },
- "node_modules/pug-code-gen": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz",
- "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==",
- "dependencies": {
- "constantinople": "^4.0.1",
- "doctypes": "^1.1.0",
- "js-stringify": "^1.0.2",
- "pug-attrs": "^3.0.0",
- "pug-error": "^2.0.0",
- "pug-runtime": "^3.0.0",
- "void-elements": "^3.1.0",
- "with": "^7.0.0"
- }
- },
- "node_modules/pug-error": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz",
- "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ=="
- },
- "node_modules/pug-filters": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz",
- "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==",
- "dependencies": {
- "constantinople": "^4.0.1",
- "jstransformer": "1.0.0",
- "pug-error": "^2.0.0",
- "pug-walk": "^2.0.0",
- "resolve": "^1.15.1"
- }
- },
- "node_modules/pug-lexer": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz",
- "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==",
- "dependencies": {
- "character-parser": "^2.2.0",
- "is-expression": "^4.0.0",
- "pug-error": "^2.0.0"
- }
- },
- "node_modules/pug-linker": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz",
- "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==",
- "dependencies": {
- "pug-error": "^2.0.0",
- "pug-walk": "^2.0.0"
- }
- },
- "node_modules/pug-load": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz",
- "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==",
- "dependencies": {
- "object-assign": "^4.1.1",
- "pug-walk": "^2.0.0"
- }
- },
- "node_modules/pug-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz",
- "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==",
- "dependencies": {
- "pug-error": "^2.0.0",
- "token-stream": "1.0.0"
- }
- },
- "node_modules/pug-runtime": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz",
- "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg=="
- },
- "node_modules/pug-strip-comments": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz",
- "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==",
- "dependencies": {
- "pug-error": "^2.0.0"
- }
- },
- "node_modules/pug-walk": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz",
- "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ=="
- },
- "node_modules/range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/readdirp": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
- "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
- "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
- "dependencies": {
- "is-core-module": "^2.2.0",
- "path-parse": "^1.0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-url": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
- "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
- "deprecated": "https://github.com/lydell/resolve-url#deprecated"
- },
- "node_modules/rfdc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
- "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
- },
- "node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/sax": {
- "version": "0.5.8",
- "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
- "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
- },
- "node_modules/select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
- "optional": true
- },
- "node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
- "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "~1.7.2",
- "mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "~2.3.0",
- "range-parser": "~1.2.1",
- "statuses": "~1.5.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/send/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/send/node_modules/debug/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/send/node_modules/depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/send/node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
- },
- "node_modules/serve-static": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
- "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
- "dependencies": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.17.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/setprototypeof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/source-map-resolve": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
- "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
- "dependencies": {
- "atob": "^2.1.2",
- "decode-uri-component": "^0.2.0",
- "resolve-url": "^0.2.1",
- "source-map-url": "^0.4.0",
- "urix": "^0.1.0"
- }
- },
- "node_modules/source-map-url": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
- "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
- },
- "node_modules/statuses": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dependencies": {
- "ansi-regex": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-indent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
- "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "dependencies": {
- "min-indent": "^1.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/striptags": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz",
- "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw=="
- },
- "node_modules/stylus": {
- "version": "0.54.8",
- "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
- "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
- "dependencies": {
- "css-parse": "~2.0.0",
- "debug": "~3.1.0",
- "glob": "^7.1.6",
- "mkdirp": "~1.0.4",
- "safer-buffer": "^2.1.2",
- "sax": "~1.2.4",
- "semver": "^6.3.0",
- "source-map": "^0.7.3"
- },
- "bin": {
- "stylus": "bin/stylus"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/stylus/node_modules/css-parse": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
- "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
- "dependencies": {
- "css": "^2.0.0"
- }
- },
- "node_modules/stylus/node_modules/debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/stylus/node_modules/glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/stylus/node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/stylus/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "node_modules/stylus/node_modules/sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "node_modules/stylus/node_modules/source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
- },
- "node_modules/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
- },
- "node_modules/tildify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
- "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/timsort": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
- "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
- },
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
- "optional": true
- },
- "node_modules/titlecase": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/titlecase/-/titlecase-1.1.3.tgz",
- "integrity": "sha512-pQX4oiemzjBEELPqgK4WE+q0yhAqjp/yzusGtlSJsOuiDys0RQxggepYmo0BuegIDppYS3b3cpdegRwkpyN3hw==",
- "bin": {
- "to-title-case": "bin.js"
- }
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/toidentifier": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/token-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
- "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ="
- },
- "node_modules/tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- },
- "node_modules/unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/urix": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
- "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
- "deprecated": "Please see https://github.com/lydell/urix#deprecated"
- },
- "node_modules/utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/void-elements": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
- "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/warehouse": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/warehouse/-/warehouse-4.0.0.tgz",
- "integrity": "sha512-9i6/JiHzjnyene5Pvvl2D2Pd18no129YGy0C0P7x18iTz/SeO9nOBioR64XoCy5xKwBKQtl3MU361qpr0V9uXw==",
- "dependencies": {
- "bluebird": "^3.2.2",
- "cuid": "^2.1.4",
- "graceful-fs": "^4.1.3",
- "is-plain-object": "^3.0.0",
- "JSONStream": "^1.0.7",
- "rfdc": "^1.1.4"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/with": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
- "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
- "dependencies": {
- "@babel/parser": "^7.9.6",
- "@babel/types": "^7.9.6",
- "assert-never": "^1.2.1",
- "babel-walk": "3.0.0-canary-5"
- },
- "engines": {
- "node": ">= 10.0.0"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- }
- },
- "dependencies": {
- "@babel/helper-validator-identifier": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
- "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
- },
- "@babel/parser": {
- "version": "7.13.10",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz",
- "integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ=="
- },
- "@babel/types": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
- "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.12.11",
- "lodash": "^4.17.19",
- "to-fast-properties": "^2.0.0"
- }
- },
- "a-sync-waterfall": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
- "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="
- },
- "abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
- },
- "accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
- "requires": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
- }
- },
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
- },
- "amdefine": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
- },
- "ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
- },
- "assert-never": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz",
- "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw=="
- },
- "atob": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
- "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
- },
- "babel-walk": {
- "version": "3.0.0-canary-5",
- "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
- "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
- "requires": {
- "@babel/types": "^7.9.6"
- }
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "basic-auth": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
- "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
- "requires": {
- "safe-buffer": "5.1.2"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
- },
- "bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "camel-case": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
- "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
- "requires": {
- "pascal-case": "^3.1.2",
- "tslib": "^2.0.3"
- }
- },
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "character-parser": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
- "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=",
- "requires": {
- "is-regex": "^1.0.3"
- }
- },
- "chokidar": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
- "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
- "requires": {
- "anymatch": "~3.1.1",
- "braces": "~3.0.2",
- "fsevents": "~2.3.1",
- "glob-parent": "~5.1.0",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.5.0"
- }
- },
- "clipboard": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
- "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
- "optional": true,
- "requires": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "command-exists": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
- "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
- },
- "commander": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
- "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
- },
- "compressible": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
- "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
- "requires": {
- "mime-db": ">= 1.43.0 < 2"
- }
- },
- "compression": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
- "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
- "requires": {
- "accepts": "~1.3.5",
- "bytes": "3.0.0",
- "compressible": "~2.0.16",
- "debug": "2.6.9",
- "on-headers": "~1.0.2",
- "safe-buffer": "5.1.2",
- "vary": "~1.1.2"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "connect": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
- "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
- "requires": {
- "debug": "2.6.9",
- "finalhandler": "1.1.2",
- "parseurl": "~1.3.3",
- "utils-merge": "1.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "constantinople": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
- "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==",
- "requires": {
- "@babel/parser": "^7.6.0",
- "@babel/types": "^7.6.1"
- }
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "css": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
- "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
- "requires": {
- "inherits": "^2.0.3",
- "source-map": "^0.6.1",
- "source-map-resolve": "^0.5.2",
- "urix": "^0.1.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- }
- }
- },
- "css-parse": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
- "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs="
- },
- "cuid": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/cuid/-/cuid-2.1.8.tgz",
- "integrity": "sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg=="
- },
- "debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
- },
- "deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
- },
- "delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
- "optional": true
- },
- "depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
- },
- "destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
- },
- "doctypes": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
- "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk="
- },
- "dom-serializer": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
- "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "entities": "^2.0.0"
- },
- "dependencies": {
- "domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "requires": {
- "domelementtype": "^2.1.0"
- }
- }
- }
- },
- "domelementtype": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
- "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w=="
- },
- "domhandler": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
- "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
- "requires": {
- "domelementtype": "^2.0.1"
- }
- },
- "domutils": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz",
- "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==",
- "requires": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0"
- },
- "dependencies": {
- "domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "requires": {
- "domelementtype": "^2.1.0"
- }
- }
- }
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
- },
- "ejs": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
- "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
- },
- "encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
- },
- "entities": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
- "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
- },
- "etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "finalhandler": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
- "requires": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.3",
- "statuses": "~1.5.0",
- "unpipe": "~1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "get-intrinsic": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
- "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1"
- }
- },
- "glob": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
- "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.2",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
- "optional": true,
- "requires": {
- "delegate": "^3.1.2"
- }
- },
- "graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
- },
- "hexo": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/hexo/-/hexo-5.4.0.tgz",
- "integrity": "sha512-4vMDle5GjpMeOVrx0NKoTZCqrmpJVg3wNiNNUVjcoFfcpYcMzQUCZHBtQqLl7BzjJ8x2gs002VQ5yv0ZKtj8Jg==",
- "requires": {
- "abbrev": "^1.1.1",
- "archy": "^1.0.0",
- "bluebird": "^3.5.2",
- "chalk": "^4.0.0",
- "hexo-cli": "^4.0.0",
- "hexo-front-matter": "^2.0.0",
- "hexo-fs": "^3.1.0",
- "hexo-i18n": "^1.0.0",
- "hexo-log": "^2.0.0",
- "hexo-util": "^2.4.0",
- "js-yaml": "^4.0.0",
- "micromatch": "^4.0.2",
- "moment": "^2.22.2",
- "moment-timezone": "^0.5.21",
- "nunjucks": "^3.2.1",
- "pretty-hrtime": "^1.0.3",
- "resolve": "^1.8.1",
- "strip-ansi": "^6.0.0",
- "text-table": "^0.2.0",
- "tildify": "^2.0.0",
- "titlecase": "^1.1.2",
- "warehouse": "^4.0.0"
- },
- "dependencies": {
- "hexo-cli": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.2.0.tgz",
- "integrity": "sha512-NJQYKnD41KUlNZzEyi8wDzPeGhrjwLLTa05dtkwq+lJch+j9idZTh4dgn3w/82o6Q/zygn+ibO1XvihMfFdSfw==",
- "requires": {
- "abbrev": "^1.1.1",
- "bluebird": "^3.5.5",
- "chalk": "^4.0.0",
- "command-exists": "^1.2.8",
- "hexo-fs": "^3.0.1",
- "hexo-log": "^2.0.0",
- "hexo-util": "^2.0.0",
- "minimist": "^1.2.5",
- "resolve": "^1.11.0",
- "tildify": "^2.0.0"
- }
- }
- }
- },
- "hexo-front-matter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-front-matter/-/hexo-front-matter-2.0.0.tgz",
- "integrity": "sha512-IR3tjAyK2Ga/0a/WDAoNy5+n3ju2/mkuAsCDEeGgGLf5+7kkiOkkG/FrnueuYgz0h2MPfWDLBiDsSTCmB0sLCA==",
- "requires": {
- "js-yaml": "^3.13.1"
- },
- "dependencies": {
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- }
- }
- },
- "hexo-fs": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-3.1.0.tgz",
- "integrity": "sha512-SfoDH7zlU9Iop+bAfEONXezbNIkpVX1QqjNCBYpapilZR+xVOCfTEdlNixanrKBbLGPb2fXqrdDBFgrKuiVGQQ==",
- "requires": {
- "bluebird": "^3.5.1",
- "chokidar": "^3.0.0",
- "graceful-fs": "^4.1.11",
- "hexo-util": "^2.0.0"
- }
- },
- "hexo-generator-category": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-category/-/hexo-generator-category-1.0.0.tgz",
- "integrity": "sha512-kmtwT1SHYL2ismbGnYQXNtqLFSeTdtHNbJIqno3LKROpCK8ybST5QVXF1bZI9LkFcXV/H8ilt8gfg4/dNNcQQQ==",
- "requires": {
- "hexo-pagination": "1.0.0"
- }
- },
- "hexo-generator-feed": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-feed/-/hexo-generator-feed-3.0.0.tgz",
- "integrity": "sha512-Jo35VSRSNeMitS2JmjCq3OHAXXYU4+JIODujHtubdG/NRj2++b3Tgyz9pwTmROx6Yxr2php/hC8og5AGZHh8UQ==",
- "requires": {
- "hexo-util": "^2.1.0",
- "nunjucks": "^3.0.0"
- }
- },
- "hexo-generator-index": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-index/-/hexo-generator-index-2.0.0.tgz",
- "integrity": "sha512-q/29Vj9BZs0dwBcF+s9IT8ymS4aYZsDwBEYDnh96C8tsX+KPY5v6TzCdttz58BchifaJpP/l9mi6u9rZuYqA0g==",
- "requires": {
- "hexo-pagination": "1.0.0",
- "timsort": "^0.3.0"
- }
- },
- "hexo-generator-tag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-tag/-/hexo-generator-tag-1.0.0.tgz",
- "integrity": "sha512-JDoB2T1EncRlyGSjuAhkGxRfKkN8tq0i8tFlk9I4q2L6iYxPaUnFenhji0oxufTADC16/IchuPjmMk//dt8Msg==",
- "requires": {
- "hexo-pagination": "1.0.0"
- }
- },
- "hexo-i18n": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-i18n/-/hexo-i18n-1.0.0.tgz",
- "integrity": "sha512-yw90JHr7ybUHN/QOkpHmlWJj1luVk5/v8CUU5NRA0n4TFp6av8NT7ujZ10GDawgnQEdMHnN5PUfAbNIVGR6axg==",
- "requires": {
- "sprintf-js": "^1.0.3"
- }
- },
- "hexo-log": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-log/-/hexo-log-2.0.0.tgz",
- "integrity": "sha512-U7zdDae74pXcyhQEyNmpJdq3UI6zWKxQ7/zLoMr/d3CBRdIfB5yO8DWqKUnewfibYv0gODyTWUIhxQDWuwloow==",
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "hexo-pagination": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-pagination/-/hexo-pagination-1.0.0.tgz",
- "integrity": "sha512-miEVFgxchPr2qNWxw0JWpJ9R/Yaf7HjHBZVjvCCcqfbsLyYtCvIfJDxcEwz1sDOC/fLzYPqNnhUI73uNxBHRSA=="
- },
- "hexo-renderer-ejs": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-ejs/-/hexo-renderer-ejs-1.0.0.tgz",
- "integrity": "sha512-O925i69FG4NYO62oWORcPhRZZX0sPx1SXGKUS5DaR/lzajyiXH5i2sqnkj0ya0rNLXIy/D7Xmt7WbFyuQx/kKQ==",
- "requires": {
- "ejs": "^2.6.1"
- }
- },
- "hexo-renderer-marked": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-marked/-/hexo-renderer-marked-4.0.0.tgz",
- "integrity": "sha512-Rc9tPqCEX+UjKhAHF2AmH4FcIqVSW7FTKH6kAhMWAn/WMxrCD3Al+99zKnnbgaLJ6TOCb1ckvB4BRkwk62ITxQ==",
- "requires": {
- "hexo-util": "^2.1.0",
- "marked": "^2.0.0"
- }
- },
- "hexo-renderer-pug": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-pug/-/hexo-renderer-pug-1.0.0.tgz",
- "integrity": "sha512-lzTSZvPxInGsYJGpv8Z9TQ0n1ZWI6fuSbtyvRmX5tloWPQNNdBhlDIlOsSc2KYQ28QOGuti8GkJ0wPBqLeKf8A==",
- "requires": {
- "pug": "^2.0.1"
- }
- },
- "hexo-renderer-stylus": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/hexo-renderer-stylus/-/hexo-renderer-stylus-2.0.1.tgz",
- "integrity": "sha512-1S4AG8RtzWqVrqKIYv2AJ4UYms5SHDjkdYS7IiGwgUejL24agbTktpAbnH2cG1JWZ15SRqYN0UGB9aAoSAgvEA==",
- "requires": {
- "nib": "^1.1.2",
- "stylus": "^0.54.8"
- }
- },
- "hexo-server": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/hexo-server/-/hexo-server-2.0.0.tgz",
- "integrity": "sha512-GnxCU0hjepjmqMENcKOKxpzOajb9YrjQczWsZPXU25l5Ze+M9KJLSVljIRFR+ikDRIPDtXaUY2WgYrWPbNEGfg==",
- "requires": {
- "bluebird": "^3.5.5",
- "chalk": "^4.0.0",
- "compression": "^1.7.4",
- "connect": "^3.7.0",
- "mime": "^2.4.3",
- "morgan": "^1.9.1",
- "open": "^7.0.0",
- "serve-static": "^1.14.1"
- }
- },
- "hexo-util": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-2.4.0.tgz",
- "integrity": "sha512-IPQvAyn0cznYMU2gskMiZ6LZEvN7wHNusrJoYxrir4f7S7POpZeDTBswiko9R1qqd+/hu07wUYZdm4ceTTCEaA==",
- "requires": {
- "bluebird": "^3.5.2",
- "camel-case": "^4.0.0",
- "cross-spawn": "^7.0.0",
- "deepmerge": "^4.2.2",
- "highlight.js": "^10.0.0",
- "htmlparser2": "^4.0.0",
- "prismjs": "^1.17.1",
- "strip-indent": "^3.0.0",
- "striptags": "^3.1.1"
- }
- },
- "highlight.js": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.6.0.tgz",
- "integrity": "sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ=="
- },
- "htmlparser2": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
- "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^3.0.0",
- "domutils": "^2.0.0",
- "entities": "^2.0.0"
- }
- },
- "http-errors": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
- "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "dependencies": {
- "depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
- }
- }
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-core-module": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
- "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-docker": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
- "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw=="
- },
- "is-expression": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz",
- "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==",
- "requires": {
- "acorn": "^7.1.1",
- "object-assign": "^4.1.1"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
- },
- "is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
- },
- "is-plain-object": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
- "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g=="
- },
- "is-promise": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
- "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
- },
- "is-regex": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
- "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-symbols": "^1.0.1"
- }
- },
- "is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "requires": {
- "is-docker": "^2.0.0"
- }
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
- },
- "js-stringify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",
- "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds="
- },
- "js-yaml": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
- "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
- "requires": {
- "argparse": "^2.0.1"
- },
- "dependencies": {
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
- }
- }
- },
- "jsonparse": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
- },
- "JSONStream": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
- "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
- "requires": {
- "jsonparse": "^1.2.0",
- "through": ">=2.2.7 <3"
- }
- },
- "jstransformer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
- "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=",
- "requires": {
- "is-promise": "^2.0.0",
- "promise": "^7.0.1"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "lower-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
- "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "requires": {
- "tslib": "^2.0.3"
- }
- },
- "marked": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz",
- "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw=="
- },
- "micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- }
- },
- "mime": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
- "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
- },
- "mime-db": {
- "version": "1.46.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
- "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="
- },
- "mime-types": {
- "version": "2.1.29",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
- "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
- "requires": {
- "mime-db": "1.46.0"
- }
- },
- "min-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
- "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
- },
- "mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "moment": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
- "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
- },
- "moment-timezone": {
- "version": "0.5.33",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz",
- "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==",
- "requires": {
- "moment": ">= 2.9.0"
- }
- },
- "morgan": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
- "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
- "requires": {
- "basic-auth": "~2.0.1",
- "debug": "2.6.9",
- "depd": "~2.0.0",
- "on-finished": "~2.3.0",
- "on-headers": "~1.0.2"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
- },
- "nib": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/nib/-/nib-1.1.2.tgz",
- "integrity": "sha1-amnt5AgblcDe+L4CSkyK4MLLtsc=",
- "requires": {
- "stylus": "0.54.5"
- },
- "dependencies": {
- "source-map": {
- "version": "0.1.43",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
- "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
- "requires": {
- "amdefine": ">=0.0.4"
- }
- },
- "stylus": {
- "version": "0.54.5",
- "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
- "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
- "requires": {
- "css-parse": "1.7.x",
- "debug": "*",
- "glob": "7.0.x",
- "mkdirp": "0.5.x",
- "sax": "0.5.x",
- "source-map": "0.1.x"
- }
- }
- }
- },
- "no-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
- "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
- "requires": {
- "lower-case": "^2.0.2",
- "tslib": "^2.0.3"
- }
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
- },
- "nunjucks": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz",
- "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
- "requires": {
- "a-sync-waterfall": "^1.0.0",
- "asap": "^2.0.3",
- "commander": "^5.1.0"
- }
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
- },
- "on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1"
- }
- },
- "open": {
- "version": "7.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
- "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
- "requires": {
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1"
- }
- },
- "parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
- },
- "pascal-case": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
- "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
- "requires": {
- "no-case": "^3.0.4",
- "tslib": "^2.0.3"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
- },
- "path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
- },
- "picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
- },
- "pretty-hrtime": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
- "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
- },
- "prismjs": {
- "version": "1.23.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
- "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
- "requires": {
- "clipboard": "^2.0.0"
- }
- },
- "promise": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
- "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
- "requires": {
- "asap": "~2.0.3"
- }
- },
- "pug": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz",
- "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==",
- "requires": {
- "pug-code-gen": "^3.0.2",
- "pug-filters": "^4.0.0",
- "pug-lexer": "^5.0.1",
- "pug-linker": "^4.0.0",
- "pug-load": "^3.0.0",
- "pug-parser": "^6.0.0",
- "pug-runtime": "^3.0.1",
- "pug-strip-comments": "^2.0.0"
- }
- },
- "pug-attrs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz",
- "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==",
- "requires": {
- "constantinople": "^4.0.1",
- "js-stringify": "^1.0.2",
- "pug-runtime": "^3.0.0"
- }
- },
- "pug-code-gen": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz",
- "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==",
- "requires": {
- "constantinople": "^4.0.1",
- "doctypes": "^1.1.0",
- "js-stringify": "^1.0.2",
- "pug-attrs": "^3.0.0",
- "pug-error": "^2.0.0",
- "pug-runtime": "^3.0.0",
- "void-elements": "^3.1.0",
- "with": "^7.0.0"
- }
- },
- "pug-error": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz",
- "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ=="
- },
- "pug-filters": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz",
- "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==",
- "requires": {
- "constantinople": "^4.0.1",
- "jstransformer": "1.0.0",
- "pug-error": "^2.0.0",
- "pug-walk": "^2.0.0",
- "resolve": "^1.15.1"
- }
- },
- "pug-lexer": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz",
- "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==",
- "requires": {
- "character-parser": "^2.2.0",
- "is-expression": "^4.0.0",
- "pug-error": "^2.0.0"
- }
- },
- "pug-linker": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz",
- "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==",
- "requires": {
- "pug-error": "^2.0.0",
- "pug-walk": "^2.0.0"
- }
- },
- "pug-load": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz",
- "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==",
- "requires": {
- "object-assign": "^4.1.1",
- "pug-walk": "^2.0.0"
- }
- },
- "pug-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz",
- "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==",
- "requires": {
- "pug-error": "^2.0.0",
- "token-stream": "1.0.0"
- }
- },
- "pug-runtime": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz",
- "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg=="
- },
- "pug-strip-comments": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz",
- "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==",
- "requires": {
- "pug-error": "^2.0.0"
- }
- },
- "pug-walk": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz",
- "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ=="
- },
- "range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
- },
- "readdirp": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
- "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "resolve": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
- "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
- "requires": {
- "is-core-module": "^2.2.0",
- "path-parse": "^1.0.6"
- }
- },
- "resolve-url": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
- "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
- },
- "rfdc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
- "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "sax": {
- "version": "0.5.8",
- "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
- "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
- },
- "select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
- "optional": true
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- },
- "send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
- "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
- "requires": {
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "~1.7.2",
- "mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "~2.3.0",
- "range-parser": "~1.2.1",
- "statuses": "~1.5.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- },
- "dependencies": {
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
- },
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
- }
- }
- },
- "serve-static": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
- "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
- "requires": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.17.1"
- }
- },
- "setprototypeof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
- },
- "source-map-resolve": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
- "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
- "requires": {
- "atob": "^2.1.2",
- "decode-uri-component": "^0.2.0",
- "resolve-url": "^0.2.1",
- "source-map-url": "^0.4.0",
- "urix": "^0.1.0"
- }
- },
- "source-map-url": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
- "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
- },
- "statuses": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "requires": {
- "ansi-regex": "^5.0.0"
- }
- },
- "strip-indent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
- "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "requires": {
- "min-indent": "^1.0.0"
- }
- },
- "striptags": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz",
- "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw=="
- },
- "stylus": {
- "version": "0.54.8",
- "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
- "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
- "requires": {
- "css-parse": "~2.0.0",
- "debug": "~3.1.0",
- "glob": "^7.1.6",
- "mkdirp": "~1.0.4",
- "safer-buffer": "^2.1.2",
- "sax": "~1.2.4",
- "semver": "^6.3.0",
- "source-map": "^0.7.3"
- },
- "dependencies": {
- "css-parse": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
- "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
- "requires": {
- "css": "^2.0.0"
- }
- },
- "debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- }
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
- },
- "tildify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
- "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw=="
- },
- "timsort": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
- "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
- },
- "tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
- "optional": true
- },
- "titlecase": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/titlecase/-/titlecase-1.1.3.tgz",
- "integrity": "sha512-pQX4oiemzjBEELPqgK4WE+q0yhAqjp/yzusGtlSJsOuiDys0RQxggepYmo0BuegIDppYS3b3cpdegRwkpyN3hw=="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "toidentifier": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
- },
- "token-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
- "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ="
- },
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
- },
- "urix": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
- "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
- },
- "utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
- },
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
- },
- "void-elements": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
- "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk="
- },
- "warehouse": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/warehouse/-/warehouse-4.0.0.tgz",
- "integrity": "sha512-9i6/JiHzjnyene5Pvvl2D2Pd18no129YGy0C0P7x18iTz/SeO9nOBioR64XoCy5xKwBKQtl3MU361qpr0V9uXw==",
- "requires": {
- "bluebird": "^3.2.2",
- "cuid": "^2.1.4",
- "graceful-fs": "^4.1.3",
- "is-plain-object": "^3.0.0",
- "JSONStream": "^1.0.7",
- "rfdc": "^1.1.4"
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "with": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
- "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
- "requires": {
- "@babel/parser": "^7.9.6",
- "@babel/types": "^7.9.6",
- "assert-never": "^1.2.1",
- "babel-walk": "3.0.0-canary-5"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index e000683..0000000
--- a/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "techblog-djsconsulting-com",
- "version": "4.2.0",
- "private": true,
- "hexo": {
- "version": "5.4.0"
- },
- "dependencies": {
- "hexo": "^5.4.0",
- "hexo-generator-category": "^1.0.0",
- "hexo-generator-feed": "^3.0.0",
- "hexo-generator-index": "^2.0.0",
- "hexo-generator-tag": "^1.0.0",
- "hexo-renderer-ejs": "^1.0.0",
- "hexo-renderer-marked": "^4.0.0",
- "hexo-renderer-pug": "^1.0.0",
- "hexo-renderer-stylus": "^2.0.1",
- "hexo-server": "^2.0.0"
- },
- "devDependencies": {
- "pug": "^3.0.2"
- }
-}
\ No newline at end of file
diff --git a/scaffolds/draft.md b/scaffolds/draft.md
deleted file mode 100644
index 498e95b..0000000
--- a/scaffolds/draft.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: {{ title }}
-tags:
----
diff --git a/scaffolds/page.md b/scaffolds/page.md
deleted file mode 100644
index f01ba3c..0000000
--- a/scaffolds/page.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: {{ title }}
-date: {{ date }}
----
diff --git a/scaffolds/post.md b/scaffolds/post.md
deleted file mode 100644
index 1f9b9a4..0000000
--- a/scaffolds/post.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: {{ title }}
-date: {{ date }}
-tags:
----
diff --git a/source/_drafts/.gitkeep b/source/_drafts/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/source/_posts/2004/a-cry-for-help.md b/source/_posts/2004/a-cry-for-help.md
deleted file mode 100644
index d85b815..0000000
--- a/source/_posts/2004/a-cry-for-help.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: post
-title: A Cry for Help
-author: Daniel
-date: 2004-07-07 00:00:38
-categories:
-- [ Linux, My Linux Adventure ]
-summary: The difficulties of downloading things when the network doesn't work
----
-
-I tried a few other things to make that module work, but nothing seemed to help. It's also very difficult to download and try new things when you can't get to the Internet to download them. I also posted a message to the WBEL user's list, and rather than go into that detail, that message can be found [here][].
-
-
-[here]: //beau.org/pipermail/whitebox-users/2004-July/002344.html
diff --git a/source/_posts/2004/a-foray-into-c-plus-plus.md b/source/_posts/2004/a-foray-into-c-plus-plus.md
deleted file mode 100644
index cab70b5..0000000
--- a/source/_posts/2004/a-foray-into-c-plus-plus.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-layout: post
-title: "A Foray into C++"
-author: Daniel
-date: 2004-06-17 00:00:48
-categories:
-- [ Linux, My Linux Adventure ]
-- [ Programming, C++ ]
-summary: A bit of C++ knowledge should help when compiling programs for Linux
----
-
-Compiling my own versions of programs when trying to get DVD stuff working intrigued me. I've tried a couple of times to teach myself C++, but hadn't really gotten that far. My understanding of some of the concepts has improved some, and I've also found a good set of tutorials on [C Programming][]'s web site. I went though the tutorials, and got some interesting things working. This was PC-based, using the [CygWin][] Linux emulator. I actually understood everything I wrote, which is a very nice feeling! This knowledge should come in handy if I ever have trouble compiling something...
-
-
-[C Programming]: //www.cprogramming.com/tutorial.html
-[CygWin]: //www.cygwin.com
diff --git a/source/_posts/2004/a-month-in-summary.md b/source/_posts/2004/a-month-in-summary.md
deleted file mode 100644
index e88930e..0000000
--- a/source/_posts/2004/a-month-in-summary.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: A Month in Summary
-author: Daniel
-date: 2004-08-31 00:00:12
-categories:
-- [ Databases, MySQL ]
-- [ Linux, My Linux Adventure ]
-- [ Web Servers, Apache ]
-- [ Web Servers, IIS ]
-summary: Progress over the past month
----
-
-Well, the last month has been interesting. I was able to get my Windows and Linux installations synchronized by creating a mount point for my second drive under /mnt/drive\_d. Under that, I created a directory called /thunderbird for my e-mail, and moved my e-mail and newsgroup folders over there. (The first time, I missed the "newsrc" file, which is important - it tells what newsgroups you've subscribed to and which messages you've read.) Under Windows, I pointed it to D:\thunderbird\pop3.knology.net, and under Linux, it was configured to /mnt/drive\_d/thunderbird/pop3.knology.net. I then moved the wwwroot directory from C:\Inetpub to drive D:, and pointed IIS to the new location. Under Linux, I did something a little different. As "root", I deleted the directory /var/www/html, and instead created /var/www/html as a symbolic link to /mnt/drive\_d/wwwroot (the actual command is ln -s /mnt/drive\_d/wwwroot /var/www/html). That worked great as well.
-
-MySQL was more complicated, but I was eventually able to get it working as well. I created the directory D:\mysql\data for the data, then configured /etc/my.cnf under Linux to look at /mnt/drive\_d/mysql/data. I kept getting "Could not connect to server using socket /var/lib/mysql/mysql.sock". After some digging, it appeared to be a permissions problem. All the documentation said that the default socket was /tmp/mysql.sock, so I changed my.cnf to point there instead, restarted mysqld, and it worked! So, I have no idea what a Unix socket it, but I know that now I have one! :)
-
-I was also able to get DVDs playing using xine, compiling it myself, and using [libdvdcss][], I can even watch commercial DVDs. I'm really impressed with xine - it handles all kinds of media out of the box, including DivX and up to version 8 of WMV files. You can add codecs to it as well, to support almost anything you want to do from an audio or video perspective. Compiling the player took around 20 minutes, and compiling the front end took another 5. And, it was simple - download the .tar.gz file, do tar xvfz [name].tar.gz, cd [name], ./configure, make install. The ./configure script is the key in the whole process - it looks at what you have installed, and creates make files that will work with your compiler.
-
-Everything started going south, though, when I started having freezes. Eventually, I got to where I could not boot without a kernel panic, and then boot errors (which I detailed in [this e-mail to the WBEL user's list][email]. Encouraged by my success over the past month, I decided to return to WBEL - it's supposed to be more stable than FC2, and I bet that I can get ndiswrapper, the dual-booting web server, the common e-mail, and maybe even some other stuff working again.
-
-
-[libdvdcss]: //developers.videolan.org/libdvdcss/
-[email]: //beau.org/pipermail/whitebox-users/2004-August/003197.html
diff --git a/source/_posts/2004/apache-and-mysql-are-back.md b/source/_posts/2004/apache-and-mysql-are-back.md
deleted file mode 100644
index 19282c0..0000000
--- a/source/_posts/2004/apache-and-mysql-are-back.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-layout: post
-title: Apache and MySQL Are Back
-author: Daniel
-date: 2004-09-08 00:01:50
-categories:
-- [ Databases, MySQL ]
-- [ Linux, My Linux Adventure ]
-- [ Web Servers, Apache ]
-summary: Apache and MySQL work on both sides of the dual-booted computer now
----
-
-I was finally able to resolve my problems with Apache and MySQL. When I decided to mount my FAT32 drive under /home/summersd, I inadvertently caused myself some problems. From talking to a Linux guy at work, I found that no processes that weren't running under my user ID could access those files. The reason is that Linux looks up the entire diretory tree, back to /, to determine if you can access the file. So, although I had -rwxrwxrwx summersd summersd on every file, /home/summersd was drwx------ summersd summersd, and /home was drwxr-xr-x. The permissions on /home/summersd was keeping Apache from seeing /home/summersd/drive\_d/wwwroot, and MySQL from seeing or writing to /home/summersd/drive\_d/mysql/data. I moved the drive to /mnt/drive\_d, with the mount point being owned by "root", still mounting the drive with my user name, and everything worked.
-
-In the process of reconfiguring Thunderbird, I believe I may have found out how to share the address book across operating systems. The file ~/.thunderbird/default.[something]/prefs.js has a listing of all the preferences and settings. I modified this file to change the location of my mail files, and there is a setting there for an address book (which isn't shown in the configuration dialog - after all, it is 0.7.3...) I'll play with that later - right now I'm just elated to have Apache and MySQL working again.
diff --git a/source/_posts/2004/attack-of-the-quadruplicate-messages.md b/source/_posts/2004/attack-of-the-quadruplicate-messages.md
deleted file mode 100644
index 9981df5..0000000
--- a/source/_posts/2004/attack-of-the-quadruplicate-messages.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-layout: post
-title: Attack of the Quadruplicate Messages
-author: Daniel
-date: 2004-06-30 00:00:42
-categories:
-- [ Linux, My Linux Adventure ]
-summary: I don't think I'm supposed to get every e-mail 4 times...
----
-
-When I left for choir practice this evening, I had 2 messages in my inbox. When I returned, I had over 600! Remember way back when I said that I removed that setting that left a copy of the e-mail on the server? Turns out in Ximian Evolution, "Close" is the equivalent of "Cancel" in most apps, and my change did not take. It looks like my ISP's mail server, in an effort to alert me that I was over my limit, started clearing whatever status was on these messages, which caused them to be downloaded multiple times, every 10 minutes. I made sure the setting was set, then went into my ISP's web mail service and deleted every message in my inbox. I deleted all the dupes out of my main inbox tonight, and I'll delete the dupes from the other folders tomorrow.
diff --git a/source/_posts/2004/back-to-wbel.md b/source/_posts/2004/back-to-wbel.md
deleted file mode 100644
index 52763ba..0000000
--- a/source/_posts/2004/back-to-wbel.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-layout: post
-title: Back to WBEL
-author: Daniel
-date: 2004-09-04 00:00:02
-categories:
-- [ Databases, MySQL ]
-- [ Linux, My Linux Adventure ]
-summary: WBEL has been reinstalled
----
-
-Today, I reinstalled WBEL 3.0. I was able to compile ndiswrapper (as I kept that on my FAT32 drive), and get the network card working smoothly very quickly. (In fact, it seems to be more reliable under Linux than WXP!) With the network up, it was easy to download Firefox, Thunderbird, and OpenOffice, and installing them was a breeze. (I decided to put them under /opt this time, trying to stick with the FHS.) I decided to mount my FAT32 drive under my home directory, as `/home/summersd/drive_d`. E-mail works fine, but Apache gives me a 403 (Permission Denied) error. MySQL doesn't seem to be working either - I'll have to play with that later.
diff --git a/source/_posts/2004/downloading-wine.md b/source/_posts/2004/downloading-wine.md
deleted file mode 100644
index 1bf656e..0000000
--- a/source/_posts/2004/downloading-wine.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-layout: post
-title: Downloading Wine
-author: Daniel
-date: 2004-07-01 00:00:08
-categories:
-- [ Linux, My Linux Adventure ]
-summary: Downloading is the first step for installing
----
-
-Today I didn't do a whole lot - I deleted the dupes out of my inbox subfolders, and I downloaded wine. I'll install it tomorrow.
diff --git a/source/_posts/2004/dvds-are-back-and-conflicting-wireless-networks.md b/source/_posts/2004/dvds-are-back-and-conflicting-wireless-networks.md
deleted file mode 100644
index bd96f39..0000000
--- a/source/_posts/2004/dvds-are-back-and-conflicting-wireless-networks.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-layout: post
-title: "DVDs Are Back & Conflicting Wireless Networks"
-author: Daniel
-date: 2004-09-05 00:00:15
-categories:
-- [ Linux, My Linux Adventure ]
-summary: Resolving two minor issues
----
-
-I downloaded xine and xine-ui again, just to get the freshest stuff. Compiled first time, worked first time. I must be learning how to do this stuff! I also did a "yum update" to get the most recent version of everything, and I upgraded ndiswrapper from .8 to .10.
-
-I moved the computer into another room, and found that I was now getting conflicts on my wireless card. After some research, it appears that I'm picking up my next-door-neighbor's wireless signal as well. I renamed our wireless network, and configured the cards to use only that network, and those conflicts went away.
diff --git a/source/_posts/2004/fedora-core-2-in-the-can.md b/source/_posts/2004/fedora-core-2-in-the-can.md
deleted file mode 100644
index 47f2ce9..0000000
--- a/source/_posts/2004/fedora-core-2-in-the-can.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-layout: post
-title: Fedora Core 2 in the Can
-author: Daniel
-date: 2004-07-24 00:00:09
-categories:
-- [ Linux, My Linux Adventure ]
-summary: Fedora Core 2 has been downloaded and is ready to install
----
-
-In an effort to cleanse my wife's computer of the spyware that dogged it so, I removed all the Linux partitions from my computer to make space for files. I got her computer rebuilt, and I'll be starting from scratch when I get back into it. No worries, though - if I'm going to get any good at setting it up... Kind of reminds me of a joke - a guy in New York asks an old man on the street, "Hey, how do you get to Radio City Music Hall?" The old guy responds, "Practice, practice, practice!"
-
-In looking toward renewed Linux experimentation, I downloaded the .ISO files for FC2. I'm going to start with that, and see if I have any better luck getting my network card to work.
diff --git a/source/_posts/2004/foobar2000-with-wine.md b/source/_posts/2004/foobar2000-with-wine.md
deleted file mode 100644
index 9b89f61..0000000
--- a/source/_posts/2004/foobar2000-with-wine.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: post
-title: foobar2000 with Wine
-author: Daniel
-date: 2004-09-08 00:00:47
-categories:
-- [ Linux, My Linux Adventure ]
-summary: A nice, lightweight Windows audio player working under wine
----
-
-[foobar2000][] is about the best, most organized audio player I've found. However, it is a Windows application, and according to what I've read, very reliant on Microsoft C++ extensions. I decided to give it a shot under wine, and it works great! There is a repaint problem - sometimes the playlist doesn't refresh as it should. But, it's pretty much a start-and-minimize sort of application, so that's acceptable.
-
-
-[foobar2000]: //www.foobar2000.org
diff --git a/source/_posts/2004/linux-play-on-pause.md b/source/_posts/2004/linux-play-on-pause.md
deleted file mode 100644
index a834835..0000000
--- a/source/_posts/2004/linux-play-on-pause.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-layout: post
-title: Linux Play on Pause
-author: Daniel
-date: 2004-07-10 00:00:18
-categories:
-- General Info
-- [ Linux, My Linux Adventure ]
-summary: Resignation to running Windows XP for a while
----
-
-With my inability to get my network working, I have resigned myself to running WXP. Work is starting to get really busy, and my personal life is as well. Maybe at some point in the future I can fire things back up and play some more.
diff --git a/source/_posts/2004/ndiswrapper-may-have-issues.md b/source/_posts/2004/ndiswrapper-may-have-issues.md
deleted file mode 100644
index 035d16f..0000000
--- a/source/_posts/2004/ndiswrapper-may-have-issues.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: post
-title: ndiswrapper May Have Issues
-author: Daniel
-date: 2004-09-07 00:00:49
-categories:
-- Hardware
-- [ Linux, My Linux Adventure ]
-summary: Wireless drivers don't handle the lack of a wireless network very gracefully
----
-
-We're speedily working towards a Friday deadline at work, so tonight I had some analysis work to do on some COBOL code. Great, I thought, I can use my VSlick setup under wine. I moved my computer from the living room back to our now-empty bedroom (soon to be nursery), and booted it up. Kernel panics galore - never got past the network stuff. When I booted to Windows, I found that the wireless network didn't reach that far, and I'm guessing that the ndiswrapper folks haven't tried their driver a lot with a wireless card, but no wireless network. Once I get past that, I may grab the dumps from these kernel panics and see if the developers need them to see what went wrong. So, for tonight, I had to use WXP (in which I actually had to disable the wireless connection - seems Windows doesn't handle a barely-there wireless connection much better than Linux).
-
-The diagnostics I ran last night never found anything - they ran for about 10 hours. I suppose I'll just have to wait until I have problems again, then run it right then. Another person from the WBEL users list suggested I check the way I have my hard drives set up; he thinks that a 2GB drive slaved to a 20GB drive may be causing conflicts, which would cause freezes or panics.
diff --git a/source/_posts/2004/next-generation-open-source-internet-apps.md b/source/_posts/2004/next-generation-open-source-internet-apps.md
deleted file mode 100644
index cb459a1..0000000
--- a/source/_posts/2004/next-generation-open-source-internet-apps.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-layout: post
-title: Next-Generation Open Source Internet Apps
-author: Daniel
-date: 2004-07-12 00:00:11
-categories:
-- Windows Open Source
-summary: Firefox and Thunderbird
----
-
-In setting up my "I'm gonna use this for a while" environment on WXP, I've stumbled across what I feel are two gems. These are the [FireFox][] browser (which I've been using for a while now) and the [Thunderbird][] mail program. Thunderbird is not as fully featured as Ximian Evolution, but I prefer it's interface to that of Mozilla Mail. I also think that once I get back on Linux on a regular basis, I'll install the same version there, and see if I can get my mail to use the same data files whether I'm using Linux or WXP.
-
-
-[FireFox]: //www.mozilla.org/products/firefox
-[Thunderbird]: //www.mozilla.org/products/thunderbird
diff --git a/source/_posts/2004/non-alcoholic-wine-experiments.md b/source/_posts/2004/non-alcoholic-wine-experiments.md
deleted file mode 100644
index 2880648..0000000
--- a/source/_posts/2004/non-alcoholic-wine-experiments.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-layout: post
-title: Non-Alcoholic Wine Experiments
-author: Daniel
-date: 2004-07-02 00:00:27
-categories:
-- [ Linux, My Linux Adventure ]
-summary: First efforts with wine leave me unimpressed
----
-
-Wine is not getting me drunk. I installed it, downloaded and installed [WineSetupTK][] to assist with configuration. I then ran the setup program (through wine) for _Thomas the Tank Engine: The Great Festival Adventure_. Once that completed, I tried to run the program (by entering `wine "C:\Program Files\Hasbro Interactive\The Great Festival Adventure\thomas.exe"`) and got a message box saying "CD check path not found." I searched the web for this message, and didn't find anything - it may be a message from the game, and not wine. I'll do some digging later.
-
-You may remember the problems I had with the Folding@Home client. So, I decided to try to run the Windows version through wine. I downloaded it, and ran it through wine. It took about 2 minutes to lock my machine up. I'm not being too hard on wine for this stuff - an emulator isn't going to be 100%. I am concerned that I don't seem to be able to run any sort of Folding@Home client, and since it's not open-source, I can't try compiling on this computer.
-
-I uninstalled the OpenOffice.org suite from the /root directory, and installed it in `/usr/local/OpenOffice.org1.1.2` (which was where it suggested). Now, it works for normal users. I still haven't been able to resolve my printing problems, but I sent a question today to the WBEL users list - they came through quickly for helping me resolve my mail importing issues.
-
-
-[WineSetupTK]: //sourceforge.net/project/showfiles.php?group_id=6241&package_id=77479&release_id=161192
diff --git a/source/_posts/2004/power-at-last.md b/source/_posts/2004/power-at-last.md
deleted file mode 100644
index a062034..0000000
--- a/source/_posts/2004/power-at-last.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-layout: post
-title: Power at Last!
-author: Daniel
-date: 2004-06-25 00:00:33
-categories:
-- Hardware
-- [ Linux, My Linux Adventure ]
-summary: The power supply arrives, but a background program is locking the machine up hard
----
-
-Upon returning from vacation, I found that the power supply was finally here. After installing it, I fired up the computer, and it works! I fired up my e-mail client (to pull all the mail off the server that I had received for the past few weeks), and downloaded the [Folding@Home][] (F@H) client for Linux. I've been running that on a couple of other computers (user name LX_i, team #37825), and I'll probably write more about it in particular in my regular blog. Anyway, once I got that started, I started reading the e-mail I had missed. Then, the machine locked up!
-
-I reset the machine, and repeated the steps (started Evolution, started F@H), and before long, it happened again. I restarted them both again, but it's getting late - I'll have to continue this tomorrow.
-
-
-[Folding@Home]: //www.stanford.edu/group/pandegroup/folding/
diff --git a/source/_posts/2004/power-on-order-vacation-pending.md b/source/_posts/2004/power-on-order-vacation-pending.md
deleted file mode 100644
index 5239aca..0000000
--- a/source/_posts/2004/power-on-order-vacation-pending.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-layout: post
-title: "Power on Order / Vacation Pending"
-author: Daniel
-date: 2004-06-16 00:00:32
-categories:
-- General Info
-- Hardware
-- [ Linux, My Linux Adventure ]
-summary: Power supply inbound
----
-
-The power supply has been ordered, but I'm going out of town between the 19th and the 26th, so it probably won't make it here before I leave. This adventure will have to resume at that point.
diff --git a/source/_posts/2004/printing-woes-and-e-mail-happiness.md b/source/_posts/2004/printing-woes-and-e-mail-happiness.md
deleted file mode 100644
index 8253dd0..0000000
--- a/source/_posts/2004/printing-woes-and-e-mail-happiness.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-layout: post
-title: "Printing Woes & E-mail Happiness"
-author: Daniel
-date: 2004-06-29 00:00:42
-categories:
-- [ Linux, My Linux Adventure ]
-summary: Printing is a challenge, but e-mail is working great
----
-
-Printing is proving to be a challenge. Using [samba][] (the Linux [SMB][] libraries) and [cups][], I was able to configure my networked printer. However, I don't have a driver on my computer for it. I tried using some drivers that were close, but they didn't work - they just caused the printer to eject a blank page. I was creating the documents using [OpenOffice.org][]'s Writer, which has a "one-click PDF conversion" feature. When I went to use that feature, I found that I was on version 1.0, which didn't have the PDF stuff.
-
-I downloaded the Linux install for version 1.1.2, and remembering that you need to use the "root" user to do most installs, did an [su][], and ran the install. I then launched the new writer and exported the PDF. Using samba, I copied the file over to the other computer, and was able to print it. However, since I installed it as root, it installed under /root, which meant that my normal user couldn't access it. At some point, I'll uninstall it and reinstall it in a public directory.
-
-On another note, I posted a message about my inability to import mail from Netscape into Evolution to the WBEL user's list, and the response I got worked! Netscape actually stores the e-mail in the same format as many other Linux e-mail programs (a format called [mbox][] format). Using samba, I copied the files from "C:\Documents and Settings\Daniel\ApplicationData\Mozilla\Profiles\default\{somthing}.slt\Mail\Local Folders" - under this folder, there was a separate folder for each [POP3][] account, and within that folder, the file called "inbox" was my inbox. On some systems, the file is named "mbox", and it's in a folder with the name of the folder it represents (i.e., "Inbox/mbox"). Once these files were copied, I used Evolution's import utility - it prompted me for a file to import (whose type it determined automatically), and a location for the messages to go. I now have all my e-mail from my old setup!
-
-One part of Unix/Linux of which I'm quickly becoming a fan is its adherance to the [Filesystem Hierarchy Standard][fhs] (FHS). The FHS defines where files should be found, and it represents all available files under a single directory, known as "/". No matter how many drives or network shares that are [mounted][], they're all under this directory. What this gives you is a system-wide view of your files, instead of the normal DOS-imposed separate drive specifications. The FHS also says what files are supposed to be in what directories, so no matter what Unix/Linux system you're using, once you know the FHS, you know exactly where to look for things.
-
-
-[samba]: //us1.samba.org/samba/samba.html
-[SMB]: //www.computerhope.com/jargon/s/smb.htm
-[cups]: //www.cups.org
-[OpenOffice.org]: //www.openoffice.org
-[su]: //hegel.ittc.ukans.edu/topics/linux/man-pages/man1/su.1.html
-[mbox]: //email.about.com/cs/standards/a/mbox_format.htm
-[POP3]: //www.computerhope.com/jargon/p/pop.htm
-[fhs]: //www.pathname.com/fhs/
-[mounted]: //www.computerhope.com/jargon/m/mount.htm
diff --git a/source/_posts/2004/programming-like-a-banshee.md b/source/_posts/2004/programming-like-a-banshee.md
deleted file mode 100644
index 2bc3c78..0000000
--- a/source/_posts/2004/programming-like-a-banshee.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-layout: post
-title: Programming Like a Banshee
-author: Daniel
-date: 2004-06-27 00:00:32
-categories:
-- [ Linux, My Linux Adventure ]
-- [ Programming, PHP ]
-sumary: Programming work has been distracting from Linux adventures
----
-
-Despite being ill early in the day (which caused me to miss Sunday School and church), the day on the computer went pretty well. I made a lot more progress on TMTS, although I ran into a problem - it appears that the [PHP][] that came with WBEL may not have [MySQL][] support enabled. Rather than get sidelined with this right now, I'm going to continue converting pages on the application, and work this issue as part of unit testing.
-
-I also managed to catch up on comp.lang.cobol and comp.sys.unisys, two newsgroups in which I participate. I was able to play a file off a DVD (although I still can't play the disc itself).
-
-
-[PHP]: //www.php.net
-[MySQL]: //www.mysql.com
diff --git a/source/_posts/2004/running-out-of-browsers.md b/source/_posts/2004/running-out-of-browsers.md
deleted file mode 100644
index b6979cb..0000000
--- a/source/_posts/2004/running-out-of-browsers.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: Running Out of Browsers...
-author: Daniel
-date: 2004-06-26 00:00:01
-categories:
-- [ Linux, My Linux Adventure ]
-- [ Programming, PHP ]
-summary: Browser lock-ups are leaving them in an unusable state
----
-
-When I moved the mouse to try to get the screen to unblank this morning, nothing happened. It was locked up once again. I decided to only run one process, to see if I could isolate which one was causing me problems. I started with the F@H client. I started it before we left for breakfast, and when we got back, the computer was still running okay. I started using the computer actively, and found another problem - my profile for Firefox now thinks it's still in use, because I was using it when the machine crashed.
-
-Now, anyone who has ever used Linux will know that one browser is much less severe than, for example, IE becoming unusable in a Windows evironment. I switched to using Mozilla, and was doing some research on Linux crashes when the machine locked up again. This time, when I restarted, both Firefox _and_ Mozilla thought they were still in use. I fired up the only other currently-installed browser, Konqueror, and surfed out to [LinuxQuestions.org][] and posted a message asking how to tell these browsers that they're not in use.
-
-A few hours later, an answer appeared. For Firefox, the file is ~/.mozilla/firefox/default.lz7/lock, and for Mozilla, the file is ~/.mozilla/default/{something}.slt/lock. Both these are symbolic links to a process PID - deleting them freed up the default profiles so these browsers could be used again.
-
-In the mean time, I have not restarted F@H, but I've had Evolution running in the background without incident. It seems that it may be the F@H client. That bugs me, because I was really looking forward to using this machine to help with the project. I may try to run the Windows version under [wine][], a Windows emulator for Linux.
-
-Some folks have also expressed interest in the Tournament and Membership Tracking System (TMTS), which is a web application I coded to track membership and golf tournaments for a local golfing organization. They're interested in the PHP version, for which I no longer have the source code (it was on a laptop that was stolen). So, much of my computing effort over the next few days will be trying to get this recreated. Today, I was able to get the database rebuilt, and the first few pages converted.
-
-
-[LinuxQuestions.org]: //www.linuxquestions.org
-[wine]: //www.winehq.com
diff --git a/source/_posts/2004/satisfying-a-lust-for-power.md b/source/_posts/2004/satisfying-a-lust-for-power.md
deleted file mode 100644
index b74bb14..0000000
--- a/source/_posts/2004/satisfying-a-lust-for-power.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-layout: post
-title: Satisfying a Lust for Power
-author: Daniel
-date: 2004-06-15 00:00:48
-categories:
-- Hardware
-- [ Linux, My Linux Adventure ]
-summary: A new (inexpensive) power supply has been found
----
-
-Searching for power supplies was very interesting. I determined that I needed at least a 300W supply, and considered upgrading case and all. Some of the bigger stores, such as [Best Buy][], [Office Depot][], and [OfficeMax][], revealed nothing under $30 (just for the power supply). I checked some other sites, such as [Tiger Direct][] and [TCWO][], and found one for $17 on Tiger Direct. I thought that was pretty good, and was planning on ordering it, when a friend (the person I bought the computer from) found one on [PC Direct Source][] for $10. I'll probably order it tomorrow.
-
-
-[Best Buy]: //www.bestbuy.com
-[Office Depot]: //www.officedepot.com
-[OfficeMax]: //www.officemax.com
-[Tiger Direct]: //www.tigerdirect.com
-[TCWO]: //www.tcwo.com
-[PC Direct Source]: //www.pcdirectsource.com
diff --git a/source/_posts/2004/sour-milk-is-right.md b/source/_posts/2004/sour-milk-is-right.md
deleted file mode 100644
index 8a176ce..0000000
--- a/source/_posts/2004/sour-milk-is-right.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-layout: post
-title: "Sour Milk Is Right!"
-author: Daniel
-date: 2004-07-08 00:00:09
-categories:
-- [ Linux, My Linux Adventure ]
-summary: A lead on a wireless driver doesn't work on my kernel
----
-
-A user wrote back and suggested that I try a driver from [SourMilk.net][], which is an "adm8211" driver project for Linux. When I downloaded it and started to compile it, I quickly became aware that it hoped I was on the 2.6 family of kernels (which is what the Fedora Project, and several of the newer distributions, are now using). WBEL 3.0 uses the 2.4 kernel, which is more established, but is beginning to drop off as most folks start developing for 2.6. Anyway, there was a 2.4 make file, but it was labeled "experimental."
-
-That pretty much describes how I spent my time this evening - experimenting. I have virtually no experience with large-scale C projects, and I got many, many compile errors. I tried tweaking the make file, to no avail. I don't fault the driver, as it said up front that it is really targeted to 2.6. I may end up downloading a 2.6 distribution and trying it out.
-
-
-[SourMilk.net]: //aluminum.sourmilk.net/adm8211/
diff --git a/source/_posts/2004/success-with-wine-and-diagnostics.md b/source/_posts/2004/success-with-wine-and-diagnostics.md
deleted file mode 100644
index a59375a..0000000
--- a/source/_posts/2004/success-with-wine-and-diagnostics.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: post
-title: "Success with Wine & Diagnostics"
-author: Daniel
-date: 2004-09-05 00:01:51
-categories:
-- [ Databases, MySQL ]
-- Hardware
-- [ Linux, My Linux Adventure ]
-- [ Web Servers, Apache ]
-summary: Some success and more troubleshooting
----
-
-At work, we use an editor called [Visual SlickEdit][] (VSlick). It's got a lot of features, and supports color-coding for many different languages. I decided that I'd give wine another shot, as we only have the Windows version of this program. I installed wine and winesetuptk, used winesetuptk to configure the installation, then ran the installation program. Everything installed, and the program ran up to a point, when it started complaining about a missing DLL. I booted to WXP, found the DLL, copied it to the FAT32 drive, rebooted to Linux, and copied the DLL into the "fake windows" system directory. Soon, it was working great! I can't believe it - success with wine!
-
-I also have made little headway towards getting Apache and MySQL to working. I changed the process that Apache uses to run as "summersd", and I was able to see pages (although any pages that relied on a database didn't work). I still haven't figured this one out yet...
-
-I'm still getting kernel panics from time to time, and it seems to be whenever I access networking. A suggestion from one of the folks on the WBEL users list was to download the [Ultimate Boot CD][ubcd], filled with diagnostic programs. I downloaded it, burned it, and ran some memory checks. Those checked out, so I'm going to run a "CPU Burn-In" program to see if it can detect errors from the CPU. It runs for up to 7 days, but I think I'll just run it overnight - folding@home didn't take nearly that long to crash it before.
-
-
-[Visual SlickEdit]: //www.slickedit.com
-[ubcd]: //www.ultimatebootcd.com
diff --git a/source/_posts/2004/webshots-wine-strikes-again.md b/source/_posts/2004/webshots-wine-strikes-again.md
deleted file mode 100644
index 51950fb..0000000
--- a/source/_posts/2004/webshots-wine-strikes-again.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-layout: post
-title: Webshots - Wine Strikes Again!
-author: Daniel
-date: 2004-09-10 00:00:29
-categories:
-- [ Linux, My Linux Adventure ]
-summary: Using wine to use Webshots
----
-
-When I ran Windows as my desktop, I had a program called [WebShots][] that I used to set my desktop wallpaper, and cycle it. They have Windows and Mac versions, but no Linux version yet. They still send me e-mails each week, showing the daily picture selections for each day in the past week. I decided to download the Windows version, and install in under wine to see if it would work. I moved `websamp.exe` to `/home/summersd/.wine/fake_windows`, then ran `wine C:\\websamp.exe` to install the program. `wine "C:\\Program Files\\Webshots\\Launcher.exe"` then started the desktop control. I used that to disable the tray icon (wine has one, but you can't see it), and I disabled almost every other "auto update" feature.
-
-I had downloaded a ".wbz" file (which is what is imported into WebShots), and I finally figured out how to import it. Running the launcher program, and following it with the name of the .wbz file, imports it. I may figure out a way to automate that, but for now, I know how to do it.
-
-_(Note: This is the end of the "My Linux Adventure" series of posts. After this, I ended up going back to Windows XP, just because it worked and I didn't have hobbyist time. As of May 2007, I'm running Ubuntu 7.04 on one computer, and Windows Vista on my laptop, which is currently out of commission.)_
-
-
-[WebShots]: //www.webshots.com
diff --git a/source/_posts/2004/when-hardware-attacks.md b/source/_posts/2004/when-hardware-attacks.md
deleted file mode 100644
index b5936f8..0000000
--- a/source/_posts/2004/when-hardware-attacks.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-layout: post
-title: When Hardware Attacks
-author: Daniel
-date: 2004-06-14 00:00:22
-categories:
-- Hardware
-- [ Linux, My Linux Adventure ]
-summary: A bad power supply interrupts our plans
----
-
-I fired up the computer today while I was at home for lunch. I booted it into Windows so my younger son could play a game. When I came home from work, I noticed that the computer was off. Seems that it just completely shut down while he was in the middle of the game. After some hardware troubleshooting, I narrowed the problem down to the power supply. Time to go power-supply hunting...
diff --git a/source/_posts/2004/wireless-woes.md b/source/_posts/2004/wireless-woes.md
deleted file mode 100644
index e5ab955..0000000
--- a/source/_posts/2004/wireless-woes.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: post
-title: Wireless Woes
-author: Daniel
-date: 2004-07-06 00:00:19
-categories:
-- [ Linux, My Linux Adventure ]
-summary: First attempts at a wireless adapter fail spectacularly
----
-
-My wife bought me a wireless network card, so I could move the second computer out of the living room (or, as she calls it, "not a computer lab!"). :) Everything works okay under WXP, but when I boot to Linux, no joy. (I sort of expected that, at this point...) I downloaded the Red Hat 8 drivers from [iBlitzz's website][ib], but the interface for a network card is what's called a "kernel module," which is, as best I can tell, a highly-specialized object module that tells the kernel all the details of the hardware. At any rate, the kernel module is very much tied to a particular version of kernel, so the RH8 doesn't seem to be working. Oh well - time to play with my new toy - WXP for now.
-
-
-[ib]: //www.iblitzz.com
diff --git a/source/_posts/2004/wow.md b/source/_posts/2004/wow.md
deleted file mode 100644
index 20607a0..0000000
--- a/source/_posts/2004/wow.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: post
-title: Wow
-author: Daniel
-date: 2004-08-01 00:00:34
-categories:
-- [ Databases, MySQL ]
-- [ Linux, My Linux Adventure ]
-- [ Programming, PHP ]
-- [ Web Servers, Apache ]
-- [ Web Servers, IIS ]
-summary: Fedora Core 2 makes a nice first impression
----
-
-Today I installed Fedora Core 2. This thing is slick! WBEL looked a lot like RH8, which I had seen before my renewed Linux learning began. FC2 has a graphical loader that hides a lot of the background stuff (unless an error occurs) - that's cool. During the install, I skipped OpenOffice.org and MySQL, although I installed PHP with MySQL support. The reason for that is that I wanted to get the latest and greatest versions of those two products. We'll see if this proves to be a good decision or not.
-
-The wireless network card still wasn't recognized (phooey). I did some more searching, armed with the knowledge that I have an adm8211 chipset. One of the first hits under Google's Linux search for "adm8211" pointed me to a project called [NDISwrapper][]. This is a "wrapper" that uses the vendor's Windows DLL file, and converts the hooks from Windows to Linux. Doing this, this driver can (in theory) support most any network card, especially those that aren't in the Linux Hardware Compatibility List (HCL). I downloaded it, compiled it, and followed the directions to install my driver under it. I still wasn't able to create a connection, but on a hunch, I restarted the computer. NDISwrapper is also a kernel module, and I know that often those are only read at startup. Once the computer was restarted, I was able to create a connection, and now my network card works! YEA!!! (And it was only one night's worth of work - much better.)
-
-Now that I have networking working under both operating systems, I plan to try to get four things working the same, whether I'm booted to WXP or Linux - E-mail (using Mozilla Thunderbird), PHP (using Apache on Linux, IIS on WXP), MySQL (using the exact same version on both), and a web server that uses the same html root directory (again, Apache on Linux, IIS on WXP). If I didn't already have IIS up, running, and configured under WXP, I'd probably just do Apache on both, but this will be interesting - it should work, as I don't have many creative permission rules.
-
-
-[NDISwrapper]: //ndiswrapper.sourceforge.net
diff --git a/source/_posts/2004/yum-yum-yum.md b/source/_posts/2004/yum-yum-yum.md
deleted file mode 100644
index 5146792..0000000
--- a/source/_posts/2004/yum-yum-yum.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: post
-title: yum yum yum
-author: Daniel
-date: 2004-06-28 00:00:06
-categories:
-- [ Linux, My Linux Adventure ]
-summary: 'The "yum" updater works nicely'
----
-
-I wasn't able to sleep very well last night, so I didn't do much tonight. One thing I did do, though, was run [yum][], which is, at a high-level, similar to Windows Update. WBEL recently released "Respin 1" (that's re-spin, not a new name - it's code name is still "Liberation"), and running yum with no options will update every available package. After about 30 minutes of watching it download stuff, I went to bed - I'll have to verify the results tomorrow.
-
-
-[yum]: //linux.duke.edu/projects/yum/
diff --git a/source/_posts/2005/about-the-xine-rpms.md b/source/_posts/2005/about-the-xine-rpms.md
deleted file mode 100644
index 5b9dae7..0000000
--- a/source/_posts/2005/about-the-xine-rpms.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-layout: post
-title: About the xine RPMs
-author: Daniel
-date: 2005-06-02 00:01:00
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-summary: Information about how xine RPMs are built
----
-
-_(This post is updated regularly, and should contain the most up-to-date information about these RPMs.)_
-
-Xine is a full-featured media player for Linux, that can play CDs, DVDs, VCDs, MP3s, Ogg, and more. The main site for xine is [www.xine-project.org][] - you can find information, install instructions, and more user interfaces. These RPMs should work on White Box Enterprise Linux (WBEL), Red Hat Enterprise Linux (RHEL), and CentOS. To stay up-to-date on these releases, you can subscribe to the [RSS feed][] for this category.
-
-_As with any standard disclaimer, no warranty is expressed or implied - these RPMs are provided as-is, and we assume no responsibility for any ill effects that may come from the downloading and installation of these files. However, feedback is welcome if you encounter problems with these RPMs._
-
-**Note:** To use xine, you'll need both the library and the UI. To play commercial DVDs, you'll need libdvdcss, which is not provided here (but, knowing the name, you should be able to find it).
-
-### How the RPMs Were Built
-
-xine-ui 0.99.9 to current / xine-lib 1.2.6 to current / gxine 0.5.908 to current
-_These RPMs were built on Ubuntu Trusty Tahr (kernel 3.13.0-34-generic) as deb packages and converted to RPM using alien._
-
-xine-ui 0.99.8
-_These RPMs were built on Ubuntu Saucy Salamander (kernel 3.11.0-17-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.21 / xine-ui 0.99.7
-_These RPMs were built on Ubuntu Precise Pangolin (kernel 3.0.0-24-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.20.1
-_These RPMs were built on Ubuntu Oneiric Ocelot (kernel 3.0.0-14-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.20
-_These RPMs were built on Ubuntu Oneiric Ocelot (kernel 3.0.0-12-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.19 / xine-ui 0.99.6
-_These RPMs were built on Ubuntu Lucid Lynx (kernel 2.6.32-24-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.16.2 and xine-lib 1.1.16.3
-_These RPMs were built on Ubuntu Intrepid Ibex (kernel 2.6.27-11-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.16.1
-_These RPMs were built on Ubuntu Intrepid Ibex (kernel 2.6.27-9-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.13 through 1.1.15
-_These RPMs were built on Ubuntu Hardy Herron (kernel 2.6.24-19-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.9.1 and 1.1.10.1
-_These RPMs were built on Ubuntu Gutsy Gibbon (kernel 2.6.22-14-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.7 / xine-ui 0.99.5
-_These RPMs were built on Ubuntu Feisty Fawn (kernel 2.6.20-16-generic) as deb packages and converted to RPM using alien._
-
-xine-lib 1.1.1 / xine-ui 0.99.4 and earlier
-_These RPMs were built on White Box Enterprise Linux 4 running kernel version 2.6.9-5.EL._
-
-
-[www.xine-project.org]: //www.xine-project.org "xine Home"
-[RSS feed]: /category/hosted-64-bit-software/xine-rpms/feed "Xine RPMs (RSS) • The Bit Badger Blog"
diff --git a/source/_posts/2005/xine-lib-1-0-1-rpm.md b/source/_posts/2005/xine-lib-1-0-1-rpm.md
deleted file mode 100644
index 49c7eeb..0000000
--- a/source/_posts/2005/xine-lib-1-0-1-rpm.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-layout: post
-title: xine-lib 1.0.1 RPM
-author: Daniel
-date: 2005-06-02 00:02:03
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
----
-
-Below are the library and development RPMs for xine-lib version 1.0.1. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-devel - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.3][ui].
-
-(To save disk space, only the current release and two prior releases will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2005/xine-ui-0-99-3-rpm.html "xine-ui 0.99.3 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2005/xine-lib-1-1-0-rpm.md b/source/_posts/2005/xine-lib-1-1-0-rpm.md
deleted file mode 100644
index 24407ee..0000000
--- a/source/_posts/2005/xine-lib-1-1-0-rpm.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.0 RPM
-author: Daniel
-date: 2005-08-31 00:00:10
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
----
-
-Below are the library and development RPMs for xine-lib version 1.1.0. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-devel - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.4][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2005/xine-ui-0-99-4-rpm.html "xine-ui 0.99.4 RPM • The Bit Badger Blog"
-[pri]: /2005/xine-lib-1-0-1-rpm.html "xine-lib 1.0.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2005/xine-lib-1-1-1-rpm.md b/source/_posts/2005/xine-lib-1-1-1-rpm.md
deleted file mode 100644
index b6119a1..0000000
--- a/source/_posts/2005/xine-lib-1-1-1-rpm.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.1 RPM
-author: Daniel
-date: 2005-11-23 00:00:49
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
----
-
-Below are the library and development RPMs for xine-lib version 1.1.1. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-devel - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.4][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2005/xine-ui-0-99-4-rpm.html "xine-ui 0.99.4 RPM • The Bit Badger Blog"
-[pri]: /2005/xine-lib-1-1-0-rpm.html "xine-lib 1.1.0 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2005/xine-ui-0-99-3-rpm.md b/source/_posts/2005/xine-ui-0-99-3-rpm.md
deleted file mode 100644
index c61f778..0000000
--- a/source/_posts/2005/xine-ui-0-99-3-rpm.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.3 RPM
-author: Daniel
-date: 2005-06-02 00:01:40
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
----
-
-Below is the RPM for xine-ui version 0.99.3. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-ui - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.0.1][lib].
-
-(To save disk space, only the current release and two prior releases will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[lib]: /2005/xine-lib-1-0-1-rpm.html "xine-lib 1.0.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2005/xine-ui-0-99-4-rpm.md b/source/_posts/2005/xine-ui-0-99-4-rpm.md
deleted file mode 100644
index 35ff4a6..0000000
--- a/source/_posts/2005/xine-ui-0-99-4-rpm.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.4 RPM
-author: Daniel
-date: 2005-08-25 00:00:44
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
----
-
-Below is the RPM for xine-ui version 0.99.4. Be sure to check out the [About the xine RPMs][abt] post for morevinformation.
-
-xine-ui - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.1.0][lib].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[lib]: /2005/xine-lib-1-1-0-rpm.html "xine-lib 1.1.0 RPM • The Bit Badger Blog"
-[pri]: /2005/xine-ui-0-99-3-rpm.html "xine-ui 0.99.3 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2007/adding-tags-to-a-wordpress-theme.md b/source/_posts/2007/adding-tags-to-a-wordpress-theme.md
deleted file mode 100644
index eae99d5..0000000
--- a/source/_posts/2007/adding-tags-to-a-wordpress-theme.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-layout: post
-title: Adding Tags to a WordPress Theme
-author: Daniel
-date: 2007-11-25 22:47:28
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- tag
-- template
-- theme
-- wordpress
-summary: Now that WordPress supports tags, this is how to put them in an existing theme
----
-
-WordPress 2.3 introduced tags, but unless you're using the default theme, your theme (like mine) probably didn't support them. Nowhere did I find a good example of how to add tags to your theme. Then, I was playing around with the theme switcher on my personal blog, and discovered that the default theme had tag support. I looked at it, and it was amazingly simple.
-
-There is a new template tag called ...drumroll... `the_tags`. It takes three parameters: how to begin the list, how to separate each tag, and how to end the list. The tag does not do any output if a post hasn't been tagged, so it can safely sit in your theme until you need it to be active.
-
-Here's how I did it in my personal blog.
-
-{% codeblock lang:php %}
-Tags » ', ' • ', ''); ?>
-{% endcodeblock %}
-
-Of course, you could also do it using an unordered list...
-
-{% codeblock lang:php %}
-
', '
', '
'); ?>
-{% endcodeblock %}
-
-Drop some styling for the "tags" class in your theme's CSS, and you're good to go!
-
-(Well, not quite. You'll want to make sure to make the same change in your main index template, single post template,
-and archive template, so that the tags appear no matter how the user got to the post.)
diff --git a/source/_posts/2007/category-drop-down-in-wordpress.md b/source/_posts/2007/category-drop-down-in-wordpress.md
deleted file mode 100644
index 0b7dece..0000000
--- a/source/_posts/2007/category-drop-down-in-wordpress.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-layout: post
-title: Category Drop-Down in WordPress
-author: Daniel
-date: 2007-05-24 09:00:15
-categories:
-- [ Programming, JavaScript ]
-- [ Programming, PHP, WordPress ]
-tags:
-- category
-- dropdown
-- wordpress
-summary: A category dropdown (select list) in WordPress
----
-
-[WordPress][] provides a [template tag][template], [wp_dropdown_categories][cat], that inserts a drop-down list (the HTML <select> element) of categories, where the value of each item is the ID from the database. This works fine if you are not using rewrite rules (AKA "pretty links") - you can construct a URL using the value (?cat=[number]). However, if you use any sort of rewrite rules, this does not work. I recently converted my [personal site][], which uses the Pool theme, to utilize a JavaScript array to assist with displaying category pages.
-
-Here's the code...
-
-_Edit: Code has been moved to [this post][]._
-
-This works for both "pretty" and standard links, as it uses the template tag [get_category_link][link] to specify the link.
-
-
-[WordPress]: //wordpress.org "WordPress"
-[template]: //codex.wordpress.org/Template_Tags "Template Tags - WordPress Codex"
-[cat]: //codex.wordpress.org/Template_Tags/wp_dropdown_categories "wp_dropdown_categories - WordPress Codex"
-[personal]: //daniel.summershome.org "Daniel J. Summers"
-[this post]: /2007/posting-source-code-in-wordpress-take-2.html "Posting Source Code in WordPress, Take 2 • The Bit Badger Blog"
-[link]: //codex.wordpress.org/Function_Reference/get_category_link "get_category_link - WordPress Codex"
diff --git a/source/_posts/2007/daniels-dropdowns-1-0-wordpress-plug-in.md b/source/_posts/2007/daniels-dropdowns-1-0-wordpress-plug-in.md
deleted file mode 100644
index 676f320..0000000
--- a/source/_posts/2007/daniels-dropdowns-1-0-wordpress-plug-in.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-layout: post
-title: Daniel's DropDowns 1.0 - WordPress Plug-In
-author: Daniel
-date: 2007-10-02 19:54:56
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- category
-- dropdown
-- plug-in
-- wordpress
-summary: A WordPress plugin to display category and archive drop-downs
----
-
-I've created a plug-in that I'm now using on my personal site to provide the category and archive drop-down lists. It's called "Daniel's DropDowns", and it will create drop-downs with either a link or a button to go to the selection in the drop-down, and a CSS class can be specified for the button and the drop-down box.
-
-daniels\_dropdowns.txt - Daniel's DropDowns 1.0 _(UPDATE: This functionality is now part of WordPress core.)_
-
-To install it, download the file, rename it "daniels_dropdowns.php", and upload it to your /wp-content/plugins directory. Then, enable it, and add the template tags to your theme. (The documentation at the top of the file lists all the template tags provided, and the options that can be passed to them.)
diff --git a/source/_posts/2007/daniels-dropdowns-2-0-1-wordpress-plug-in.md b/source/_posts/2007/daniels-dropdowns-2-0-1-wordpress-plug-in.md
deleted file mode 100644
index a031656..0000000
--- a/source/_posts/2007/daniels-dropdowns-2-0-1-wordpress-plug-in.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-layout: post
-title: Daniel's DropDowns 2.0.1 - WordPress Plug-In
-author: Daniel
-date: 2007-12-24 10:34:06
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- category
-- dropdown
-- plug-in
-- update
-- wordpress
-summary: A quick bug fix
----
-
-I have released version 2.0.1 of Daniel's DropDowns, the [WordPress][] plug-in that provides category and archive dropdown template tags. It is available on [its page at the WordPress Plug-In Directory][pi].
-
-This was a minor change - the auto-navigating lists added in version 2 needed a slight tweak. There wasn't a "select category" entry, so one could not navigate to the first item in the list without going somewhere else first. The category dropdown now has this entry, and is consistent with the archive dropdown.
-
-Enjoy!
-
-_(UPDATE: This plug-in is inactive, as its functionality is now part of WordPress core.)_
-
-
-[WordPress]: //wordpress.org "WordPress"
-[pi]: //wordpress.org/extend/plugins/daniels-dropdowns/ "Download Daniel's DropDowns 2.0.1"
diff --git a/source/_posts/2007/daniels-dropdowns-2-wordpress-plug-in.md b/source/_posts/2007/daniels-dropdowns-2-wordpress-plug-in.md
deleted file mode 100644
index 112b055..0000000
--- a/source/_posts/2007/daniels-dropdowns-2-wordpress-plug-in.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-layout: post
-title: Daniel's DropDowns 2 - WordPress Plug-In
-author: Daniel
-date: 2007-12-23 23:02:49
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- category
-- dropdown
-- plug-in
-- update
-- wordpress
-summary: A new version of the category / archive plug-in
----
-
-I have released version 2 of my category and archive drop-down plug-in for [WordPress][]. It is hosted at the WordPress Plug-In Directory - you can [go get it there][pi]. Following are a few of the changes that were made.
-
-* Both tags now have only 2 parameters - the type of navigation and the text for the link or button. For navigation type, 'button' remains the default, and 'link' is still available. However, a third option of 'auto' has been added, which will render the list as an auto-navigating select box.
-* The CSS parameters for the select and button elements were dropped. How these elements can be specified using CSS is detail in the top-of-plugin comments, along with an example.
-* The usage examples in the comments now have an example of how to put the tag in a template in such a way that, if the plug-in is disabled, the template will still render. This could be done with 1.0, but I didn't give an example.
-* I added PHP Documentor-style comments to both functions.
-
-Let me know if you have any problems with it, or any ideas for other behavior. Enjoy!
-
-_(UPDATE: This plug-in is inactive, as its functionality is now part of WordPress core.)_
-
-
-[WordPress]: //wordpress.org "WordPress"
-[pi]: //wordpress.org/extend/plugins/daniels-dropdowns/ "Download Daniel's DropDowns 2"
diff --git a/source/_posts/2007/hcsb-verse-of-the-day-1-0-wordpress-plug-in.md b/source/_posts/2007/hcsb-verse-of-the-day-1-0-wordpress-plug-in.md
deleted file mode 100644
index f426dfe..0000000
--- a/source/_posts/2007/hcsb-verse-of-the-day-1-0-wordpress-plug-in.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: HCSB Verse of the Day 1.0 - WordPress Plug-In
-author: Daniel
-date: 2007-09-25 22:08:24
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- bible gateway
-- hcsb
-- plug-in
-- wordpress
-summary: A WordPress plug-in to display a verse or passage each day
----
-
-I have used a hack in the theme of my personal site for a while to obtain the "Verse of the Day" in the Holman Christian Standard Bible (HCSB) version. With things that I've learned about plug-ins, I decided to take a stab at creating a plug-in to do this work. That way, if I changed themes, I wouldn't have to hack the new one they way I've hacked the current one.
-
-The fruits of my labor is the new HCSB Verse of the Day plug-in for WordPress. It uses the reference from [BibleGateway.com][], then gets the text from their regular website. (They do not provide the service, citing copyright restrictions.) How to use the plug-in, along with my justification on copyright grounds, is in the top of the file's comments. If they're not clear, certainly post comments here and I'll address them. (I do plan to submit the plug-in to [WordPress.org][] - but, they require a specific README file format that it will take me a bit to put together.)
-
-votd\_hcsb.txt - HCSB Verse of the Day 1.0 _(UPDATE: It is in the plugin directory now.)_
-
-To install it, download the file, rename it "votd_hcsb.php", and upload it to your /wp-content/plugins directory. Then, enable it, and add the template tags to your theme - that's it!
-
-
-[BibleGateway.com]: //www.biblegateway.com "Bible Gateway"
-[WordPress.org]: //wordpress.org "WordPress"
diff --git a/source/_posts/2007/incorporating-an-akismet-counter-into-a-wordpress-theme.md b/source/_posts/2007/incorporating-an-akismet-counter-into-a-wordpress-theme.md
deleted file mode 100644
index fb52bad..0000000
--- a/source/_posts/2007/incorporating-an-akismet-counter-into-a-wordpress-theme.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-layout: post
-title: Incorporating an Akismet Counter Into a WordPress Theme
-author: Daniel
-date: 2007-08-06 10:14:00
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- aksimet
-- counter
-- spam
-- theme
-- wordpress
-summary: Akismet counts the spam it blocks, and that count can be displayed
----
-
-[Akismet][] is, by far, the most popular anti-spam plug-in for WordPress. (It comes bundled with the download, so that gets it market share. But, it's also very, very good.) It comes with a counter that can be put into a WordPress theme. It's attractive, but its light blue color may not integrate well into a given theme.
-
-I went digging around in the source code, and found the line that actually pulls the count from the database. Using this parameter, I was able to integrate a spam count into the sidebar that has a look consistent with the rest of the site.
-
-Here's the code that's in use on the theme on this site.
-
-{% codeblock lang:php %}
-
-{% endcodeblock %}
-
-Of course, line 5 is the important one - that's how to get the number, formatted for whatever locale the server is set up for. (On my [personal blog][djs], the number is up over 1,400!)
-
-
-[Akismet]: //akismet.com "Akismet"
-[djs]: //daniel.summershome.org "Daniel J. Summers"
diff --git a/source/_posts/2007/lightning-calendar-plug-in-for-thunderbird-amd64.md b/source/_posts/2007/lightning-calendar-plug-in-for-thunderbird-amd64.md
deleted file mode 100644
index 097097b..0000000
--- a/source/_posts/2007/lightning-calendar-plug-in-for-thunderbird-amd64.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-layout: post
-title: Lightning Calendar Plug-In for Thunderbird AMD64
-author: Daniel
-date: 2007-07-21 09:01:42
-categories:
-- [ Hosted 64-bit Software, Lightning Plug-In ]
-tags:
-- amd64
-- lightning
-- mozilla
-- plug-in
-- sunbird
-- thunderbird
-summary: A plugin that brings Mozilla Sunbird into Thunderbird
-comments: []
----
-
-[Mozilla Sunbird][] is a calendar project that's being designed as a sister program to Thunderbird and Firefox. It's now at the 0.5 version, and there is a plug-in that integrates Sunbird with Thunderbird, called [Lightning][]. It allows you to not only have a calendar, but send and receive meeting requests as well.
-
-I'm running Thunderbird 2 under Ubuntu Feisty Fawn (7.04) on the AMD64 architecture, and could not find a pre-compiled version of this that worked. So, I decided to give it a shot. It was pretty easy, and the result is a plug-in that works with the AMD64 version of Thunderbird! Since I had trouble finding it, I thought I would share it.
-
-Since I have just started using it, I haven't wrung it out, or tested all the options. Use at your own risk, etc.
-
-You can download the plug-in here _(UPDATE: See [this post][].)_ Happy storming! ;)
-
-
-[Mozilla Sunbird]: //www.mozilla.org/projects/calendar/sunbird/ "Mozilla Sunbird Calendar Project"
-[Lightning]: //www.mozilla.org/projects/calendar/lightning/ "Lightning Plug-in for Thunderbird"
-[this post]: /2007/mozilla-now-hosting-lightning-64-bit-plug-in.html "Mozilla Now Hosting Lightning 64-bit Plug-In • The Bit Badger Blog"
diff --git a/source/_posts/2007/mozilla-now-hosting-lightning-64-bit-plug-in.md b/source/_posts/2007/mozilla-now-hosting-lightning-64-bit-plug-in.md
deleted file mode 100644
index 4cc0189..0000000
--- a/source/_posts/2007/mozilla-now-hosting-lightning-64-bit-plug-in.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-layout: post
-title: Mozilla Now Hosting Lightning 64-bit Plug-In
-author: Daniel
-date: 2007-08-07 12:56:46
-categories:
-- [ Hosted 64-bit Software, Lightning Plug-In ]
-tags:
-- lightning
-- mozilla
-- plug-in
-summary: Mozilla provides the Lightning plug-in now
-comments: []
----
-
-Just when I get a nice system set up here, lo and behold, Mozilla now has a 64-bit Linux plug-in available. It can be [obtained from their FTP site][ftp] (link for version 0.5). I'll continue to keep the version I have here available, in case this dries up. _(UPDATE: It's gone.)_ But, unless that does, this is probably the last post you'll see here about the 64-bit Lightning plug-in.
-
-
-[ftp]: //releases.mozilla.org/pub/mozilla.org/calendar/lightning/releases/0.5/contrib/linux-x86-64/
diff --git a/source/_posts/2007/posting-source-code-in-wordpress-take-2.md b/source/_posts/2007/posting-source-code-in-wordpress-take-2.md
deleted file mode 100644
index 928b5b9..0000000
--- a/source/_posts/2007/posting-source-code-in-wordpress-take-2.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-layout: post
-title: Posting Source Code in WordPress, Take 2
-author: Daniel
-date: 2007-06-13 11:33:15
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- geshi
-- plug-in
-- source
-- wordpress
-- wp-syntax
-summary: The WP Syntax Plugin is another plugin that simplifies posting source code
----
-
-In my searching, I have found another WordPress source code plugin, called [wp-syntax][]. This one uses [GeSHi][], the Generic Syntax Highlighter. It features many languages, and is extensible to even more. (If I ever post a COBOL snippet, I'll probably add COBOL support to it, and contribute it to the codebase.)
-
-To use it, you simply put a pre tag, followed by `lang=[language]`. It will also do line numbering. Of course, with a single "language" parameter, the embedded language will not be highlighted as well. In this case, the previous plug-in works better; although the syntax highlighting has to be done manually, it can handle multiple languages.
-
-_(NOTE: The samples have been removed, as this blog is not running under WordPress. However, since the source code from another post was moved here, it is presented below, using [Jekyll][]'s PHP highlighting mode.)_
-
-{% codeblock lang:php %}
-
-
-
-
-{% endcodeblock %}
-
-This is another option, and is probably what I'll use for single-language posts, or posts where the embedded language may not be crucial.
-
-
-[wp-syntax]: //wordpress.org/plugins/wp-syntax/ "WP Syntax Plugin"
-[GeSHi]: http://qbnz.com/highlighter/ "GeSHi"
-[Jekyll]: //jekyllrb.com "Jekyll"
diff --git a/source/_posts/2007/posting-source-code-in-wordpress.md b/source/_posts/2007/posting-source-code-in-wordpress.md
deleted file mode 100644
index 4b6bddc..0000000
--- a/source/_posts/2007/posting-source-code-in-wordpress.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-layout: post
-title: Posting Source Code in WordPress
-author: Daniel
-date: 2007-05-30 14:45:10
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- bennet mcelwee
-- plug-in
-- source
-- wordpress
-summary: A plug-in for WordPress makes posting source code samples easy
----
-
-Traditionally, posting source code in a WordPress blog, especially if it were HTML or PHP, was problematic. There are a few reasons for this...
-
-* WordPress is very good about ensuring that it outputs valid XHTML, so it strips mis-matched and invalid tags. This is usually desirable, but it wreaks havoc with HTML and XML code posts.
-* Since WordPress is coded in PHP, blocks of PHP will attempt to execute.
-* White space is collapsed, which can kill any readability that the user has set out; the "visual editor" ([TinyMCE][]) does its best to create efficient HTML. This can actually break spacing-oriented languages such as Python.
-
-So how do you do it? It's actually pretty easy, using the [Code Markup][] WordPress plugin. You can download the plugin from that link, and upload it to ./wp-content/plugins. The instructions on the website are critical - the "visual" editor will not allow the code to come through unscathed. However, the visual editor only corrupts the code if you actually save it; what I have done is write the post using the visual editor, then disable it and put the code in. It's the best of both worlds! (Make sure that, once you have the code in, you don't edit the post using the visual editor - unless you have a good backup...)
-
-The post below this one (about category lists in WordPress) was done using this plugin. _(This isn't running in WordPress any more.)_ In addition, you can use the <span> tag to do the color-coding. I created a few CSS classes ("key" for keywords, "func" for functions, "attr" for attributes, "embed" for embedded language), and used them to accomplish the color coding. It seems that it would be pretty easy to write another plugin that used a list of keywords to do this syntax highlighting; maybe that's a challenge for another day.
-
-A big "atta boy" to [Bennet McElwee][] for a fantastic plugin!
-
-
-[TinyMCE]: //www.tinymce.com "TinyMCE"
-[Code Markup]: //thunderguy.com/semicolon/wordpress/code-markup-wordpress-plugin/ "Code Markup Plug-in - Semicolon"
-[Bennet McElwee]: //thunderguy.com/semicolon/ "Semicolon - by Bennett McElwee"
diff --git a/source/_posts/2007/releases-for-lightning-plug-in-and-xine-rpms.md b/source/_posts/2007/releases-for-lightning-plug-in-and-xine-rpms.md
deleted file mode 100644
index c84fb76..0000000
--- a/source/_posts/2007/releases-for-lightning-plug-in-and-xine-rpms.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-layout: post
-title: Releases for Lightning Plug-In and xine RPMs
-author: Daniel
-date: 2007-08-06 22:49:08
-categories:
-- [ Hosted 64-bit Software, Lightning Plug-In ]
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- category
-- lightning
-- xine
-summary: How to track releases of pre-built open source software hosted by Bit Badger Solutions
----
-
-At Bit Badger Solutions, we maintain 64-bit builds for two software products - xine and the Lightning plug-in for Thunderbird. These are now shown under "Hosted 64-Bit Software" in the sidebar. You can also view links for each of the categories.
-
-**Lightning Plug-In** _(UPDATE: See [this post][].)_
-
-Category Link • RSS Feed
-
-**xine RPMs**
-
-[Category Link][xine-cat] • [RSS Feed][xine-rss]
-
-Along these lines, there will hopefully be a new xine (1.1.7) coming soon - stay tuned!
-
-
-[this post]: /2007/mozilla-now-hosting-lightning-64-bit-plug-in.html "Mozilla Now Hosting Lightning 64-bit Plug-In • The Bit Badger Blog"
-[xine-cat]: /category/xine-rpms
-[xine-rss]: /xine-rpms.xml
diff --git a/source/_posts/2007/transferring-clobs-across-linked-oracle-databases.md b/source/_posts/2007/transferring-clobs-across-linked-oracle-databases.md
deleted file mode 100644
index 72b44fd..0000000
--- a/source/_posts/2007/transferring-clobs-across-linked-oracle-databases.md
+++ /dev/null
@@ -1,133 +0,0 @@
----
-layout: post
-title: Transferring CLOBs Across Linked Oracle Databases
-author: Daniel
-date: 2007-06-15 14:04:02
-categories:
-- [ Databases, Oracle ]
-- [ Programming, SQL, PL/SQL ]
-tags:
-- algorithm
-- clob
-- data
-- linked database
-- oracle
-summary: An algorithm to move CLOBs from one database to another
----
-
-Linking databases in Oracle make it easy to share data, and can be useful for replication. However, there is a limitation in Oracle that prevents Character Large Objects (CLOBs) from coming across these links. The following technique uses stored procedures and a temporary table to pull CLOBs across a database link.
-
-First, you'll need the temporary table, which will hold a sequence number, the primary key for the table where you'll want to reconstruct the CLOB, and some text. This table can reside in the source or destination database, but must be linked from the other one. For our purposes, it looks like this...
-
-{% codeblock lang:sql %}
-create table clob_xfer_area
-(
- cxa_pk number(12),
- cxa_number number(12),
- cxa_text varchar2(4000 byte)
-);
-alter table clob_xfer_area add
-(
- constraint pk_cxa_id
- primary key (cxa_pk, cxa_number)
-);
-{% endcodeblock %}
-
-Second, you'll need the procedure in the source database that breaks the CLOB apart and populates the temporary table.
-
-{% codeblock lang:sql %}
-set serveroutput on size 1000000
-set lines 1000
-set pages 0
-set tab off
-set feedback on
-create or replace
-procedure break_clobs_apart
-is
- v_line_number number(3);
- v_text_piece varchar2(4000);
- v_total_length number(12);
- cursor clob_cur is
- select twc_pk, twc_clob_field
- from table_with_clob;
-begin /* { */
- for clob_rec in clob_cur loop /* { */
- v_total_length := 1;
- v_line_number := 0;
- while (v_total_length <=
- DBMS_LOB.GETLENGTH(clob_rec.twc_clob_field)) loop /* { */
- v_line_number := v_line_number + 1;
- v_text_piece := DBMS_LOB.SUBSTR(clob_rec.twc_clob_field,
- 3999, v_total_length);
- v_total_length := v_total_length + 3999;
- insert into clob_xfer_area (
- cxa_pk,
- cxa_number,
- cxa_text
- )
- values (
- clob_rec.twc_pk, -- cxa_pk
- v_line_number, -- cxa_number
- v_text_piece -- cxa_text
- );
- end loop; /* } of while */
- end loop; /* } of clob_cur */
-end; /* } of procedure break_clobs_apart */
-{% endcodeblock %}
-
-Third, you'll need a procedure in the destination database that puts the CLOB back together, and deletes the data from the temporary table.
-
-{% codeblock lang:sql %}
-set serveroutput on size 1000000
-set lines 1000
-set pages 0
-set feedback on
-set tab off
-create or replace
-procedure put_clobs_together
-is
- v_new_clob clob;
- cursor pk_cur is
- select distinct cxa_pk
- from clob_xfer_area;
- cursor piece_cur(p_cxa_pk number) is
- select cxa_text
- from clob_xfer_area
- where cxa_pk = p_cxa_pk
- order by cxa_number;
-begin /* { */
- for pk_rec in pk_cur loop /* { */
- DBMS_LOB.CREATETEMPORARY(v_new_clob, TRUE);
- DBMS_LOB.OPEN(v_new_clob, DBMS_LOB.LOB_READWRITE);
- for piece_rec in piece_cur(pk_rec.cxa_pk) loop /* { */
- DBMS_LOB.WRITEAPPEND(v_new_clob, LENGTH(piece_rec.cxa_text),
- piece_rec.cxa_text);
- end loop; /* } of piece_cur */
- DBMS_LOB.CLOSE(v_new_clob);
- update dest_table_with_clob
- set migrated_clob = v_new_clob
- where dtwc_pk = pk_rec.cxa_pk;
- end loop; /* } of pk_cur */
- delete from clob_xfer_area;
-end; /* } of procedure put_clobs_together */
-{% endcodeblock %}
-
-Finally, you'll need a procedure that controls the whole thing. We'll assume that this procedure is loaded in the destination database, and the source database is linked with the name "source".
-
-{% codeblock lang:sql %}
-set lines 1000
-set pages 0
-set feedback on
-set tab off
-create or replace
-procedure xfer_clobs
-is
-begin /* { */
- break_clobs_apart@source;
- put_clobs_together;
-end; /* } */
-{% endcodeblock %}
-
-(This does not include a commit - the changes will not be persistent unless they are committed.)
-
-Of course, these processes could (and, to be useful, likely would) be integrated into other procedures and scripts. But, this framework will successfully transfer CLOBs across linked databases in Oracle.
diff --git a/source/_posts/2007/transferring-data-between-oracle-and-sql-server.md b/source/_posts/2007/transferring-data-between-oracle-and-sql-server.md
deleted file mode 100644
index fda7394..0000000
--- a/source/_posts/2007/transferring-data-between-oracle-and-sql-server.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-layout: post
-title: Transferring Data Between Oracle and SQL Server
-author: Daniel
-date: 2007-07-09 15:23:10
-date_gmt: '2007-07-09 21:23:10 +0000'
-categories:
-- [ Databases, Oracle ]
-- [ Databases, SQL Server ]
-tags:
-- data
-- dts
-- instant client
-- oracle
-- sql server
-summary: Using Oracle's Instant Client for easy SQL Server data exchange
----
-
-There are lots of "how to" articles on sharing data between Oracle and SQL Server. Most of these involve installing Oracle's code base on the SQL Server machine, then using that instance to link tables within Oracle. This technique does not require that, thanks to a product from Oracle called [Oracle Instant Client][ic].
-
-To set up the Oracle piece, download the packages for "Basic" and "ODBC Supplement", and follow the instructions for installation, on the machine with SQL Server. (This is not an "install" per se - it's basically an unzip.) Next, you'll need to provide a TNSNAMES.ORA file - this can be any valid file, including a simple shell with an "ifile=" statement pointing to a common TNSNAMES.ORA file. Finally, set the environment variable TNS_ADMIN to point to the directory where this TNSNAMES.ORA file resides.
-
-Now, you can easily create a DTS script through SQL Server to push or pull data however you'd like. Oracle Instant Client will appear in the drop-down list of providers, and you'll be able to specify your connection the way you normally do (i.e., "DB01.WORLD").
-
-Happy migrating!
-
-
-[ic]: http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html "Download Oracle Instant Client"
diff --git a/source/_posts/2007/welcome.md b/source/_posts/2007/welcome.md
deleted file mode 100644
index 3fb0450..0000000
--- a/source/_posts/2007/welcome.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-layout: post
-title: Welcome!
-author: Daniel
-date: 2007-05-17 14:29:32
-categories:
-- General Info
-tags:
-- blog
-- welcome
----
-
-Welcome to The Bit Badger Blog. This blog is a place where I plan to posts tips and other information regarding technology (AKA "geek stuff"). This will allow me to keep [my personal blog][pers] non-technical.
-
-I have imported my old "My Linux Adventure" posts from 2004 here, to allow the to be indexed and searchable. I noticed, in the process, that some of the information is somewhat dated - take it for what it's worth, which is twice what you paid for it!
-
-I hope that the information here will be beneficial to you.
-
-
-[pers]: //daniel.summershome.org "Daniel J. Summers: Charter Member of the VRWC"
diff --git a/source/_posts/2007/wordpress-2-3-about-to-drop.md b/source/_posts/2007/wordpress-2-3-about-to-drop.md
deleted file mode 100644
index ca3fe7d..0000000
--- a/source/_posts/2007/wordpress-2-3-about-to-drop.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-layout: post
-title: WordPress 2.3 About to Drop
-author: Daniel
-date: 2007-09-24 13:05:27
-categories:
-- General Info
-tags:
-- update
-- wordpress
-summary: A pending WordPress release
----
-
-Version 2.3 of WordPress, the blogging software I use to produce this blog (as well as the other blogs on my site), will be released later today. I'll be upgrading these blogs on Monday evening. There have been major pieces of WordPress that have been re-worked, and those are causing some plug-ins to not work correctly. None of my blogs are all that reliant on plug-ins - the "Share This" plug-in is the main one, and it's been verified in 2.3 already.
-
-There's lots more information on the [WordPress Development Blog][dev] - I won't go into the details here. I'm confident this will be a smooth upgrade. I just wanted to let you know in case some things look strange, I'm on it.
-
-
-[dev]: //wordpress.org/news/ "Development Blog - WordPress.org"
diff --git a/source/_posts/2007/xine-lib-1-1-7-rpm.md b/source/_posts/2007/xine-lib-1-1-7-rpm.md
deleted file mode 100644
index fb3e92a..0000000
--- a/source/_posts/2007/xine-lib-1-1-7-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.7 RPM
-author: Daniel
-date: 2007-08-21 21:10:15
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.7. These have been built a little differently. First, these have been built on Ubuntu Linux, and converted to RPM using alien. Second, I could not quickly figure out how to get only the files tagged for the 1.1.7 release, so this is actually the in-work 1.1.8 release. I ran these builds through some paces, and nothing glaring came out. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2005/xine-lib-1-1-1-rpm.html "xine-lib 1.1.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2007/xine-ui-0-99-5-rpm.md b/source/_posts/2007/xine-ui-0-99-5-rpm.md
deleted file mode 100644
index b65f7fe..0000000
--- a/source/_posts/2007/xine-ui-0-99-5-rpm.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.5 RPM
-author: Daniel
-date: 2007-08-21 21:15:35
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-ui
----
-
-Below is the RPM for xine-ui version 0.99.5. This RPM has been built a little differently. First, it was built on Ubuntu Linux and converted to RPM using alien. Second, I could not quickly figure out how to get the files tagged for the 0.99.5 release, so this build includes changes committed after the official 0.99.5 release. I ran the UI through some paces, and no glaring errors jumped out. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-ui - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.1.7][lib].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[lib]: /2007/xine-lib-1-1-7-rpm.html "xine-lib 1.1.7 RPM • The Bit Badger Blog"
-[pri]: /2005/xine-ui-0-99-4-rpm.html "xine-ui 0.99.4 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2008/a-handy-php-backup-script.md b/source/_posts/2008/a-handy-php-backup-script.md
deleted file mode 100644
index 02d2620..0000000
--- a/source/_posts/2008/a-handy-php-backup-script.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-layout: post
-title: A Handy PHP Backup Script
-author: Daniel
-date: 2008-03-28 23:06:37
-categories:
-- [ Databases, MySQL ]
-- [ Databases, PostgreSQL ]
-- [ Programming, PHP ]
-tags:
-- backup
-- database
-- php
-- script
-summary: A PHP script to create a zip archive and e-mail it
----
-
-I found a script over on the Lunarpages Forums about [using PHP to back up your site][forum]. I have taken it, modified it a little, beefed up the documentation a lot, and am now posting it here. You can copy and paste it from below to customize it for your own use.
-
-{% codeblock backup.php lang:php %}
-
- */
-
-// --- SCRIPT PARAMETERS ---
-
-/* -- File Name --
- This is the name of the file that you're backing up, and should contain no
- slashes. For example, if you're backing up a database, this might look
- something like...
-$sFilename = "backup-my_database_name-" . date("Y-m-d") . ".sql"; */
-$sFilename = "backup-[whatever-it-is]-" . date("Y-m-d") . ".[extension]";
-
-/* -- E-mail Address --
- This is the e-mail address to which the message will be sent. */
-$sEmailAddress = "[your e-mail address]";
-
-/* -- E-mail Subject --
- This is the subject that will be on the e-mail you receive. */
-$sEmailSubject = "[something meaningful]";
-
-/* -- E-mail Message --
- This is the text of the message that will be sent. */
-$sMessage = "Compressed database backup file $sFilename.gz attached.";
-
-/* -- Backup Command --
- This is the command that does the work.
-
- A note on the database commands - your setup likely requires a password
- for these commands, and they each allow you to pass a password on the
- command line. However, this is very insecure, as anyone who runs "ps" can
- see your password! For MySQL, you can create a ~/.my.cnf file - it is
- detailed at //dev.mysql.com/doc/refman/4.1/en/password-security.html .
- For PostgreSQL, the file is ~/.pgpass, and it is detailed at
- //www.postgresql.org/docs/8.0/interactive/libpq-pgpass.html . Both of
- these files should be chmod-ded to 600, so that they can only be viewed by
- you, the creator.
-
- That being said, some common commands are...
-
- - Backing Up a MySQL Database
-$sBackupCommand = "mysqldump -u [user_name] [db_name] > $sFilename";
-
- - Backing Up a PostgreSQL Database
-$sBackupCommand = "pg_dump [db_name] -h localhost -U [user_name] -d -O > $sFilename";
-
- - Backing Up a set of files (tar and gzip)
-$sBackupCommand = "tar cvf $sFilename [directory]
-
- Whatever command you use, this script appends .gz to the filename after the command is executed. */
-$sBackupCommand = "[a backup command]";
-
-// --- END OF SCRIPT PARAMETERS ---
-//
-// Edit below at your own risk. :)
-
-// Do the backup.
-$sResult = passthru($sBackupCommand . "; gzip $sFilename");
-$sFilename .= ".gz";
-
-// Create the message.
-$sMessage = "Compressed database backup file $sFilename attached.";
-$sMimeBoundary = "<<<:" . md5(time());
-$sData = chunk_split(base64_encode(implode("", file($sFilename))));
-
-$sHeaders = "From: $sEmailAddress\r\n"
- . "MIME-Version: 1.0\r\n"
- . "Content-type: multipart/mixed;\r\n"
- . " boundary=\"$sMimeBoundary\"\r\n";
-
-$sContent = "This is a multi-part message in MIME format.\r\n\r\n"
- . "--$sMimeBoundary\r\n"
- . "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n"
- . "Content-Transfer-Encoding: 7bit\r\n\r\n"
- . $sMessage."\r\n"
- . "--$sMimeBoundary\r\n"
- . "Content-Disposition: attachment;\r\n"
- . "Content-Type: Application/Octet-Stream; name=\"$sFilename\"\r\n"
- . "Content-Transfer-Encoding: base64\r\n\r\n"
- . $sData."\r\n"
- . "--$sMimeBoundary\r\n";
-
-// Send the message.
-mail($sEmailAddress, $sEmailSubject, $sContent, $sHeaders);
-
-// Delete the file - we don't need it any more.
-unlink($sFilename);
-{% endcodeblock %}
-
-
-[forum]: //www.lunarforums.com/lunarpages_how_tos/site_and_mysql_backups_via_cron-t22118.0.html "Site and MySQL backups via cron - Lunarforums"
diff --git a/source/_posts/2008/algorithm-for-one-to-many-child-table-updates.md b/source/_posts/2008/algorithm-for-one-to-many-child-table-updates.md
deleted file mode 100644
index b0bc170..0000000
--- a/source/_posts/2008/algorithm-for-one-to-many-child-table-updates.md
+++ /dev/null
@@ -1,138 +0,0 @@
----
-layout: post
-title: Algorithm for One-to-Many Child Table Updates
-author: Daniel
-date: 2008-03-28 20:13:24
-categories:
-- Databases
-- [ Programming, PHP ]
-- [ Programming, SQL ]
-tags:
-- algorithm
-- array
-- nsx
-- one-to-many
-- php
-- sql
-summary: An easy way to sync changes in a one-to-many relationship
----
-
-While working on the [Not So Extreme Makeover: Community Edition][nsx] site, I came up with an algorithm that simplifies anything else I've ever written to deal with this condition. I'll set the scenario, explain the algorithm, share how I implemented it in PHP, and provide a modification if the scenario is a bit more complicated.
-
-**Scenario** - You have two parent tables, and a child table with a many-to-one relationship with both parent tables, used to map entries in the two parent tables to each other. For this example, we'll use these three tables...
-
-{% codeblock lang:sql %}
-create table volunteer (
- vol_id integer not null,
- vol_last_name varchar(50) not null,
- ...etc...
- primary key (vol_id)
-);
-
-create table r_volunteer_area (
- rva_id integer not null,
- rva_description varchar(255) not null,
- primary key (rva_id)
-);
-
-create table volunteer_area (
- va_volunteer_id integer not null,
- va_area_id integer not null,
- primary key (va_volunteer_id, va_area_id),
- foreign key (va_volunteer_id) references volunteer (vol_id),
- foreign key (va_area_id) references r_volunteer_area (rva_id)
-);
-{% endcodeblock %}
-
-**Algorithm** - The three-step algorithm is as follows...
-
-1. Create a comma-delimited string of IDs for the child table.
-2. Delete the IDs from the child table that are not in the list.
-3. Insert the IDs into the child table that are not there already.
-
-**Implementation** - In PHP, if you have an array, it's easy to come up with comma-delimited list. To get an array of values back in a post, define your fields with "[]" after the name...
-
-{% codeblock lang:php %}
-
-
-
-
-{% endcodeblock %}
-
-Here's the PHP code, using [PHP Data Objects (PDO)][pdo] as the database interface, behind a helper class that creates the statement, appends the parameters, and executes it. _(The "quoting" escapes the statement to avoid potential SQL injection attacks - putting it in its own class would make the implementation here much cleaner.)_
-
-{% codeblock lang:php %}
-/**
- * STEP 1
- * Create a comma-delimited list of IDs.
- */
-
-// Quote will return the string as '2,3,4' - since we're using this
-// as an IN clause of integers, we'll strip the quotes off.
-$sAreas = $pdo->quote(join(",", $_POST["area"]));
-$sAreas = substr($sAreas, 1, strlen($sAreas) - 1);
-
-// Quote the volunteer ID.
-$iVol = $pdo->quote($_POST["vol"], PDO::PARAM_INT);
-
-/**
- * STEP 2
- * Delete the IDs that are no longer in the list.
- */
-$dbService->executeCommand(
- "DELETE FROM volunteer_area
- WHERE va_volunteer_id = ?
- AND va_area_id NOT IN ($sAreas)",
- array($iVol);
-
-/**
- * STEP 3
- * Insert the IDs that are not yet in the list.
- */
-$dbService->executeCommand(
- "INSERT INTO volunteer_area
- SELECT $iVol, rva_id
- FROM r_volunteer_area
- WHERE rva_id IN ($sAreas)
- AND rva_id NOT IN
- (SELECT va_area_id
- FROM volunteer_area
- WHERE va_volunteer_id = ?)",
- array($iVol));
-{% endcodeblock %}
-
-**Modification** - Suppose that now you accepted comments along with each of the checkboxes, so a simple two-integer insert/delete is no longer sufficient. You would still only need to break step 3 into two steps.
-
-1. Get a list of IDs to update.
-2. For each ID in the posted list
- 1. If the ID exists in the update list, update it.
- 2. Otherwise, insert it.
-
-The implementation would then be able to use this list to make the decision without hitting the database every time.
-
-{% codeblock lang:php %}
-// Assume this returns an associative array of IDs.
-$aUpdates = $dbService->performSelect(
- "SELECT va_area_id
- FROM volunteer_area
- WHERE va_volunteer_id = ?
- AND va_area_id IN ($sAreas)",
- array($iVol));
-
-foreach($_POST["area"] as $iArea) {
- if (in_array($iArea, $aUpdates)) {
- // Update the table
- ...etc...
- }
- else {
- // Insert into the table
- ...etc...
- }
-}
-{% endcodeblock %}
-
-I think you'll agree that this is much better than spinning through a loop, doing a count on each ID to see if it exists, then either doing an update or an insert based on the count. And, while the implementation here is PHP, it could easily be implemented in any language that supports arrays and database access.
-
-
-[nsx]: //bitbadger.solutions/solutions/nsx "Not So Extreme Makeover: Community Edition • Bit Badger Solutions"
-[pdo]: //us.php.net/pdo "PHP Data Objects (PDO)"
diff --git a/source/_posts/2008/daniels-dropdowns-2-1-wordpress-plug-in.md b/source/_posts/2008/daniels-dropdowns-2-1-wordpress-plug-in.md
deleted file mode 100644
index e6e18ff..0000000
--- a/source/_posts/2008/daniels-dropdowns-2-1-wordpress-plug-in.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-layout: post
-title: Daniel's DropDowns 2.1 - WordPress Plug-In
-author: Daniel
-date: 2008-05-09 20:14:20
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- category
-- dropdown
-- plug-in
-- wordpress
-summary: Bug fixes in conjunction with changes in WordPress 2.5
----
-
-Version 2.1 of Daniel's DropDowns has been released. This fixes a problem introduced with the 2.5-series of WordPress - the output of the WordPress tag changed, so the search-and-replace portion that added a "Select Category" entry didn't work. This has been fixed in version 2.1. I also corrected a small bug that caused the first entry in the category list to be selected if a default wasn't specified.
-
-It can be downloaded from the [WordPress Plug-In Directory][pi]. Enjoy!
-
-_(UPDATE: This plug-in is inactive, as its functionality is now part of WordPress core.)_
-
-
-[pi]: //wordpress.org/extend/plugins/daniels-dropdowns/ "Download Daniel's DropDowns 2.1"
diff --git a/source/_posts/2008/hcsb-verse-of-the-day-2-wordpress-plug-in.md b/source/_posts/2008/hcsb-verse-of-the-day-2-wordpress-plug-in.md
deleted file mode 100644
index 8202c8f..0000000
--- a/source/_posts/2008/hcsb-verse-of-the-day-2-wordpress-plug-in.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-layout: post
-title: HCSB Verse of the Day 2 - WordPress Plug-In
-author: Daniel
-date: 2008-01-01 11:02:11
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- bible gateway
-- hcsb
-- plug-in
-- update
-- wordpress
-summary: Significant updates to the verse-of-the-day plug-in
----
-
-I have released version 2 of HCSB Verse of the Day, the [WordPress][] plug-in that provides a verse or passage each day, using the reference provided by [BibleGateway.com][]. I also completed the required files for the WordPress Plug-In Directory, so it can be [downloaded from there][pi].
-
-New in this version...
-
-* **New Tag** - There is now a tag votd_hcsb() that puts out the heading, the text, the reference, and the credit line all in one. This will simplify the template modification required to implement the plug-in.
-* **Custom Tag** - There is a separate file where you can specify a separate group of tags, and the votd_hcsb() tag will utilize it instead of its default. This also means that, even if future versions change the default, the custom tag layout will be used.
-* **Two Versions** - WordPress (and most plug-ins) must be compatible with PHP version 4. However, if your web server is running PHP version 5, there is now a PHP 5 version included. It incorporates the object-oriented enhancements in PHP 5.
-* **Options Revamped** - Since I initially wrote the plug-in, I've learned that WordPress allows an option to be an array. So, to streamline its usage, the options are now an array, and only require one row in the database instead of five. There is also a file to clean up the old options.
-* **Bug Fixes** - BibleGateway.com changed the way they display multiple passages (ex. "Matthew 1:13, 17-19"); version 2 has a fix that makes that work again.
-
-As always, if you encounter any problems with the plug-in, just let me know and I'll try to help. Enjoy!
-
-
-[WordPress]: //wordpress.org "WordPress"
-[BibleGateway.com]: //www.biblegateway.com "Bible Gateway"
-[pi]: //wordpress.org/extend/plugins/hcsb-verse-of-the-day/ "Download HCSB Verse of the Day 2"
diff --git a/source/_posts/2008/killing-_utma-_utmb-_utmc-_utmz-cookies.md b/source/_posts/2008/killing-_utma-_utmb-_utmc-_utmz-cookies.md
deleted file mode 100644
index 672469c..0000000
--- a/source/_posts/2008/killing-_utma-_utmb-_utmc-_utmz-cookies.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-layout: post
-title: Killing _utma _utmb _utmc _utmz Cookies
-author: Daniel
-date: 2008-10-27 21:06:26
-categories:
-- Security and Privacy
-tags:
-- adblock plus
-- cookie
-- google
-summary: Using AdBlock Plus to get rid of common third-party cookies
----
-
-For those of us who are cookie-conscious as we surf the web, you're aware that a lot of sites give cookies with names like _utma, _utmb, _utmc, and _utmz. It turns out that these cookies come from Google Analytics.
-
-However, using AdBlock Plus, there is an easy way to kill it. To put in a filter for it, click the "ABP" stop sign icon, and click the "New Filter..." button. Enter "http://www.google-analytics.com/\*" and press Enter. That's it! Those _utm* cookies are now a thing of the past.
diff --git a/source/_posts/2008/on-mission.md b/source/_posts/2008/on-mission.md
deleted file mode 100644
index 7e2ff2b..0000000
--- a/source/_posts/2008/on-mission.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-layout: post
-title: On Mission
-author: Daniel
-date: 2008-03-14 18:44:49
-categories:
-- General Info
-tags:
-- easter
-- nsx
-- postgresql
-summary: Posts have been delayed due to work on a volunteer effort in Albuquerque, New Mexico
----
-
-Sorry for the lack of new content (although I did download and build the latest release of xine). I've been working on a community-based volunteer effort in Albuquerque, New Mexico called [Not So Extreme Makeover: Community Edition][nsx]. I'm handling the public website, as well as a private side that the leaders can use to track lots of different things. I'm going to have some good stuff I've discovered out here once we're done (along with lots of praise to heap on [PostgreSQL][pg] - I have a new "most favorite" open source database), but for the rest of March, I'll likely be incommunicado.
-
-Happy Easter - see you in April!
-
-
-[nsx]: //bitbadger.solutions/solutions/nsx "Not So Extreme Makeover: Community Edition • Bit Badger Solutions"
-[pg]: //www.postgresql.org
diff --git a/source/_posts/2008/oracle-sql-developer-debian-package.md b/source/_posts/2008/oracle-sql-developer-debian-package.md
deleted file mode 100644
index 405c1d0..0000000
--- a/source/_posts/2008/oracle-sql-developer-debian-package.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-layout: post
-title: Oracle SQL Developer Debian Package
-author: Daniel
-date: 2008-10-29 07:17:14
-categories:
-- [ Databases, MySQL ]
-- [ Databases, Oracle ]
-- [ Databases, PostgreSQL ]
-- [ Databases, SQL Server ]
-- [ Programming, SQL ]
-tags:
-- alien
-- deb
-- java
-- oracle
-- rpm
-- sql developer
-summary: A .deb package for Oracle's SQL Developer product
----
-
-[Oracle SQL Developer][sd] is a Java-based tool that provides a graphical interface to a database. While it's main focus is Oracle (of course), it can be hooked up, via JDBC, to many other databases, such as MySQL, PostgreSQL, and SQL Server. It's similar to [Toad][], but is provided by Oracle at no cost.
-
-Oracle provides SQL Developer in either an RPM, or a generic binary install. I like the ability to manage packages, but I've never had much luck at getting RPM to run on Ubuntu. I downloaded the RPM file, and, using [alien][], I converted the package to a .deb package (Debian package format) and installed it. It worked like a charm!
-
-I haven't tested it with gcj, but using Sun's Java 6 update 7 from the Ubuntu repositories, it ran just fine. After you install the package, do a directory list on `/usr/lib/jvm`. You're looking for the Sun JDK - if it's installed, you'll have a symlink java-6-sun that points to java-6-sun-1.6.0.07. Once you've determined the location of the JDK, run "sqldeveloper" from the command line - the program will prompt you for the path to your JDK. Enter it (probably `/usr/lib/jvm/java-6-sun`) and you're good to go. (You have to install the package as root - but, for the rest of these steps, use your normal user, not root, as this puts settings in a .sqldeveloper directory off your home directory.) The package installs an icon in the "Programming" or "Development" group. Once you've told it where the JDK is, you can use this to launch it.
-
-[Download SQL Developer 1.5.1 Debian Package][deb]
-
-
-[sd]: //www.oracle.com/technology/products/database/sql_developer/index.html "Oracle SQL Developer • Oracle"
-[Toad]: //www.toadsoft.com
-[alien]: //kitenet.net/~joey/code/alien/
-[deb]: //djs-consulting.com/linux/software/sqldeveloper/sqldeveloper_1.5.54.40-2_all.deb "SQL Developer 1.5.1 Debian Package • Bit Badger Solutions Linux Software Repository"
diff --git a/source/_posts/2008/the-djs-consulting-linux-software-repository.md b/source/_posts/2008/the-djs-consulting-linux-software-repository.md
deleted file mode 100644
index 83171a1..0000000
--- a/source/_posts/2008/the-djs-consulting-linux-software-repository.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-layout: post
-title: The Bit Badger Solutions Linux Software Repository
-author: Daniel
-date: 2008-06-24 21:05:18
-categories:
-- General Info
-tags:
-- mike petersen
-- open source
-- opensuse
-- repository
-- sled
-- xine
-- xine-lib
-- xine-ui
-summary: A new place to find all the software we host
----
-
-We have created a software repository, where users can browse files that may be available. The base location is [https://hosted.djs-consulting.com/software][repo]. Within there, there are a few areas.
-
-* [/sled][] and [/opensuse][] - These contain add-on CD images for SUSE Linux Enterprise Desktop (SLED) and openSUSE, created by [Mike Petersen][pcc]. These add-ons provide multimedia and gaming capabilities that don't come with SLED unless you purchase the support or compile them yourselves. These images can be added as resources in YaST.
-* [/xine][] - This contains the 64-bit RPMs for xine (the latest three), both xine-lib and xine-ui. New releases will continue to get their own posts, but that's where they will be.
-
-Enjoy!
-
-
-[repo]: //hosted.djs-consulting.com/software "Bit Badger Solutions Linux Software Repository"
-[/sled]: //hosted.djs-consulting.com/software/sled "SUSE Linux Enterprise Desktop Add-On Images"
-[/opensuse]: //hosted.djs-consulting.com/software/opensuse "openSUSE Add-On Images"
-[pcc]: //www.pcc-services.com "PCC Services"
-[/xine]: //hosted.djs-consulting.com/software/xine "xine RPMs"
diff --git a/source/_posts/2008/xine-lib-1-1-10-1-rpm.md b/source/_posts/2008/xine-lib-1-1-10-1-rpm.md
deleted file mode 100644
index 84a0d93..0000000
--- a/source/_posts/2008/xine-lib-1-1-10-1-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.10.1 RPM
-author: Daniel
-date: 2008-03-14 18:21:55
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.10.1. These have been built the same way that 1.1.7 and 1.1.9.1 were - built on Ubuntu Linux, and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2008/xine-lib-1-1-9-1-rpm.html "xine-lib 1.1.9.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2008/xine-lib-1-1-13-rpm.md b/source/_posts/2008/xine-lib-1-1-13-rpm.md
deleted file mode 100644
index 52257be..0000000
--- a/source/_posts/2008/xine-lib-1-1-13-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.13 RPM
-author: Daniel
-date: 2008-06-24 19:06:36
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.13. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2008/xine-lib-1-1-10-1-rpm.html "xine-lib 1.1.10.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2008/xine-lib-1-1-14-rpm.md b/source/_posts/2008/xine-lib-1-1-14-rpm.md
deleted file mode 100644
index 86e0972..0000000
--- a/source/_posts/2008/xine-lib-1-1-14-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.14 RPM
-author: Daniel
-date: 2008-06-29 19:20:58
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.14. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2008/xine-lib-1-1-13-rpm.html "xine-lib 1.1.13 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2008/xine-lib-1-1-9-1-rpm.md b/source/_posts/2008/xine-lib-1-1-9-1-rpm.md
deleted file mode 100644
index 2f1f77c..0000000
--- a/source/_posts/2008/xine-lib-1-1-9-1-rpm.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.9.1 RPM
-author: Daniel
-date: 2008-01-23 21:41:28
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.9.1. These have been built the same way that the 1.1.7 RPMs were - built on Ubuntu Linux, and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2007/xine-lib-1-1-7-rpm.html "xine-lib 1.1.7 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2009/xine-lib-1-1-16-1-rpm.md b/source/_posts/2009/xine-lib-1-1-16-1-rpm.md
deleted file mode 100644
index e85a430..0000000
--- a/source/_posts/2009/xine-lib-1-1-16-1-rpm.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.16.1 RPM
-author: Daniel
-date: 2009-01-12 22:53:20
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.16.1. Additionally, beginning with this release, there is also a documentation RPM available. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-xine-lib-doc - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2008/xine-lib-1-1-14-rpm.html "xine-lib 1.1.14 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2009/xine-lib-1-1-16-2-rpm.md b/source/_posts/2009/xine-lib-1-1-16-2-rpm.md
deleted file mode 100644
index 39fdf97..0000000
--- a/source/_posts/2009/xine-lib-1-1-16-2-rpm.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.16.2 RPM
-author: Daniel
-date: 2009-02-11 19:29:50
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.16.2. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-xine-lib-doc - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2009/xine-lib-1-1-16-1-rpm.html "xine-lib 1.1.16.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2009/xine-lib-1-1-16-3-rpm.md b/source/_posts/2009/xine-lib-1-1-16-3-rpm.md
deleted file mode 100644
index fcb2f5b..0000000
--- a/source/_posts/2009/xine-lib-1-1-16-3-rpm.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.16.3 RPM
-author: Daniel
-date: 2009-04-03 18:21:57
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.16.3. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-xine-lib-doc - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.5][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
-[pri]: /2009/xine-lib-1-1-16-2-rpm.html "xine-lib 1.1.16.2 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2010/4040-web-service.md b/source/_posts/2010/4040-web-service.md
deleted file mode 100644
index 78f69af..0000000
--- a/source/_posts/2010/4040-web-service.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-layout: post
-title: 40/40 Web Service
-author: Daniel
-date: 2010-09-19 19:55:34
-categories:
-- [ Programming, Web Services ]
-tags:
-- erlc
-- prayer
-- sbc
-- web service
-summary: A web service to support the 2010 40/40 Prayer Vigil
----
-
-The [Ethics and Religious Liberty Commission][erlc] of the [Southern Baptist Convention][sbc] is holding a "[40/40 Prayer Vigil][site]," encouraging prayer through the end of October. While some of the prayer is focused on the upcoming elections, the focus is on national revival. They have produced a prayer guide, which details suggestions for prayer over the course of 40 days, beginning September 20th, and for 40 hours, beginning October 29th at 4pm.
-
-We have created a web service to break this guide up into day and hour-sized chunks. The service is at this URL no longer active. There are several ways to retrieve this information.
-
-* **GetDay**
- This gets one of the 40 days, by the day number. (September 20th is 1, September 21st is 2, etc.) The "day" parameter controls which day is returned.
-* **GetHour**
- This gets one of the 40 hours, by the hour number (10/29 4pm is 1, 10/29 5pm is 2, etc.) The "hour" parameter controls which hour is returned.
-* **GetDate**
- This gets one of the 40 days, by the current date. The "date" parameter controls which day is returned. (The time portion may be given, but it is ignored.)
-* **GetTime**
- This gets one of the 40 hours, by the date/time. The "time" parameter controls which hour is returned.
-* **GetDayHTML**, **GetHourHTML**, **GetDateHTML**, and **GetTimeHTML**
- This is the same as the above 4 calls, except what is returned is a formatted block of text that can be displayed on a web page.
-
-In all cases, if the day/hour/date/time does not match a valid value for the vigil, a null is returned.
-
-If you're not interested in consuming the web service, but you'd like to see the suggested prayer each day, the Hoffmantown Prayer site is displaying the days and hours on Mountain Time. This information is on the front page with no login required.
-
-This web service will be discontinued at some point after December 31, 2010.
-
-
-[erlc]: http://erlc.com "The Ethics and Religious Liberty Commission of the Southern Baptist Convention"
-[sbc]: http://www.sbc.net "Southern Baptist Convention"
-[site]: //4040prayer.wordpress.com "40/40 Prayer Vigil"
diff --git a/source/_posts/2010/mono-fastcgi-startup-script.md b/source/_posts/2010/mono-fastcgi-startup-script.md
deleted file mode 100644
index 34dd79a..0000000
--- a/source/_posts/2010/mono-fastcgi-startup-script.md
+++ /dev/null
@@ -1,135 +0,0 @@
----
-layout: post
-title: Mono / FastCGI Startup Script
-author: Daniel
-date: 2010-09-03 19:28:15
-categories:
-- Linux
-- [ Programming, .NET, Mono ]
-- Web Servers
-tags:
-- badgerports
-- config
-- fastcgi
-- mono
-- script
-summary: A script that allows Mono web applications to be defined and started the way Apache and nginx enable and disable their sites
----
-
-We've begun running Mono on some Bit Badger Solutions servers to enable us to support the .NET environment, in addition to the PHP environment most of our other applications use. While Ubuntu has nice packages (and Badgerports even brings brought them up to the latest release), one thing that we were missing was a "conf.d"-type of configuration; my "/applications=" clause of the command was getting really, really long. We decided to see if we could create something similar to Apache / Nginx's sites-available/sites-enabled paradigm, and we have succeeded!
-
-To begin, you'll need to create the directories `/etc/mono/fcgi/apps-available` and `/etc/mono/fcgi/apps-enabled`. These directories will hold files that will be used define applications. The intent of these directories is to put the actual files in `apps-available`, then symlink the ones that are enabled from `apps-enabled`. These files have no name restrictions, but do not put an extra newline character in them. The script will concatenate the contents of that file to create the [MONO_FCGI_APPLICATIONS environment variable][env], which tells the server what applications exist. (The syntax is the same as that for the "/applications=" clause - `[domain]:[URL path]:[filesystem path]`.) Here's how the site you're reading now is configured (from the file `djs-consulting.com.techblog.conf`)...
-
-{% codeblock djs-consulting.com.techblog.conf lang:shell %}
-techblog.djs-consulting.com:/:/path/to/install/base/for/this/site
-{% endcodeblock %}
-
-Finally, what brings it all together is a shell script. This should be named "monoserve" and placed in `/etc/init.d`. (This borrows heavily from this script a script we found online, which we used until we wrote this one.) Note the group of variables surrounded by the "make changes here" notes - these are the values that are used in starting the server. They are at the top so that you can easily modify this for your own needs.
-
-{% codeblock monoserve lang:shell %}
-#/bin/bash
-
-### BEGIN INIT INFO
-# Provides: monoserve.sh
-# Required-Start: $local_fs $syslog $remote_fs
-# Required-Stop: $local_fs $syslog $remote_fs
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Start FastCGI Mono server with hosts
-### END INIT INFO
-
-PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-DAEMON=/usr/bin/mono
-NAME=monoserver
-DESC=monoserver
-
-## Begin -- MAKE CHANGES HERE --
-PROGRAM=fastcgi-mono-server2 # The program which will be started
-ADDRESS=127.0.0.1 # The address on which the server will listen
-PORT=9001 # The port on which the server will listen
-USER=www-data # The user under which the process will run
-GROUP=$USER # The group under which the process will run
-## End -- MAKE CHANGES HERE --
-
-# Determine the environment
-MONOSERVER=$(which $PROGRAM)
-MONOSERVER_PID=""
-FCGI_CONFIG_DIR=/etc/mono/fcgi/apps-enabled
-
-# Start up the Mono server
-start_up() {
- get_pid
- if [ -z "$MONOSERVER_PID" ]; then
- echo "Configured Applications"
- echo "-----------------------"
- # Construct the application list if the configuration directory exists
- if [ -d $FCGI_CONFIG_DIR ]; then
- MONO_FCGI_APPLICATIONS=""
- for file in $( ls $FCGI_CONFIG_DIR ); do
- if [ "$MONO_FCGI_APPLICATIONS" != "" ]; then
- MONO_FCGI_APPLICATIONS=$MONO_FCGI_APPLICATIONS,
- fi
- MONO_FCGI_APPLICATIONS=$MONO_FCGI_APPLICATIONS`cat $FCGI_CONFIG_DIR/$file`
- done
- export MONO_FCGI_APPLICATIONS
- echo -e ${MONO_FCGI_APPLICATIONS//,/"\n"}
- else
- echo "None (config directory $FCGI_CONFIG_DIR not found)"
- fi
- echo
-
- # Start the server
- start-stop-daemon -S -c $USER:$GROUP -x $MONOSERVER -- /socket=tcp:$ADDRESS:$PORT &
- echo "Mono FastCGI Server $PROGRAM started as $USER on $ADDRESS:$PORT"
- else
- echo "Mono FastCGI Server is already running - PID $MONOSERVER_PID"
- fi
-}
-
-# Shut down the Mono server
-shut_down() {
- get_pid
- if [ -n "$MONOSERVER_PID" ]; then
- kill $MONOSERVER_PID
- echo "Mono FastCGI Server stopped"
- else
- echo "Mono FastCGI Server is not running"
- fi
-}
-
-# Refresh the PID
-get_pid() {
- MONOSERVER_PID=$(ps auxf | grep $PROGRAM.exe | grep -v grep | awk '{print $2}')
-}
-
-case "$1" in
- start)
- start_up
- ;;
- stop)
- shut_down
- ;;
- restart|force-reload)
- shut_down
- start_up
- ;;
- status)
- get_pid
- if [ -z "$MONOSERVER_PID" ]; then
- echo "Mono FastCGI Server is not running"
- else
- echo "Mono FastCGI Server is running - PID $MONOSERVER_PID"
- fi
- ;;
- *)
- echo "Usage: monoserve (start|stop|restart|force-reload|status)"
- ;;
-esac
-
-exit 0
-{% endcodeblock %}
-
-This needs to be owned by root and be executable (`chmod +x monoserve`). You can use `update-rc.d monoserve defaults` to set this to start at boot.
-
-
-[env]: http://www.mono-project.com/docs/web/fastcgi/ "FastCGI • Mono Project"
diff --git a/source/_posts/2010/oracle-sql-developer-2-1-debian-package.md b/source/_posts/2010/oracle-sql-developer-2-1-debian-package.md
deleted file mode 100644
index c517374..0000000
--- a/source/_posts/2010/oracle-sql-developer-2-1-debian-package.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-layout: post
-title: Oracle SQL Developer 2.1 Debian Package
-author: Daniel
-date: 2010-03-02 12:11:26
-categories:
-- [ Databases, Oracle ]
-tags:
-- deb
-- oracle
-- sql developer
-summary: A newer version of SQL Developer is available
----
-
-It had been a while since I had updated SQL Developer. It turns out that version 2.1 was released March 1st of this year. I've downloaded it and created a Debian package. It can be [downloaded][deb] from the [Bit Badger Solutions Linux Software Repository][repo].
-
-I've used it with Sun's Java 6 Update 18; I have not tested it with OpenJDK. If you have problems getting it to work, you may want to check the [previous post][post] on this topic.
-
-
-[deb]: //hosted.djs-consulting.com/software/sqldeveloper/sqldeveloper_2.1.1.64.39-2_all.deb "Download SQL Developer 2.1 Debian Package"
-[repo]: //hosted.djs-consulting.com/software "Bit Badger Solutions Linux Software Repository"
-[post]: /2008/oracle-sql-developer-debian-package.html "Oracle SQL Developer Debian Package • The Bit Badger Blog"
diff --git a/source/_posts/2010/tech-blog-2-0.md b/source/_posts/2010/tech-blog-2-0.md
deleted file mode 100644
index cadaacf..0000000
--- a/source/_posts/2010/tech-blog-2-0.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-layout: post
-title: Tech Blog 2.0
-author: Daniel
-date: 2010-08-05 19:09:54
-categories:
-- General Info
-- [ Programming, .NET, C# ]
-tags:
-- .net
-- blogengine
-- fastcgi
-- mono
-- php
-- wordpress
----
-
-After three years on [WordPress][], The Bit Badger Blog has moved to [BlogEngine.NET][]. There are several reasons for this change, some technical and some not.
-
-* PHP's Fast CGI processor has a problem where, if all of the processes are busy, the server will simply time out. While this hasn't afflicted my server as much as others, it has caused problems; when this problem occurred, none of the PHP sites were accessible.
-* Through experience with a very heavily-used site, I became less enamored of WordPress's "read from the database every time" way of doing business. I also found that various caching plug-ins for WordPress, on this particular site, did very little to ease the load.
-* Since I first looked at Mono (Linux's implementation of the .NET framework), it has matured significantly. It supports most of C# 4.0 already, which was released earlier this year.
-* BlogEngine.NET is a rapidly-maturing blog platform, and the project has a stated goal of 100% compatibility with Mono. This is good, because you can mention Mono problems to the team, and you're not dismissed because you're running Linux.
-
-As part of the move, the URL has changed; the new link is . I have implemented redirection for each post, the category and category feed links, and the main blog feed and home page from the old URL, so you may not have even realized that you're looking at the new site. The Bit Badger Solutions Software Repository remains at .
-
-I'm looking forward to this new setup!
-
-_(NOTE: The next-to-last paragraph was updated with correct links as of February 2017.)_
-
-
-[WordPress]: //wordpress.org "WordPress"
-[BlogEngine.NET]: http://dnbe.net/docs/ "BlogEngine.NET"
diff --git a/source/_posts/2010/xine-lib-1-1-19-rpm.md b/source/_posts/2010/xine-lib-1-1-19-rpm.md
deleted file mode 100644
index 8236111..0000000
--- a/source/_posts/2010/xine-lib-1-1-19-rpm.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.19 RPM
-author: Daniel
-date: 2010-08-05 21:00:48
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.19. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-xine-lib - The main xine library
-xine-lib-dev - The development xine library (needed if you're building an interface against xine-lib)
-xine-lib-doc - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.6][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[ui]: /2010/xine-ui-0-99-6-rpm.html "xine-ui 0.99.6 RPM • The Bit Badger Blog"
-[pri]: /2009/xine-lib-1-1-16-3-rpm.html "xine-lib 1.1.16.3 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2010/xine-ui-0-99-6-rpm.md b/source/_posts/2010/xine-ui-0-99-6-rpm.md
deleted file mode 100644
index c0df3ce..0000000
--- a/source/_posts/2010/xine-ui-0-99-6-rpm.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.6 RPM
-author: Daniel
-date: 2010-08-06 17:28:09
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-ui
----
-
-Below is the RPM for xine-ui version 0.99.6. See the [About the xine RPMs][abt] post for information on how this RPM was built.
-
-xine-ui - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.1.19][lib].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[lib]: /2010/xine-lib-1-1-19-rpm.html "xine-lib 1.1.19 RPM • The Bit Badger Blog"
-[pri]: /2007/xine-ui-0-99-5-rpm.html "xine-ui 0.99.5 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2011/database-abstraction-v0-8.md b/source/_posts/2011/database-abstraction-v0-8.md
deleted file mode 100644
index efd854f..0000000
--- a/source/_posts/2011/database-abstraction-v0-8.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-layout: post
-title: Database Abstraction v0.8
-author: Daniel
-date: 2011-10-22 21:00:48
-categories:
-- [ Databases, MySQL ]
-- [ Databases, PostgreSQL ]
-- [ Databases, SQL Server ]
-- [ Databases, SQLite ]
-- [ Programming, .NET, C# ]
-- [ Projects, Database Abstraction ]
-tags:
-- abstraction
-- ado.net
-- c#
-- linq
-- linq to sql
-- nhibernate
-summary: An open-source project to allow queries to be defined in code and not tied to a specific database implementation
----
-
-When we began developing C# web applications, we found ourselves in the position of determining what the best way of accessing the database is. We evaluated several technologies...
-
-* **NHibernate** - May be very good, but it was overkill for what we were trying to do.
-* **LINQ to SQL** - This brings C#'s LINQ (Language-Integrated Query) to SQL databases. You create database-aware classes and use LINQ to select from collections, which LINQ to SQL converts to database access. This is a good abstraction, but it relies on SQL Server; as we typically deploy to PostgreSQL, this didn't work. (We also couldn't get DBLinq, a database-agnostic implementation, to work.)
-* **ADO.NET** - This is the tried-and-true database access methodology, released as part of the initial release of the .NET framework. The downside to this is that it encourages SQL in the code at the point of data retrieval; it does not provide a clean separation of data access from data processing.
-* **EF Code First** - This didn't exist; it's also very SQL Server-centric. Not faulting Microsoft for that, especially since they release a free version now; but, as we deploy on Linux, until they release a Linux version, SQL Server is not an option.
-
-With our PHP applications, we had written a database service that read queries from XML files. Then, queries were accessed by name, with parameters passed via arrays. The one thing that ADO.NET has that was useful was the fact that it is based on interfaces. This means that if we wrote something that exposed, manipulated, and depended on `IDataConnection` (instead of `SqlConnection`, the SQL Server implementation of that interface), we could support any implementation of database. The `SqlDataReader` implements `IDataReader` as well. Our solution was becoming apparent.
-
-Over time, we developed what is now the Database Abstraction project hosted on CodePlex _(UPDATE: migrated project to [GitHub][])_. On Thursday, we released the first public release (although the DLLs are in the repository, and are usually current at every commit). If you are looking for a way to separate your data access from the rest of your code, or want a solution that's database-agnostic, check it out. It supports SQL Server, MySQL, PostgreSQL, SQLite, and ODBC connections *, using the data provider name to derive the proper connection to implement. There is also a Mock implementation to support unit tests; this mock can provide data, providing a useful way to test methods. Finally, there is a membership and role provider based on Database Abstraction; simply configure the connection string, create the database tables, and away you go! **
-
-A pre-release version is already in production use in our [PrayerTracker][] application, and others are being built around it. If this sounds like something that could help your project, certainly feel free to check it out!
-
-_\* Oracle is omitted from this list, as their DLL had redistribution restrictions; this meant that the source code repository, upon check-out, would have build errors. There may be an Oracle implementation in the future (it would be trivial), but there is not one now._
-
-_\** The membership and role providers are untested; they will be tested and tweaked by version 0.9._
-
-
-[PrayerTracker]: //prayer.djs-consulting.com "PrayerTracker"
-[GitHub]: //github.com/danieljsummers/DatabaseAbstraction
diff --git a/source/_posts/2011/hcsb-verse-of-the-day-plus-3-0-1-wordpress-plug-in.md b/source/_posts/2011/hcsb-verse-of-the-day-plus-3-0-1-wordpress-plug-in.md
deleted file mode 100644
index d64a0c5..0000000
--- a/source/_posts/2011/hcsb-verse-of-the-day-plus-3-0-1-wordpress-plug-in.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-layout: post
-title: "HCSB Verse of the Day (Plus) 3.0.1 - WordPress Plug-In"
-author: Daniel
-date: 2011-09-03 22:30:09
-categories:
-- [ Programming, PHP, WordPress ]
-tags:
-- esv
-- hcsb
-- kjv
-- niv
-- nkjv
-- plug-in
-- update
-- widget
-- wordpress
-summary: New features available in this plug-in
----
-
-After a nearly four-year run at version 2, the HCSB Verse of the Day plug-in has been updated to version 3. The latest version available is 3.0.1, which contains a quick fix that was found just after I had released version 3. When you see that ".0.1," just think, "Oh, this was written by a human!"
-
-Major changes in this version include:
-
-* The addition of "(Plus)" to the name, as this version supports five different translations - in addition to the Holman Christian Standard Bible (HCSB), it now supports the English Standard Version (ESV), the New King James Version (NKJV), the New International Version (NIV), and the King James Version (KJV).
-* A new settings page, where you can select the version.
-* A widget, that will drop right in any widget zone.
-* The replacement of several function calls that have been deprecated in the WordPress API over the past 3 years and 8 months.
-* Formal dropping of support for PHP 4, following WordPress's lead in 3.2.
-
-While a lot of the code is different, if you only used the template tags, you should notice nothing different with this release. You can [download HCSB Verse of the Day (Plus) 3.0.1][pi] at the WordPress Plug-In Directory, or upgrade on the WordPress Plug-In Administration Page in your blog.
-
-
-[pi]: //wordpress.org/extend/plugins/hcsb-verse-of-the-day/ "HCSB Verse of the Day (Plus) • WordPress Plug-In Directory"
diff --git a/source/_posts/2011/spring-clean-your-windows-machine.md b/source/_posts/2011/spring-clean-your-windows-machine.md
deleted file mode 100644
index 3562e1a..0000000
--- a/source/_posts/2011/spring-clean-your-windows-machine.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-layout: post
-title: Spring Clean Your Windows Machine
-author: Daniel
-date: 2011-05-07 15:48:26
-categories:
-- Security and Privacy
-tags:
-- compcln
-- security
-- spring
-- vista
-- windows
-- winsxs
-summary: Reclaim significant space on your Windows drive by deleting old versions of system libraries
----
-
-Spring has sprung, the grass has riz; do you know where your HD space is? If you're running Windows Vista or Windows 7, you may have some unclaimed disk space waiting for you. (Disclaimer: I am not telling you to do anything to your computer, and I maintain no liability for the effects of the commands you enter. I'm sharing what worked for me.)
-
-Windows Vista was a rewrite of Windows; as part of this, they developed Windows Side by Side (WinSxS) to deal with the conflicting/removed DLL issue that plagued Windows in the past. SxS maintains components, and programs continue to use their components unless they specifically ask to use a new one. This keeps upgrades from breaking older programs, and makes all upgrades reversible. With Vista currently at SP2, you probably have lots of versions of several of these components, and if you have a smaller drive, they can be pinching your disk space. If you're content with the way your computer is running, SP2 includes a utility called COMPCLN.EXE which will make these upgrades permanent by removing unused components. WinSxS knows which components are referenced by current software, so you can run this without worrying that you'll break an older program.
-
-To run it, click the Windows icon on the bottom left of the task bar, type "cmd", then press Enter. When the command prompt window opens, type "compcln" and press Enter. It will give you a y/n prompt, then clean the old components off your computer. Windows also makes restore points, which is a saved group of files and settings that exist before installing updates. If you're cleaning the components, you can also delete these as well. To run this, open the control panel and search for "disk cleanup". Choose your C: drive, then click the "More Files" tab. The restore point button is in the middle of that page.
-
-Finally, Microsoft has released [Microsoft Security Essentials][mse], an anti-virus/anti-malware program for Windows XP through 7. If you're tired of "buy the real version" nags or renewing subscriptions, this is the tool for you. It's a tool that many feel should have been included in Windows for a long time (though the reasons why it hasn't been are outside the scope of this how-to), it works well, and it's free.
-
-
-[mse]: //www.microsoft.com/en-us/safety/pc-security/microsoft-security-essentials.aspx "Microsoft Security Essentials"
diff --git a/source/_posts/2011/tech-blog-3-0.md b/source/_posts/2011/tech-blog-3-0.md
deleted file mode 100644
index 21449bd..0000000
--- a/source/_posts/2011/tech-blog-3-0.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: post
-title: 'Tech Blog 3.0 (aka "You win, PHP...")'
-author: Daniel
-date: 2011-08-24 22:12:44
-categories:
-- General Info
-- [ Programming, .NET, Mono ]
-- [ Programming, PHP ]
-- [ Web Servers, Apache ]
-tags:
-- apache
-- blog
-- blogengine
-- mpm
-- php
-- pre-fork
-- theme
-- thread
-- wordpress
-- worker
-summary: This site has returned to WordPress
----
-
-After a little over a year running on [Tech Blog 2.0][], you are now viewing version 3.0. For this version, we've returned to [WordPress][] from [BlogEngine][]. There are several issues that colluded to drive this change, most of which surrounded PHP and its crazy behavior. (Geeky details follow - skip to the paragraph starting with "Bottom line:" if you don't want the geek stuff. I bolded it so it would be easy to spot.)
-
-PHP's recommended configuration is to run under Apache using the pre-fork multi-processing module (MPM). The advantage to this is that Apache does not have to spin off another process to handle each request; it handles it in the same thread. However, this means that each instance of the server must have all enabled modules loaded. This means that each instance of the server (AKA "thread") is very large, so the number of threads run is lower (typically 5-15 in a server the size we're on). Also, this means that each thread can only handle one request at a time; if you have 7 threads configured, each serving one of 7 requests, and an 8th request comes it, it has to wait for one to finish. If the requests are served quickly, this may not be a problem; however, the avalanche of request that follow the typical front-page mention on mega-blogs can easily overwhelm it.
-
-To fix this problem, there is another MPM, this one called worker. In this scenario, there are spare thread waiting to fill requests, and these can spawn other threads to do further work if required. So, the Apache threads would realize that a request needs to be handled by PHP, and pass it off to that process to be completed. The Apache memory footprint is much smaller; it serves the images, scripts, and other static files, and passes off the requests that require heavy lifting. PHP, then, has a (FastCGI) process where it receives these requests, processes them, and returns the response to the caller. Because each of these threads only has to load the PHP requirements, they are smaller too, so you can have more threads processing at the same time; you just might survive that front-page mention! (This is the same technique applied by LightTPD and Nginx, two other servers I tried at various times.)
-
-It is in this scenario where PHP fails to live up to its expectations. These PHP processes would simply stop responding, but the controller thinks they're still there. The end result to the user is a site that just sits and waits for output that will never come. Eventually, they may receive a Gateway Timeout or Bad Gateway error. The problem is worse on slower sites, but even popular sites seemed to fall victim to this from time to time. This was also a problem whether PHP controlled its threads, or Apache controlled them.
-
-The one thing that really perturbs me is instability. If something is broken, I can fix it; if it works, I can fix it 'til it's broke. :) But something that works sometimes, and other times doesn't, simply won't fly. I was able to introduce some stability by restarting the server 4 times a day, but that's a band-aid, not a long term solution. I was tired of fighting.
-
-**Bottom line**: the configuration required for a stable server is in opposition to a lean-and-mean configuration. So, I installed the required Apache modules, and will continue to run my PHP-serving server at a configuration twice as large as it needs to be. I'll eventually move the Mono (.NET) processes to another machine, where the fast configuration won't cause stability problems.
-
-But, PHP isn't all. While I would still heartily recommend BlogEngine.NET to someone who was going to serve the blog from a Windows machine, but I had some issues getting upgrades to go smoothly under Mono. It also is optimized for fast serving, at the expense of RAM. At this point, that's not the tradeoff we need.
-
-Finally, with this update, the blog has received its first new theme. It's a clean, clear theme that should serve the content well. Plus, the social media icons up in the corner are just too cool, IMO. I've also applied tags to all posts except the "My Linux Adventure" series, and this theme displays them. (Comments are not here now, but will be migrated shortly.)
-
-So, there you have it. Enjoy!
-
-
-[Tech Blog 2.0]: /2010/tech-blog-2-0.html "Tech Blog 2.0 • The Bit Badger Blog"
-[WordPress]: //wordpress.org "WordPress"
-[BlogEngine]: http://dnbe.net/docs/ "BlogEngine.NET"
diff --git a/source/_posts/2011/xine-lib-1-1-20-rpm.md b/source/_posts/2011/xine-lib-1-1-20-rpm.md
deleted file mode 100644
index b2318b3..0000000
--- a/source/_posts/2011/xine-lib-1-1-20-rpm.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.20 RPM
-author: Daniel
-date: 2011-11-13 20:20:16
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.20. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-[xine-lib][] - The main xine library
-[xine-lib-dev][] - The development xine library (needed if you're building an interface against xine-lib)
-[xine-lib-doc][] - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.6][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-lib]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-1.1.20-2.x86_64.rpm
-[xine-lib-dev]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine-dev-1.1.20-2.x86_64.rpm
-[xine-lib-doc]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-doc-1.1.20-2.noarch.rpm
-[ui]: /2010/xine-ui-0-99-6-rpm.html "xine-ui 0.99.6 RPM • The Bit Badger Blog"
-[pri]: /2010/xine-lib-1-1-19-rpm.html "xine-lib 1.1.19 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2011/your-mothers-maiden-name-is-useless.md b/source/_posts/2011/your-mothers-maiden-name-is-useless.md
deleted file mode 100644
index eea045a..0000000
--- a/source/_posts/2011/your-mothers-maiden-name-is-useless.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-layout: post
-title: Your Mother's Maiden Name Is Useless
-author: Daniel
-date: 2011-10-04 18:10:36
-categories:
-- Security and Privacy
-tags:
-- answer
-- facebook
-- maiden
-- question
-- security
-summary: With the advent of social media, be smart about your security questions and answers
----
-
-...well, at least as a security question.
-
-This is not a new thing, and is the reason that most places allow you to define security questions other than that. With the prevalence of information available online, it really is not much of a stretch for a would-be attacker to determine; if you are connected to your mother via a social network like Facebook, where having a public maiden name is encouraged to help you be found, it becomes trivial.
-
-If you still have "mother's maiden name" as a security question somewhere, there's no need to panic. There are two simple options. You can see if there is another question you can use in its place, and just use that one. If you can't (or don't want to) do that, lie make something up; there is no requirement that the answer is accurate, only that you can match the answer when challenged. What you should **not** do is demand that your mother remove that information from her profile. This is unnecessary, as the information has already been released; plus, "security through obscurity" is of limited benefit.
-
-Just a quick tip to help keep you secure online...
diff --git a/source/_posts/2012/4040-web-service-for-2012.md b/source/_posts/2012/4040-web-service-for-2012.md
deleted file mode 100644
index 72a3af0..0000000
--- a/source/_posts/2012/4040-web-service-for-2012.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-layout: post
-title: 40/40 Web Service for 2012
-author: Daniel
-date: 2012-06-17 22:21:01
-categories:
-- [ Programming, Web Services ]
-tags:
-- '4040'
-- api
-- hoffmantown
-- english
-- español
-- html
-- json
-- prayer
-- prayertracker
-- rest
-- soap
-- web service
-- wsdl
-- xml
-summary: The 40/40 Prayer Vigil has been updated for 2012, as a REST API supporting both English and Spanish
----
-
-Back in 2010, we wrote a [web service][post] for the [40/40 Prayer Vigil][4040] organized by the [Ethics and Religious Liberty Commission][erlc] of the Southern Baptist Convention. This allowed us to use the content in multiple places. They are doing another vigil this year, but the service we wrote two years ago was not terribly reusable.
-
-This year, we have developed a reusable web service that should hold up for 2014 and beyond. _(Acronym alert - non-programmers skip the next sentence.)_ This one has a REST API instead of SOAP and WSDL, and supports XML, JSON, and HTML output formats. This year, it also supports both English and Español.
-
-The REST API start page is at this URL no longer active. The prayer guides require an output format, a language, the Scripture version, whether the guide is for a day or an hour, and the day or hour number. There are lookup transactions for lists of available output formats, languages, and Scripture versions, and lookups for converting a date to a day number and a date/time to an hour number.
-
-There will be a WordPress plug-in shortly that will utilize this to display the current day or hour's prayer guide directly on your blog; we'll make another post when that is available. Also, starting September 26th (the first day of the vigil), it will be available for display with no login required at the Hoffmantown Prayer and [PrayerTracker][pt] websites. Developers, the service is available now; if you want to write code to utilize the service, you've got 3 months to make it work!
-
-
-[post]: /2010/4040-web-service.html "40/40 Web Service • The Bit Badger Blog"
-[4040]: //4040prayer.wordpress.com "40/40 Prayer Vigil"
-[erlc]: http://erlc.com "Ethics and Religious Liberty Commission"
-[pt]: //prayer.djs-consulting.com "PrayerTracker"
diff --git a/source/_posts/2012/4040-wordpress-plugin.md b/source/_posts/2012/4040-wordpress-plugin.md
deleted file mode 100644
index f93eb0d..0000000
--- a/source/_posts/2012/4040-wordpress-plugin.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-layout: post
-title: 40/40 WordPress Plugin
-author: Daniel
-date: 2012-07-01 14:27:45
-categories:
-- [ Programming, PHP, WordPress ]
-- [ Programming, Web Services ]
-summary: A WordPress plugin is now available to display the suggested prayers for the 40/40 Prayer Vigil
----
-
-The WordPress plugin for the 40/40 Prayer Vigil has just been published! You can download it from your plugin menu, or by visiting [its home on the WordPress Plugin Directory][pi].
-
-The plugin provides a widget that utilizes [the web service about which we previously wrote][post] to display the prayer guide for each day. You can configure whether you want it to display 40 days or 40 hours; what language to retrieve; the translation version for the Scripture links displayed with each day's guide; and the number of overlap days (it will display a "Coming Soon" entry before and a "Thanks for Praying" entry after). Use is pretty simple; just drop it into a widgetized area of your theme. It will probably look best with at least 200 horizontal pixels, although it will wrap to any sort of narrowness.
-
-Version 2012.0 is the version that's up there now. The Spanish translations of the options menu is not done yet, but you can specify Spanish prayer guides. Version 2012.1 will contain the localized options menu. If you run into any problems using it, you can submit issues against it at its WordPress Plugin Directory page.
-
-
-[pi]: //wordpress.org/plugins/4040-prayer-vigil/ "40/40 Prayer Vigil • WordPress Plugin Directory"
-[post]: /2012/4040-web-service-for-2012.html "40/40 Web Service for 2012 • The Bit Badger Blog"
diff --git a/source/_posts/2012/xine-lib-1-1-20-1-rpm.md b/source/_posts/2012/xine-lib-1-1-20-1-rpm.md
deleted file mode 100644
index 36cacdf..0000000
--- a/source/_posts/2012/xine-lib-1-1-20-1-rpm.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.20.1 RPM
-author: Daniel
-date: 2012-01-02 11:41:10
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.20.1. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-[xine-lib][] - The main xine library
-[xine-lib-dev][] - The development xine library (needed if you're building an interface against xine-lib)
-[xine-lib-doc][] - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.6][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-lib]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-1.1.20.1-2.x86_64.rpm
-[xine-lib-dev]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine-dev-1.1.20.1-2.x86_64.rpm
-[xine-lib-doc]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-doc-1.1.20.1-2.noarch.rpm
-[ui]: /2010/xine-ui-0-99-6-rpm.html "xine-ui 0.99.6 RPM • The Bit Badger Blog"
-[pri]: /2011/xine-lib-1-1-20-rpm.html "xine-lib 1.1.20 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2012/xine-lib-1-1-21-rpm.md b/source/_posts/2012/xine-lib-1-1-21-rpm.md
deleted file mode 100644
index 7cf887c..0000000
--- a/source/_posts/2012/xine-lib-1-1-21-rpm.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-layout: post
-title: xine-lib 1.1.21 RPM
-author: Daniel
-date: 2012-06-10 16:52:27
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-lib
----
-
-Below are the library and development RPMs for xine-lib version 1.1.21. These were built on Ubuntu Linux and converted to RPM using alien. Be sure to check out the [About the xine RPMs][abt] post for more information.
-
-[xine-lib][] - The main xine library
-[xine-lib-dev][] - The development xine library (needed if you're building an interface against xine-lib)
-[xine-lib-doc][] - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.7][ui].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-lib]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-1.1.21-2.x86_64.rpm
-[xine-lib-dev]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine-dev-1.1.21-2.x86_64.rpm
-[xine-lib-doc]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine1-doc-1.1.21-2.noarch.rpm
-[ui]: /2012/xine-ui-0-99-7-rpm.html "xine-ui 0.99.7 RPM • The Bit Badger Blog"
-[pri]: /2012/xine-lib-1-1-20-1-rpm.html "xine-lib 1.1.20.1 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2012/xine-ui-0-99-7-rpm.md b/source/_posts/2012/xine-ui-0-99-7-rpm.md
deleted file mode 100644
index d4f9d8c..0000000
--- a/source/_posts/2012/xine-ui-0-99-7-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.7 RPM
-author: Daniel
-date: 2012-06-10 16:55:11
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-ui
----
-
-Below is the RPM for xine-ui version 0.99.7. See the [About the xine RPMs][abt] post for information on how this RPM was built.
-
-[xine-ui][] - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.1.21][lib].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-ui]: //hosted.djs-consulting.com/software/xine/xine-ui/xine-ui-0.99.7-2.x86_64.rpm
-[lib]: /2012/xine-lib-1-1-21-rpm.html "xine-lib 1.1.21 RPM • The Bit Badger Blog"
-[pri]: /2010/xine-ui-0-99-6-rpm.html "xine-ui 0.99.6 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2013/oracle-sql-developer-3-2-debian-package.md b/source/_posts/2013/oracle-sql-developer-3-2-debian-package.md
deleted file mode 100644
index 35bb30c..0000000
--- a/source/_posts/2013/oracle-sql-developer-3-2-debian-package.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-layout: post
-title: Oracle SQL Developer 3.2 Debian Package
-author: Daniel
-date: 2013-06-22 23:24:04
-categories:
-- [ Databases, Oracle ]
-- [ Programming, SQL ]
-tags:
-- deb
-- java
-- oracle
-- sql developer
-summary: A new version of Oracle's SQL Developer
----
-
-Oracle has released version 3.2 (.20.09) of their SQL Developer tool. They're still releasing RPMs, so developers on Debian-based systems need to use alien to install it on their machines. We have done that, and have made this available for others to use as well. What makes this particular release of SQL Developer so great is that [it now runs reliably under Java 1.7][java7] - no more keeping a 1.6 JDK floating around just for SQL Developer!
-
-The .deb package [can be downloaded here][deb], or you can browse current and previously posted packages [in the "SQL Developer" directory][dir] of the Bit Badger Solutions Software Repository.
-
-
-[java7]: //www.thatjeffsmith.com/archive/2013/06/oracle-sql-developer-and-java-7/ "Oracle SQL Developer and Java 7 • That Jeff Smith"
-[deb]: //hosted.djs-consulting.com/software/sqldeveloper/sqldeveloper_3.2.20.09.87-2_all.deb "SQL Developer 3.2.20.09 Debian Package"
-[dir]: //hosted.djs-consulting.com/software/sqldeveloper/ "SQL Developer • Bit Badger Solutions Linux Software Repository"
diff --git a/source/_posts/2014/a-handy-c-sharp-async-utility-method.md b/source/_posts/2014/a-handy-c-sharp-async-utility-method.md
deleted file mode 100644
index 5210b91..0000000
--- a/source/_posts/2014/a-handy-c-sharp-async-utility-method.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-layout: post
-title: A Handy C# Async Utility Method
-author: Daniel
-date: 2014-08-04 19:48:43
-categories:
-- [ Programming, .NET, C# ]
-tags:
-- asynchronous
-- c#
-- utility
-summary: Using async when you can't use async
----
-
-In the course of writing C# code utilizing the new (for 4.5.1) [Task-based asynchronous programming][async], I've run across a couple of places where the `await` keyword either is not allowed (a catch block or a property accessor) or the `async` keyword greatly complicates the syntax (lambda expressions). I've found myself writing this method for two different projects, and so I thought I would drop this Q&D, more-comments-than-code utility method here for others to use if you see the need.
-
-_(UPDATE: This works well in console applications; it can cause deadlocks in desktop and web apps. Test before you rely on it.)_
-
-{% codeblock lang:csharp %}
-///
-/// Get the result of a task in contexts where the "await" keyword may be prohibited
-///
-/// The return type for the task
-/// The task to be awaited
-/// The result of the task
-public static T TaskResult(Task task)
-{
- Task.WaitAll(task);
- return task.Result;
-}
-{% endcodeblock %}
-
-And, in places where you can't do something like this...
-
-{% codeblock ExampleClass.cs lang:csharp %}
-///
-/// A horribly contrived example class
-///
-/// Don't ever structure your POCOs this way, unless EF is handling the navigation properties
-public class ExampleClass
-{
- ///
- /// A contrived ID to a dependent entity
- ///
- public int ForeignKeyID { get; set; }
-
- ///
- /// The contrived dependent entity
- ///
- public DependentEntity DependentEntity
- {
- get
- {
- // Does not compile; can't use await without async, can't mark a property as async
- return await Data.DependentEntities
- .FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID);
- }
- }
-}
-{% endcodeblock %}
-
-...you can instead do this in that "DependentEntity" property...
-
-{% codeblock lang:csharp %}
- ///
- /// The contrived dependent entity
- ///
- public DependentEntity DependentEntity
- {
- get
- {
- return UtilClass.TaskResult(Data.DependentEntities
- .FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID));
- }
- }
-{% endcodeblock %}
-
-
-[async]: //msdn.microsoft.com/EN-US/library/hh191443(v=vs.110).aspx "Asynchronous Programming with Async and Await - MSDN"
diff --git a/source/_posts/2014/gxine-0-5-908-rpm.md b/source/_posts/2014/gxine-0-5-908-rpm.md
deleted file mode 100644
index 2ef4048..0000000
--- a/source/_posts/2014/gxine-0-5-908-rpm.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-layout: post
-title: gxine 0.5.908 RPM
-author: Daniel
-date: 2014-08-24 19:37:37
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- gxine
-- rpm
-- xine-lib
----
-
-Below are the RPMs for gxine version 0.5.908. See [About the xine RPMs][abt] for information on how these were built.
-
-[gxine][] - The main gxine program
-[gxineplugin][] - Browser plugin library for gxine
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.2.6][lib]. The latest [xine-lib 1.1 is 1.1.21][lib1].
-
-(To save disk space, only the current release and two prior releases will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[gxine]: //hosted.djs-consulting.com/software/xine/gxine/gxine-0.5.908-2.x86_64.rpm
-[gxineplugin]: //hosted.djs-consulting.com/software/xine/gxine/gxineplugin-0.5.908-2.x86_64.rpm
-[lib]: /2014/xine-lib-1-2-6-rpm.html "xine-lib 1.2.6 RPM • The Bit Badger Blog"
-[lib1]: /2012/xine-lib-1-1-21-rpm.html "xine-lib 1.1.21 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2014/xine-lib-1-2-6-rpm.md b/source/_posts/2014/xine-lib-1-2-6-rpm.md
deleted file mode 100644
index dfc4dd5..0000000
--- a/source/_posts/2014/xine-lib-1-2-6-rpm.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-layout: post
-title: xine-lib 1.2.6 RPM
-author: Daniel
-date: 2014-08-24 19:33:28
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- gxine
-- rpm
-- xine-lib
-- xine-ui
----
-
-Below are the library and development RPMs for xine-lib version 1.2.6. Be sure to check out the [About the xine RPMs][abt] post for information on how these were built.
-
-[xine-lib][] - The main xine library
-[xine-lib-dev][] - The development xine library (needed if you're building an interface against xine-lib)
-[xine-lib-doc][] - Documentation
-
-You'll also need a user interface - as of this release, the most current release of [xine-ui is 0.99.9][ui], and the most current release of [gxine is 0.5.908][gxine].
-
-(To save disk space, only the current release and two prior releases in the 1.2-series will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-lib]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine2-1.2.6-2.x86_64.rpm
-[xine-lib-dev]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine2-dev-1.2.6-2.x86_64.rpm
-[xine-lib-doc]: //hosted.djs-consulting.com/software/xine/xine-lib/libxine2-doc-1.2.6-2.noarch.rpm
-[ui]: /2014/xine-ui-0-99-9-rpm.html "xine-ui 0.99.9 RPM • The Bit Badger Blog"
-[gxine]: /2014/gxine-0-5-908-rpm.html "gxine 0.5.908 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2014/xine-ui-0-99-8-rpm.md b/source/_posts/2014/xine-ui-0-99-8-rpm.md
deleted file mode 100644
index 588f22a..0000000
--- a/source/_posts/2014/xine-ui-0-99-8-rpm.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.8 RPM
-author: Daniel
-date: 2014-02-26 05:42:19
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-ui
----
-
-Below is the RPM for xine-ui version 0.99.8. See the [About the xine RPMs][abt] post for information on how this RPM was built.
-
-[xine-ui][] - The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.1.21][lib].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-ui]: //hosted.djs-consulting.com/software/xine/xine-ui/xine-ui-0.99.8-2.x86_64.rpm
-[lib]: /2012/xine-lib-1-1-21-rpm.html "xine-lib 1.1.21 RPM • The Bit Badger Blog"
-[pri]: /2012/xine-ui-0-99-7-rpm.html "xine-ui 0.99.7 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2014/xine-ui-0-99-9-rpm.md b/source/_posts/2014/xine-ui-0-99-9-rpm.md
deleted file mode 100644
index f60cd2d..0000000
--- a/source/_posts/2014/xine-ui-0-99-9-rpm.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: xine-ui 0.99.9 RPM
-author: Daniel
-date: 2014-08-24 19:24:14
-categories:
-- [ Hosted 64-bit Software, xine RPMs ]
-tags:
-- rpm
-- xine-ui
----
-
-Below is the RPM for xine-ui version 0.99.9. See the [About the xine RPMs][abt] post for information on how this RPM was built.
-
-[xine-ui][] — The user interface
-
-To use this, you'll also need xine-lib - as of this release, the most recent release of [xine-lib is 1.2.6][lib]. The latest [xine-lib 1.1 is 1.1.21][lib1].
-
-(To save disk space, only the current release and two [prior releases][pri] will be maintained.)
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[xine-ui]: //hosted.djs-consulting.com/software/xine/xine-ui/xine-ui-0.99.9-2.x86_64.rpm
-[lib]: /2014/xine-lib-1-2-6-rpm.html "xine-lib 1.2.6 RPM • The Bit Badger Blog"
-[lib1]: /2012/xine-lib-1-1-21-rpm.html "xine-lib 1.1.21 RPM • The Bit Badger Blog"
-[pri]: /2014/xine-ui-0-99-8-rpm.html "xine-lib 0.99.8 RPM • The Bit Badger Blog"
diff --git a/source/_posts/2017/generating-a-jekyll-site-on-mercurial-hg-push.md b/source/_posts/2017/generating-a-jekyll-site-on-mercurial-hg-push.md
deleted file mode 100644
index e117fa7..0000000
--- a/source/_posts/2017/generating-a-jekyll-site-on-mercurial-hg-push.md
+++ /dev/null
@@ -1,115 +0,0 @@
----
-layout: post
-title: Generating a Jekyll Site on Mercurial (Hg) Push
-author: Daniel
-date: 2017-02-18 12:41:00
-categories:
-- Linux
-- [ Programming, Jekyll ]
-tags:
-- commit
-- cron
-- hg
-- jekyll
-- mercurial
-- push
-- regenerate
-- rsync
-- scp
-- ssh
-summary: The process we use to regenerate Jekyll sites when a push occurs to a private Mercurial (Hg) repository
----
-
-As we mentioned in [our last post][v4], we plan to share aspects of how we moved to [Jekyll][]. This is the first of these posts.
-
-## Background
-
-With a database-based solution, updating is easy; when the user updates content through the user interface, the new content is served when the page or post is requested. However, with a static site, an "update" is technically any change to the underlying files from which the site is generated. Typically, though, this is marked by source control commit and push to a master repository. [GitHub Pages][ghp], the product for which Jekyll was developed, uses this as a flag to regenerate the site. We weren't using GitHub*, though - we were using [Mercurial][hg] (Hg) for our source code control, with the master repository on a different server than the one from which the site is served.
-
-_\* There were a few reasons we did not wish to host our sites using GitHub, none of which are pertinent to how this works._
-
-## Options
-
-With the need to regenerate the site after each site's master repository receives a push, there were a few different options we considered.
-
-1. When a push occurs, regenerate the site on the Hg server, then use `scp` to delete the old files from and copy the new files to the web server.
-2. Set up a sandbox on the Hg server that updates and regnerates each time a push occurs, and run `rsync` on the web server to check for updates every so often.
-3. When a push occurs, notify the web server, and have it regenerate the site.
-
-The first option has the potential to run afoul of SSH rate limits, plus has the potential to require much more data transfer than option 3. The second option had the advantage of running a process local to the Hg server, but would have required disk space utilization that we didn't really need; and, as Jekyll regenerates all the pages in a site, `rsync` would have likely ended up transferring all the data for every update anyway, losing one of its benefits. The third option required Jekyll to be installed on the web server, and uses it for processing, potentially taking cycles that could be used to serve web pages.
-
-Eventually, we decided to go with option 3.
-
-## Script All the Things
-
-On the Hg server, in the master repository for each site, we put the following in `.hg/hgrc` _(the following examples are for this site)_:
-
-{% codeblock hgrc lang:shell %}
-[hooks]
-incoming = /opt/jobs/notify.tech-blog.sh
-{% endcodeblock %}
-
-...and then, `notify.tech-blog.sh`...
-
-{% codeblock notify.tech-blog.sh lang:shell %}
-#!/bin/bash
-ssh user@web.server touch /opt/jobs/jekyll/.tech-blog
-{% endcodeblock %}
-
-That is the only logic required on the Hg server. Now, over on the web server, we need logic to regenerate the site and make it live. Since we have multiple sites, we wrote a script that has a few variables, so it could be duplicated for other sites. The following is `tech-blog.sh`:
-
-{% codeblock tech-blog.sh lang:shell %}
-##
-## DJS Consulting Tech Blog Jekyll Build Script
-##
-## This will check out, build, and replace a Jekyll-generated site. Just update
-## the parts under the "Env" heading for the specific site.
-##
-
-## Env
-REPO=jekyll.tech-blog
-DEST=/path/to/public/techblog
-TRIGGER=.tech-blog
-## /Env
-
-cd /opt/jobs/jekyll
-
-if [ -e $TRIGGER ]
-then
- rm $TRIGGER
-
- ## Check out the site and build it
- hg clone ssh://user@hg.server/HgPath/$REPO $REPO
- cd $REPO
- jekyll build
-
- ## Copy it to the proper directory
- cd _site
- rm -r $DEST/*
- cp -r * $DEST
-
- ## Clean up
- cd ../..
- rm -r $REPO
-fi
-{% endcodeblock %}
-
-This script isn't perfect; it needs to check the exit code from the Jekyll build process before whacking the current site (and notifying for a failed build would be a nice addition). However, with Jekyll being the same on both development and production, and a single committer, this is fine for our purposes.
-
-Finally, each script needs to be run to check for the presence of the semaphore (or `TRIGGER`, as the script calls it). The following cron definition will check every 4 minutes for a change.
-
-{% codeblock crontab lang:shell %}
-*/4 * * * * /opt/jobs/jekyll/tech-blog.sh > /dev/null
-{% endcodeblock %}
-
-## Conclusion
-
-Overall, we're pleased with the results. The inter-server communication is light, only requiring one initiated `ssh` connection from each server, so we won't run afoul of rate limits. With the work being done on the destination server, the amount of time where there are no files in the directory (between the `rm -r $DEST/*` and the time the `cp -r * $DEST` finishes) is very short; it would have been much longer if the directory were being repopulated across the network, or more complex if we added a staging area on the web server. Each piece can be run separately, and if we've committed a post with a future date, we can run the same `touch` command to make that post appear.
-
-Next time, we'll discuss our experiences converting a non-WordPress site.
-
-
-[v4]: /2017/tech-blog-v4.html "Tech Blog v4 • The Bit Badger Blog"
-[Jekyll]: //jekyllrb.com "Jekyll"
-[ghp]: //pages.github.com "GitHub Pages"
-[hg]: //www.mercurial-scm.org "Mercurial (Hg)"
diff --git a/source/_posts/2017/mapping-categories-and-tags-with-hexo.md b/source/_posts/2017/mapping-categories-and-tags-with-hexo.md
deleted file mode 100644
index 34b3257..0000000
--- a/source/_posts/2017/mapping-categories-and-tags-with-hexo.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: Mapping Categories and Tags with Hexo
-author: Daniel
-date: 2017-09-02 18:35:15
-categories:
-- [ Programming, JavaScript, Hexo ]
-tags:
-- category
-- gitter
-- hexo
-- jekyll
-- tag
-- yaml
----
-This blog moved today from [Jekyll][] to [Hexo][] (and it's now [open source][gh] as well). One of the final issues I had when wrapping up the conversion was how to handle categories and tags that do not necessarily have a slug that can be naturally derived from the name. Take the "C#" category, for example. The normal slug for that category would be `c`, which is an entirely different programming language; interestingly, "C++" will also normally get its slug as `c`.
-
-Within Hexo's default `_config.yml` file, there are two empty items named `category_map` and `tag_map`; their comments allude to a mapping, but I could not find what the proper syntax was for those items. We hopped onto the Hexo [Gitter][] chat and asked the question, and someone pointed us to [this issue][iss]. To define a mapping, create an item under either the `category_map` or `tag_map` top-level item. The maps for this site, as they currently are, look like this:
-
-{% codeblock _config.yml lang:yaml %}
-category_map:
- C++: c-plus-plus
- C#: c-sharp
- .NET: dot-net
-tag_map:
- c#: c-sharp
- .net: dot-net
-{% endcodeblock %}
-
-As you can see by hovering over the links in the sidebar, "Programming > .NET > C#" ends up with a URL ending with `/programming/dot-net/c-sharp/`, which is exactly what we were looking for.
-
-
-[Jekyll]: //jekyllrb.com "Jekyll"
-[Hexo]: //hexo.io "Hexo"
-[gh]: //github.com/danieljsummers/blog.bitbadger.solutions "The Bit Badger Blog • GitHub"
-[Gitter]: //gitter.im "Gitter"
-[iss]: //github.com/hexojs/hexo/issues/908#issuecomment-62913729 "Hexo category_map Issue"
diff --git a/source/_posts/2017/tech-blog-v4.md b/source/_posts/2017/tech-blog-v4.md
deleted file mode 100644
index 23f1b4c..0000000
--- a/source/_posts/2017/tech-blog-v4.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: post
-title: Tech Blog v4
-author: Daniel
-date: 2017-02-16 19:21:00
-categories:
-- General Info
-- [ Web Servers, nginx ]
-tags:
-- blog
-- jekyll
-- nginx
-- wordpress
-summary: The blog moves from WordPress to Jekyll
----
-
-From [August 2011][v3] until today, this site has been running under WordPress. During this time, we have done many experiments with several other blog platforms, but none of them made it to the "import all the old stuff from this one - this is what we're looking for!" stage. As you may have already guessed, though, this is no longer the case. WordPress does what it does very well. However, the last post before this one was August... of 2014! That means that, every page served from this site, a script was run on the server that accessed a database and dynamically assembled the page. This content did not need to be dynamic - even when there is a new post, there is very little in the way of dynamic content here.
-
-[Jekyll][] is a static site generator; these types of applications generate static sites based on a collection of templates and content files, that can then be served with no backing data store. Now, we can utilize the blazing fast [nginx][] web server to push these files as quick as people can request them, where the request does not even have to escape the process.
-
-There will be more to come on Jekyll; there are at least two posts to be written, one on automating the build process and another on the migration from WordPress. Until then, though, there are redirects that ensure the RSS feeds for both the main blog and the xine RPMs require no changes, and the category pages have redirects as well. If something does not look right, let us know via either of the social media accounts linked above.
-
-
-[v3]: /2011/tech-blog-3-0.html "Tech Blog 3.0 • The Bit Badger Blog"
-[Jekyll]: //jekyllrb.com "Jekyll"
-[nginx]: //nginx.com "nginx"
diff --git a/source/_posts/2017/writing-a-hexo-tag-plugin.md b/source/_posts/2017/writing-a-hexo-tag-plugin.md
deleted file mode 100644
index 8fb08b8..0000000
--- a/source/_posts/2017/writing-a-hexo-tag-plugin.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-layout: post
-title: Writing a Hexo Tag Plugin
-date: 2017-09-09 23:45:17
-author: Daniel
-categories:
-- [ Programming, JavaScript, Hexo ]
-- [ Projects, hexo-tag-scripture ]
-tags:
-- bible
-- hexo
-- jekyll
-- plugin
-- tag
----
-In the process of migrating [Daniel's Weekly Devotions][dwd] to [Hexo][], we ran into a problem that we felt sure a tag plugin could solve.
-
-## The Problem
-
-[Jekyll][]'s Markdown parser follows the original one, where text within an HTML tag is not processed. This can be the desired behavior in many cases, as you could put what would otherwise be translated as Markdown between HTML tags, and the parser/renderer will leave it alone. One of the common features, used multiple times in most posts, are links to Scripture references and blocks of quoted text. We had an `include` to automate the links, but we needed a special class on the `
` tag, which meant that all Scripture blockquotes could not use Markdown (or end up with "smartified" quotes and such; we had to use the HTML entities within these quotes.) We also included the verse numbers as superscripts within the quoted text; more tags.
-
-It looked something like this... _(the "ref" CSS class turns the text red)_
-
-{% codeblock lang:html %}
-
-
- 11 …And Jesus said, “Neither do I condemn you;
- go, and from now on sin no more.”
-
-{% endcodeblock %}
-
-If you've ever edited Markdown, you'll recognize how jarring all that HTML code is within the flow of the otherwise-regular text; and look at all those entities!
-
-## The Solution
-
-We looked through at the [Hexo Plugin List][pl] to find some examples, and began working towards writing a plugin to handle both the links (the part within the `` in the example above) as well as the entire blocks of quoted text. Some tags, like the `{% raw %}{% codeblock %}{% endraw %}` tag, have a start tag and an end tag (`{% raw %}{% endcodeblock %}{% endraw %}`); others, like the `{% raw %}{% youtube %}{% endraw %}` tag, just pass arguments with the tag. _([You can see all the default tags here][tag].)_ Hexo passes two arguments to the tag plugin - the arguments within the (start) tag, plus the content (which is blank for tags that don't have an end tag). The returned value from the plugin call is substituted in the document.
-
-For generating a link, that is pretty easy; it could be an inline tag, and it's just a matter of parsing the arguments and forming a link. For the quotes, we need to make sure that we include the content, and Hexo provides a way to run that content through the Markdown renderer. We are converging on a solution!
-
-Hexo will pick up and execute any `.js` files in the `scripts` directory of the site as its generating it, so the first efforts were just local to that repo. The reference link looked something like this...
-
-{% codeblock esv.js lang:javascript %}
-hexo.extend.tag.register('esv', (args, content) => {
- // option parsing with RegEx, similar to the way their tags do
-
- let reference = arg.trim()
- let urlReference = reference.split(' ').join('+')
-
- return `${reference}${extraText}${versionText}`
-})
-{% endcodeblock %}
-
-...which let the Markdown document go from...
-
-{% codeblock lang:html %}
-John 8:11b (ESV)
-{% endcodeblock %}
-
-...to...
-
-{% codeblock lang:markdown %}
-{% raw %}{% esv John 8:11 extra:b show-version %}{% endraw %}
-{% endcodeblock %}
-
-We refactored the link code to be version-agnostic and extracted it from the `tag.register` function so that we could reuse that for the blockquote citation. This made the local version of the blockquote look something like this:
-
-{% codeblock bible.js lang:javascript %}
-hexo.extend.tag.register('bible', (args, content) => {
- let text = hexo.render.renderSync({ text: content, engine: 'markdown' })
- return `
${text}— ${generateRef(args)}
`
-})
-{% endcodeblock %}
-
-This means that the blockquote can support all of the arguments the inline reference did. We also switched out the `marked` Markdown processor for the `markdown-it` one, which lets us do superscripts by using the `^` character. Revisiting our example under "The Problem," our Markdown source to generate the same blockquote is now:
-
-{% codeblock lang:markdown %}
-{% raw %}{% bible John 8:11 extra:b show-version %}{% endraw %}
-^11^...And Jesus said, "Neither do I condemn you; go, and from
-now on sin no more."
-{% raw %}{% endbible %}{% endraw %}
-{% endcodeblock %}
-
-## The Plugin
-
-The plugin is available on [npm][], is fully [tested][], and its source is [open][]. If you use Hexo, and wish to cite Scripture references in your posts with links where readers can see the text for themselves - enjoy!
-
-
-[dwd]: //devotions.summershome.org
-[Hexo]: //hexo.io
-[Jekyll]: //jekyllrb.com
-[pl]: //hexo.io/plugins/
-[tag]: //hexo.io/docs/tag-plugins.html
-[npm]: //www.npmjs.com/package/hexo-tag-scripture
-[tested]: //ci.appveyor.com/project/danieljsummers/hexo-tag-scripture
-[open]: //github.com/danieljsummers/hexo-tag-scripture
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/authentication.md b/source/_posts/2018/a-tour-of-myprayerjournal/authentication.md
deleted file mode 100644
index 557122a..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/authentication.md
+++ /dev/null
@@ -1,104 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: Authentication"
-date: 2018-08-30 09:30:00
-author: Daniel
-categories:
-- [ Programming, JavaScript, Vue ]
-- [ Programming, .NET, F# ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- api
-- auth0
-- f#
-- giraffe
-- handler
-- javascript
-- json
-- npm
-- spa
----
-_NOTES:_
-- _This is post 5 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-At this point in our tour, we're going to shift to a cross-cutting concern for both app and API - authentication. While authentication and authorization are distinct concerns, the authorization check in myPrayerJournal is simply "Are you authenticated?" So, while we'll touch on authorization, and it will seem like a synonym for authentication, remember that they would not be so in a more complex application.
-
-## Deciding on Auth0
-
-[Auth0][] provides authentication services; they focus on one thing, and getting that one thing right. They support simple username/password authentication, as well as integrations with many other providers. As "minimalist" was one of our goals, not having to build yet another user system was appealing. As an open source project, Auth0 provides these services at no cost. They're the organization behind the [JSON Web Token (JWT)][JWT] standard, which allows base-64-encoded, encrypted JSON to be passed around as proof of identity.
-
-This decision has proved to be a good one. In the introduction, we mentioned all of the different frameworks and server technologies we had used before settling on the one we did. In all but one of these "roads not further traveled"1, authentication worked. They have several options for how to use their service; you can bring in their library and host it yourself, you can write your own and make your own calls to their endpoints, or you can use their hosted version. We opted for the latter.
-
-## Integrating Auth0 in the App
-
-JavaScript seems to be Auth0's primary language. They provide an [npm package][npm] to support using the responses that will be returned from their hosted login page. The basic flow is:
-- The user clicks a link that executes Auth0's `authorize()` function
-- The user completes authorization through Auth0
-- Auth0 returns the result and JWT to a predefined endpoint in the app
-- The app uses Auth0's `parseHash()` function to extract the JWT from the URL (a `GET` request)
-- If everything is good, establish the user's session and proceed
-
-myPrayerJournal's implementation is contained in `AuthService.js` ([mpj:AuthService.js][AuthService.js]). There is a file that is not part of the source code repository; this is the file that contains the configuration variables for the Auth0 instance. Using these variables, we configure the `WebAuth` instance from the Auth0 package; this instance becomes the execution point for our other authentication calls.
-
-## Using JWTs in the App
-
-We'll start easy. The `login()` function simply exposes Auth0's `authorize()` function, which directs the user to the hosted log on page.
-
-The next in logical sequence, `handleAuthentication()`, is called by `LogOn.vue` ([mpj:LogOn.vue][LogOn.vue]) on line 16, passing in our store and the router. (In our [last post][], we discussed how server requests to a URL handled by the app should simply return the app, so that it can process the request; this is one of those cases.) `handleAuthentication()` does several things:
-- It calls `parseHash()` to extract the JWT from the request's query string.
-- If we got both an access token and an ID token:
- - It calls `setSession()`, which saves these to local storage, and schedules renewal (which we'll discuss more in a bit).
- - It then calls Auth0's `userInfo()` function to retrieve the user profile for the token we just received.
- - When that comes back, it calls the store's ([mpj:store/index.js][store]) `USER_LOGGED_ON` mutation, passing the user profile; the mutation saves the profile to the store, local storage, and sets the `Bearer` token on the API service (more on that below as well).
- - Finally, it replaces the current location (`/user/log-on?[lots-of-base64-stuff]`) with the URL `/journal`; this navigates the user to their journal.
-- If something didn't go right, we log to the console and pop up an alert. There may be a more elegant way to handle this, but in testing, the only way to reliably make this pop up was to mess with things behind the scenes. (And, if people do that, they're not entitled to nice error messages.)
-
-Let's dive into the store's `USER_LOGGED_ON` mutation a bit more; it starts on line 68. The local storage item and the state mutations are pretty straightforward, but what about that `api.setBearer()` call? The API service ([mpj:api/index.js][api]) handles all the API calls through the [Axios][] library. Axios supports defining default headers that should be sent with every request, and we'll use the HTTP `Authorization: Bearer [base64-jwt]` header to tell the API what user is logged in. Line 18 sets the default `authorization` header to use for all future requests. (Back in the store, note that the `USER_LOGGED_OFF` mutation (just above this) does the opposite; it clears the `authorization` header. The `logout()` function in `AuthService.js` clears the local storage.)
-
-At this point, once the user is logged in, the `Bearer` token is sent with every API call. None of the components, nor the store or its actions, need to do anything differently; it just works.
-
-## Maintaining Authentication
-
-JWTs have short expirations, usually expressed in hours. Having a user's authentication go stale is not good! The `scheduleRenewal()` function in `AuthService.js` schedules a behind-the-scenes renewal of the JWT. When the time for renewal arrives, `renewToken()` is called, and if the renewal is successful, it runs the result through `setSession()`, just as we did above, which schedules the next renewal as its last step.
-
-For this to work, we had to add `/static/silent.html` as an authorized callback for Auth0. This is an HTML page that sits outside of the Vue app; however, the `usePostMessage: true` parameter tells the renewal call that it will receive its result from a `postMessage` call. `silent.html` uses the Auth0 library to parse the hash and post the result to the parent window.2
-
-## Using JWTs in the API
-
-Now that we're sending a `Bearer` token to the API, the API can tell if a user is logged in. We looked at some of the handlers that help us do that when we looked at the API in depth. Let's return to those and see how that is.
-
-Before we look at the handlers, though, we need to look at the configuration, contained in `Program.fs` ([mpj:Program.fs][Program.fs]). You may remember that Giraffe sits atop ASP.NET Core; we can utilize its `JwtBearer` methods to set everything up. Lines 38-48 are the interesting ones for us; we use the `UseAuthentication` extension method to set up JWT handling, then use the `AddJwtBearer` extension method to configure our specific JWT values. (As with the app, these are part of a file that is not in the repository.) The end result of this configuration is that, if there is a `Bearer` token that is a valid JWT, the `User` property of the `HttpContext` has an instance of the `ClaimsPrincipal` type, and the various properties from the JWT's payload are registered as `Claims` on that user.
-
-Now we can turn our attention to the handlers ([mpj:Handlers.fs][Handlers.fs]). `authorize`, on line 72, calls `user ctx`, which is defined on lines 50-51. All this does is look for a claim of the type `ClaimTypes.NameIdentifier`. This can be non-intuitive, as the source for this is the `sub` property from the JWT3. A valid JWT with a `sub` claim is how we tell we have a logged on user; an authenticated user is considered authorized.
-
-You may have noticed that, when we were describing the entities for the API, we did not mention a `User` type. The reason for that is simple; the only user information it stores is the `sub`. `Request`s are assigned by user ID, and the user ID is included with every attempt to make any change to a request. This eliminates URL hacking or rogue API posting being able to get anything meaningful from the API.
-
-The `userId` function, just below the `user` function, extracts this claim and returns its value, and it's used throughout the remainder of `Handlers.fs`. `add` (line 160) uses it to set the user ID for a new request. `addHistory` (line 192) and `addNote` (line 218) both use the user ID, as well as the passed request ID, to try to retrieve the request before adding history or notes to it. `journal` (line 137) uses it to retrieve the journal by user ID.
-
-
-
-We now have a complete application, with the same user session providing access to the Vue app and tying all API calls to that user. We also use it to maintain data security among users, while truly outsourcing all user data to Microsoft or Google (the two external providers currently registered). We do still have a few more stops on our tour, though; the next is the back end data store.
-
----
-
-1 _Sorry, Elm; it's not you, it's me..._
-
-2 _This does work, but not indefinitely; if I leave the same browser window open from the previous day, I still have to sign in again. I very well could be "doing it wrong;" this is an area where I probably experienced the most learning through creating this project._
-
-3 _I won't share how long it took me to figure out that `sub` mapped to that; let's just categorize it as "too long." In my testing, it's the only claim that doesn't come across by its JWT name._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[Auth0]: https://auth0.com
-[JWT]: https://jwt.io
-[npm]: https://www.npmjs.com/package/auth0-js
-[AuthService.js]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/auth/AuthService.js "app/src/auth/AuthService.js | myPrayerJournal | GitHub"
-[LogOn.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/user/LogOn.vue "app/src/components/user/LogOn.vue | myPrayerJournal | GitHub"
-[last post]: /2018/a-tour-of-myprayerjournal/the-api.html "A Tour of myPrayerJournal: The API | The Bit Badger Blog"
-[store]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/store/index.js "app/src/store/index.js | myPrayerJournal | GitHub"
-[api]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/api/index.js "app/src/api/index.js | myPrayerJournal | GitHub"
-[Axios]: https://www.npmjs.com/package/axios
-[Program.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Program.fs "api/Program.fs | myPrayerJournal | GitHub"
-[Handlers.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Handlers.fs "api/Handlers.fs | myPrayerJournal | GitHub"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/conclusion.md b/source/_posts/2018/a-tour-of-myprayerjournal/conclusion.md
deleted file mode 100644
index 133061b..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/conclusion.md
+++ /dev/null
@@ -1,115 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: Conclusion"
-date: 2018-09-02 07:10:00
-author: Daniel
-categories:
-- [ Programming, Go ]
-- [ Programming, JavaScript ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- bootstrap
-- bundle
-- community
-- css
-- element ui
-- flexbox
-- go
-- golang
-- grid
-- html
-- jquery
-- lodash
-- markdown
-- moment
-- tree-shaking
-- vue
-- webpack
-- writing
----
-_NOTE: This is the final post of an 8-post series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-
-Over the course of this tour, we've meandered through client side code, server side code, a database, and documentation. However, the experience of developing an application is more than just the sum of the assembled technologies and techniques. Let's take a look at some of these "lessons learned" and opinions formed through this process. (This post will use the first-person singular pronouns "I" / "me" / "my" a lot more than the previous ones.)
-
-## Vue Is Awesome -- But...
-
-As I tried different SPA frameworks, they were interesting and fun, but a lot more work than I expected. Then, I came across [Vue][], and its paradigm and flow just clicked. Single file components are great; it was so nice to not have to go digging through a site-wide CSS file looking for styles that affected the elements in the component. I just had to scroll down! While I did put the common CSS in `App.vue`, the application's top component, anything unique that component did was right there. There are also all kinds of Vue-aware packages that you can add and use, that add their own elements/components to the process; [Element UI][], [Bootstrap Vue][], and [Vue-Awesome][] were three of the ones I used at different points in development. Since it's a JavaScript framework, you can use vanilla JS packages as well; myPrayerJournal uses [moment.js][] to display relative dates ("last activity 8 minutes ago") and format dates for display.
-
-Then... I ran the build process, and the bundles were huge -- as in, multiple megabytes huge! We changed our implementation of Vue-Awesome to only import the icons we used in the application (to be fair to them, that is the project's recommendation). Element also seemed to be rather heavy. One of the last issues I worked before final release was removing Bootstrap Vue and just using straight HTML/CSS for layout and flow (which is another lesson we'll explore below). There are guides on configuring [Webpack][] to help make moment's bundle smaller (and that project has an open issue to refactor so that it's more friendly to a "just import the part you need" paradigm).
-
-None of this is meant as a knock of any of the fine projects I've named up to this point. It was also near the end of the project when I converted to the Vue CLI v3 template, which uses a version of Webpack that has a much better "tree-shaking" algorithm. (This means that, if it can establish that code is never executed, it excludes it from the bundle.) myPrayerJournal v1.0's modern "vendor" bundle (the one with the libraries) is 283K, while the legacy bundle is 307K; while that's not lightning fast on mobile, it's also comparable to a lot of other sites, and since page updates happen through the API, it is fast once it's loaded.[1](#note-1)
-
-**Lesson**: Be smart about what you import.
-
-**Lesson**: The JavaScript ecosystem evolves quickly. This was published September 2nd, 2018, describing development that occurred September 2016 through August 2018; a good bit of this is likely already obsolete. :)
-
-## You Might Not Need...
-
-We mentioned above that the site eventually was written with simple HTML and CSS. Many of the more popular packages and utilities were created to make up for deficiencies, either in the browser ecosystem or among the differing browser vendors. With the recent efforts by browser vendors to support published standards, though, many of these packages are used for reasons that distill to comfort and inertia. As before, this is not a knock on these projects; they filled a definite need, and continue to work as the basis for a lot of deployed, executing code.
-
-For new development, though, existing standards -- and their support -- may be sufficient. There are some great sites that detail how certain things can be done using plain JavaScript or CSS.
-- [You Might Not Need jQuery][jq]
-- [You Might Not Need Bootstrap][boot] _(for this one, you have to read the HTML yourself; looks like it's not hosted at the given URL anymore)_
-- [You Might Not Need Lodash][lodash]
-- [Can I Use ___?][ciu]
-
-I used the last one quite a bit. I also extensively referred to [CSS Tricks' "A Complete Guide to Flexbox"][flexbox] post. When I decided to rework the layout without Bootstrap, I thought the replacement would be CSS Grid; however, Flexbox was more than enough.
-
-**Lesson**: Use a framework if you want, but don't assume it's the only way to do things.
-
-**Lesson**: If you want to shrink your bundle size, 20-30 lines of your own code can sometimes save you 20-30K (or more).
-
-## Learn Go
-
-> Ladies and gentlemen of the Internet class of 2018 -
-> Learn Go.
-> If I could offer you only one tip for the future,
-> Go would be it.
-> -- [with apologies to Baz Luhrmann][ws]
-
-[Go][] is a systems programming language. It was developed at Google, to help them better utilize their hardware. It natively supports concurrent processing (which can be done in parallel, but is distinct from "parallel programming"); has an opinionated code formatter; forces you to address calls that may error; and is terribly efficient. When myPrayerJournal was running with the Go backend, the working size in RAM was around 10MB. Let me say that again, this time with feeling - **the working size for a database-accessing, HTTP-listening, dynamic web service was 10MB of RAM!** If you have ever profiled a web server process, you know that it's nearly ludicrous how small this is. For comparison, the process working set for the F#/Giraffe/EF Core version of the backend runs between 60-80MB, and includes another ~256MB of shared working set memory.[2](#note-2) (An Apache2 process running PHP can run in the 256MB range as well.)
-
-Why am I recommending a technology that I ultimately moved away from before the v1.0 release? Well, other than "did you read the last paragraph?!?!", the short answer is "it's the future, and will change how you code in every other language." The fact that it forces you to deal with every single thing that may error makes it robust; but, if you learn to develop with it, you will find yourself thinking about error handling more fully than you did before -- and I say this as a person who already coded error handlers as I coded the happy path.
-
-Why did I move away from a technology on which I'm so bullish? Well, for starters, F# is the language that "clicks" for me in the same way that Vue did as a client-side framework; its development paradigm just makes sense with the way I think about structuring code. I completed a project that used F# and Giraffe (which I hope to take open-source soon), and that gave me the confidence to move forward with a third attempt at an F# API. _(Third time's the charm, right?)_ Also, while Entity Framework generated some pretty verbose SQL statements, EF Core more or less generates what I would have written anyway, **plus** it takes care of populating the objects it returns from the database.
-
-I also found the development process awkward, though not unwieldy. _(They're probably not going to adopt that as their slogan...)_ Much has been written about the `GOPATH` environment variable, but once you get into it, it starts to make sense. `go get` is great at pulling down your dependencies, and the way it does it, you can peruse the source code to see exactly what they are doing. Also, it was not too difficult to develop on Windows, but build executables for Linux -- which, in the "systems" programming work, is a really cool feature.
-
-**Lesson**: Learn Go.
-
-## Write about Your Code
-
-This wasn't a lesson I learned on this project; this was one I'd known for a while. There are _(at least)_ two distinct benefits to writing about your code:
-- It can help you learn even more than you may have learned when you were writing the code itself. As developers, we sometimes forget to step back and look at the body of work we've created. If you write about it, you have to form a coherent view about it so you can explain it to others; this helps you long-term. Also, people who know more about the environment can chime in on what you've written, which also not only helps you learn, ...
-- It helps build community. If you hit a snag, and someone in the community around that technology helps you get past it, writing about your experience means that the next person to encounter that issue may not have to ask; if their searching leads them to your post, they can fix it and move on. This applies doubly if you could **not** get help from the community; you might be the one who surfaces this issue/technique, and moves the entire community forward.
-
-**Lesson**: Write about your code; participate in the community around your technology to whatever extent you are able.
-
-
-
-If you've been with us for this entire tour -- thank you. I hope you've learned something; I know I have, not just through the development of [myPrayerJournal][], but through the course of writing about it. And, certainly, if you feel that this application could help you in any way, help yourself. It is and will always be free, and [Bit Badger Solutions][bbs] (and DJS Consulting before it) has, as of this writing, a 14-year streak of no known data breaches; your prayer requests are safe with us.
-
----
-
-1 _There are chunk-splitting techniques that can be used to make the initial download smaller, and load other portions on-demand. Moment.js, for example, isn't needed for the default "Welcome to myPrayerJournal" page. We could defer loading that until the user has logged in, as the journal page definitely needs it; we'd still have to download the same amount, but it would be spread out across 2 requests. Opportunities to save some size in the initial download are still out there, but 283K is just above the 244K suggested bundle size, so we went forward with it._
-
-2 _The server on which I host myPrayerJournal already has other .NET Core processes running on it, so the shared memory size has already been allocated._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[Vue]: https://vuejs.org "Vue"
-[Element UI]: https://github.com/ElemeFE/element "Element UI | GitHub"
-[Bootstrap Vue]: https://bootstrap-vue.js.org "Bootstrap Vue"
-[Vue-Awesome]: https://github.com/Justineo/vue-awesome "Vue-Awesome | GitHub"
-[moment.js]: https://momentjs.com "Moment.js"
-[Webpack]: https://webpack.js.org "Webpack"
-[jq]: http://youmightnotneedjquery.com "You Might Not Need jQuery"
-[boot]: https://github.com/stuyam/YouMightNotNeedBootstrap/tree/gh-pages "You Might Not Need Bootstrap | GitHub"
-[lodash]: https://youmightnotneed.com/lodash "You Might Not Need Lodash"
-[ciu]: https://caniuse.com "Can I Use ___?"
-[flexbox]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/ "A Complete Guide to Flexbox | CSS Tricks"
-[ws]: http://www.metrolyrics.com/everybodys-free-to-wear-sunscreen-lyrics-baz-luhrmann.html "Everybody's Free (to Wear Sunscreen) - Baz Luhrmann | Metro Lyrics"
-[Go]: https://golang.org "The Go Programming Language"
-[myPrayerJournal]: https://prayerjournal.me "myPrayerJournal"
-[bbs]: https://bitbadger.solutions "Bit Badger Solutions"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/documentation.md b/source/_posts/2018/a-tour-of-myprayerjournal/documentation.md
deleted file mode 100644
index 7bc9b42..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/documentation.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: Documentation"
-date: 2018-09-01 20:24:00
-author: Daniel
-categories:
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- documentation
-- github
-- https
-- jekyll
-- lets encrypt
-- liquid
-- markdown
-- subdomain
----
-_NOTES:_
-- _This is post 7 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-We have spent a lot of time looking at various aspects of the application, written from the perspective of a software developer. However, there is another perspective to consider - that of a user. With a "minimalist" app, how do we let them know what the buttons do?
-
-## Setting Up GitHub Pages
-
-In other projects, we had use [GitHub Pages][] by creating a `gh-pages` branch of our repository. This has some advantages, such as a page structure that is completely separate from the source files. At the same time, though, you either have to have 2 sandboxes on different branches, or switch branches when switching from coding to documentation. Fortunately, this is not the only option; GitHub Pages can publish from a `/docs` folder on the `master` branch as well. They have a [nice guide on how to set it up][howto].
-
-The `_config.yml` file that's also in the `/docs` folder ([mpj:docs folder][docs]) was put there by GitHub when we selected the theme from the Settings page of the repo. The only file we ever put there was `index.md` ([mpj:docs/index.md][index.md]).
-
-## Writing the Documentation
-
-As GitHub Pages uses [Jekyll][] behind the scenes, we have [Markdown][] and the default [Liquid][] tags available to us. We didn't need any Liquid tags, though, as the documentation is pretty straightforward. You may notice that there isn't any front matter at the top of `index.md`; absent that, GitHub Pages selects the title of the page from the first `h1` tag in the document, defined with a leading `# ` sequence.
-
-If you browse the [commit history for `index.md`][commits], you'll see that many of the commits reference either a version or issue number. This makes it rather simple to go back in time through the source code, and not only review the code, but see how its functionality was explained in the documentation. You can also review typos that got committed, which helps keep you humble. :)
-
-## Making It Better
-
-There is more that could be done to improve this aspect of the project. The first would be to assign it a subdomain of `prayerjournal.me` instead of serving the pages from `bit-badger.github.io`. GitHub Pages does support custom subdomains, and even supports HTTPS for these through [Let's Encrypt][le]. The second would be to work up a lightweight theme for the page that matched the look-and-feel of the main site; this would make a more unified experience. Finally, while "minimalist" was the goal, there ended up being a few features that took lots of words to explain; a table of contents on the page would help people navigate directly to the help they need.
-
-
-
-Our tour is drawing to a close; next time, we'll wrap it up with observations and opinions over the development process.
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[GitHub Pages]: https://pages.github.com "GitHub Pages"
-[howto]: https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch
-[docs]: https://github.com/bit-badger/myPrayerJournal/tree/1.0.0/docs "docs | myPrayerJournal | GitHub"
-[index.md]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/docs/index.md "docs/index.md | myPrayerJournal | GitHub"
-[Jekyll]: https://jekyllrb.com "Jekyll"
-[Markdown]: https://daringfireball.net/projects/markdown/ "Markdown"
-[Liquid]: https://github.com/Shopify/liquid/wiki "Liquid"
-[commits]: https://github.com/bit-badger/myPrayerJournal/commits/1.0.0/docs/index.md "docs/index.md (Commits) | myPrayerJournal | GitHub"
-[le]: https://letsencrypt.org "Let's Encrypt"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/introduction.md b/source/_posts/2018/a-tour-of-myprayerjournal/introduction.md
deleted file mode 100644
index cd19faf..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/introduction.md
+++ /dev/null
@@ -1,76 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: Introduction"
-date: 2018-08-24 12:15:00
-author: Daniel
-categories:
-- [ Databases, PostgreSQL ]
-- [ Programming, .NET, F# ]
-- [ Programming, JavaScript, Vue ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- angular
-- aurelia
-- elm
-- f#
-- giraffe
-- go
-- golang
-- introduction
-- javascript
-- journaling
-- koa
-- node
-- prayer
-- requirements
-- suave
-- vue
----
-Recently, we released version 1.0 of [myPrayerJournal][], a minimalistic prayer journaling application. This series aims to provide a tour of the code, with several stops along the way:
-
-- **Part 0: Introduction** _(this post)_
-- **[Part 1: The Front End][part1]** - Vue components and routing
-- **[Part 2: State in the Browser][part2]** - Vuex and getting information from an API
-- **[Part 3: The API][part3]** - Giraffe and JSON web endpoints
-- **[Part 4: Authentication][part4]** - Auth0, using information in both app and API
-- **[Part 5: The Data Store][part5]** - EF Core backed by PostgreSQL, with the `DbContext` defined in F#
-- **[Part 6: Documentation][part6]** - GitHub Pages generated on each commit
-- **[Part 7: Conclusion][part7]** - Lessons learned and opinions based on the development experience
-
-From a technical perspective, this application was going to be a learning experience. We knew we wanted to use a Single Page Application (SPA) framework with an API; we'd built APIs before, but had yet to build a SPA. For front-end frameworks, we started with [Angular][], went through [Aurelia][] and [Elm][], then decided on [Vue][]. For the back-end API, we started with [Suave][], then went live on [Node.js][] with [Koa][]; later, we moved it to [Go][], and after .NET Core 2.1 was released, landed on [Giraffe][]. The "learning experience" part was a success; through all these attempts, we utilized 5 different languages and 3 different database access techniques.
-
-To understand the requirements, a short explanation of the process will help. "Prayer journaling" is a discipline where a person will write down the things for which they are praying; this provides a defined list to help guide their prayer, and helps them not forget things. Then, as the situation changes, they can record updates, through to the resolution of the situation (also called the request being "answered"). This discipline not only helps to focus efforts, it also provides a record of requests and answers. Although people have successfully used a notebook, or something similar, for a long time, that approach does have some downsides:
-- For long term requests, you can run out of room for updates.
-- A physical journal can only be in one place at one time.
-- Answered requests coexist with unanswered requests, so you have to flip pages past them.
-- Books can end up under stacks of other things, falling victim to "out of sight, out of mind."
-
-Looking to address some of those, the initial requirements started as the first three bullets below. The remaining requirements emerged through using the application as it was being developed.
-- List unanswered requests, in a way that they can be marked as prayed or answered, and be updated
-- List answered requests, and allow full requests (and their history) to be viewed
-- Do the above in a way that will not be distracting
-- Allow notes to be recorded for a request; not every update on a situation requires a change in the verbiage of the request
-- Allow requests to be "snoozed" (removed from the journal, with a specified date when they will reappear), and list snoozed requests so that the snooze can be expired (returning the request to the journal immediately)
-- Allow requests to be prioritized (this became the request recurrence feature)
-
-Armed with these requirements, we will pick up next time with a look at the Vue front end.
-
-
-[myPrayerJournal]: https://github.com/bit-badger/myPrayerJournal/tree/1.0.0
-[part1]: /2018/a-tour-of-myprayerjournal/the-front-end.html "A Tour of myPrayerJournal: The Front End | The Bit Badger Blog"
-[part2]: /2018/a-tour-of-myprayerjournal/state-in-the-browser.html "A Tour of myPrayerJournal: State in the Browser | The Bit Badger Blog"
-[part3]: /2018/a-tour-of-myprayerjournal/the-api.html "A Tour of myPrayerJournal: The API | The Bit Badger Blog"
-[part4]: /2018/a-tour-of-myprayerjournal/authentication.html "A Tour of myPrayerJournal: Authentication | The Bit Badger Blog"
-[part5]: /2018/a-tour-of-myprayerjournal/the-data-store.html "A Tour of myPrayerJournal: The Data Store | The Bit Badger Blog"
-[part6]: /2018/a-tour-of-myprayerjournal/documentation.html "A Tour of myPrayerJournal: Documentation | The Bit Badger Blog"
-[part7]: /2018/a-tour-of-myprayerjournal/conclusion.html "A Tour of myPrayerJournal: Conclusion | The Bit Badger Blog"
-[Angular]: https://angular.io
-[Aurelia]: https://aurelia.io
-[Elm]: http://elm-lang.org
-[Vue]: https://vuejs.org
-[Suave]: https://suave.io
-[Node.js]: https://nodejs.org
-[Koa]: https://koajs.com
-[Go]: https://golang.org
-[Giraffe]: https://github.com/giraffe-fsharp/Giraffe
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/state-in-the-browser.md b/source/_posts/2018/a-tour-of-myprayerjournal/state-in-the-browser.md
deleted file mode 100644
index 1474df8..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/state-in-the-browser.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: State in the Browser"
-date: 2018-08-26 07:30:00
-author: Daniel
-categories:
-- [ Programming, JavaScript, Vue ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- action
-- components
-- facebook
-- flux
-- javascript
-- mutation
-- react
-- redux
-- script
-- state
-- vue
-- vuex
----
-_NOTES:_
-- _This is post 3 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-Flux (a pattern that originated at Facebook) defines state, as well as actions that can mutate that state. Redux is the most popular implementation of that pattern, and naturally works very well with React. However, other JavaScript framewoks use this pattern, as it ensures that state is managed sanely. (Well, the state is sane, but so is the developer!)
-
-As part of Vue, the [Vuex][] component is a flux implementation for Vue that provides a standard way of managing state. They explain it in much more detail, so if the concept is a new one, you may want to read their "What is Vuex?" page before you continue. Once you are ready, let's continue and take a look at how it's used in myPrayerJournal.
-
-## Defining the State
-
-The store ([mpj:store/index.js][store]) exports a single new `Vuex.Store` instance, with its `state` property defining the items it will track, along with initial values for those items. This represents the initial state of the app, and is run whenever the browser is refreshed.
-
-In looking at our store, there are 4 items that are tracked; two items are related to authentication, and two are related to the journal. As part of authentication (which will get a further exploration in its own post), we store the user's profile and identity token in local storage; the initial values for those items attempt to access those values. The two journal related items are simply initialized to an empty state.
-
-## Mutating the State
-
-There are a few guiding principles for mutations in Vuex. First, they must be defined as part of the `mutations` property in the store; outside code cannot simply change one state value to another without going through a mutation. Second, they must be synchronous; mutations must be a fast operation, and must be accomplished in sequence, to prevent race conditions and other inconsistencies. Third, mutations cannot be called directly; mutations are "committed" against the current store. Mutations receive the current state as their first parameter, and can receive as many other parameters as necessary.
-
-_(Side note: although these functions are called "mutations," Vuex is actually replacing the state on every call. This enables some really cool time-traveling debugging, as tools can replay states and their transformations.)_
-
-So, what do you do when you need to run an asynchronous process - like, say, calling an API to get the requests for the journal? These processes are called actions, and are defined on the `actions` property of the store. Actions receive an object that has the state, but it also has a `commit` property that can be used to commit mutations.
-
-If you look at [line 87 of store/index.js][line87], you'll see the above concepts put into action1 as a user's journal is loaded. This one action can commit up to 4 mutations of state. The first clears out whatever was in the journal before, committing the `LOADED_JOURNAL` mutation with an empty object. The second sets the `isLoadingJournal` property to `true` via the `LOADING_JOURNAL` mutation. The third, called if the API call resolves successfully, commits the `LOADED_JOURNAL` mutation with the results. The fourth, called whether it works or not, commits `LOADING_JOURNAL` again, this time with `false` as the parameter.
-
-A note about the names of our mutations and actions - the Vuex team recommends defining constants for mutations and actions, to ensure that they are defined the same way in both the store, and in the code that's calling it. This code follows their recommendations, and those are defined in `action-types.js` and `mutation-types.js` in the `store` directory.
-
-## Using the Store
-
-So, we have this nice data store with a finite number of ways it can be mutated, but we have yet to use it. Since we looked at loading the journal, let's use it as our example ([mpj:Journal.vue][Journal.vue]). On line 56, we wrap up the computed properties with `...mapState`, which exposes data items from the store as properties on the component. Just below that, the `created` function calls into the store, exposed as `$store` on the component instance, to execute the `LOAD_JOURNAL` action.
-
-The template uses the mapped state properties to control the display. On lines 4 and 5, we display one thing if the `isLoadingJournal` property is true, and another (which is really the rest of the template) if it is not. Line 12 uses the `journal` property to display a `RequestCard` ([mpj:RequestCard.vue][RequestCard.vue]) for each request in the journal.
-
-I mentioned developer sanity above; and in the [last post][part1], I said that the logic that has `RequestCard` making the decision on whether it should show, instead of `Journal` deciding which ones it should show, would make sense. This is where we put those pieces together. The Vuex store is reactive; when data from it is rendered into the app, Vue will update the rendering if the store changes. So, `Journal` simply displays a "hang on" note when the journal is loading, and "all the requests" once it's loaded. `RequestCard` only displays if the request should be displayed. And, the entire "brains" behind this is the thing that starts the entire process, the call to the `LOAD_JOURNAL` action. We aren't moving things around, we're simply displaying the state of things as they are!
-
-`Navigation` ([mpj:Navigation.vue][Navigation.vue]) is another component that bases its display off state, and takes advantage of the state's reactivity. By mapping `isAuthenticated`, many of the menu items can be shown or hidden based on whether a user is signed in or not. Through mapping `journal` and the computed property `hasSnoozed`, the "Snoozed" menu link does not show if there are no snoozed requests; however, the first time a request from the journal is snoozed, this one appears _**just because the state changed**_.
-
-This is one of the things that cemented the decision to use Vue for the front end2, and is one of my favorite features of the entire application. _(You've probably picked up on that already, though.)_
-
-
-
-We've now toured our stateful front end; next time, we'll take a look at [the API we use to get data into it][api].
-
----
-1 _Pun not originally intended, but it is now!_
-
-2 _The others were the lack of ceremony and the Single File Component structure; both of those seem quite intuitive._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[Vuex]: https://vuex.vuejs.org
-[store]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/store/index.js "app/src/store/index.js | myPrayerJournal | GitHub"
-[line87]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/store/index.js#L87 "app/src/store/index.js (line 87) | myPrayerJournal | GitHub"
-[Journal.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/Journal.vue "app/src/components/Journal.vue | myPrayerJournal | GitHub"
-[RequestCard.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/RequestCard.vue "app/src/components/request/RequestCard.vue | myPrayerJournal | GitHub"
-[part1]: /2018/a-tour-of-myprayerjournal/the-front-end.html#Components "Components | A Tour of myPrayerJournal: The Front End | The Bit Badger Blog"
-[Navigation.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/common/Navigation.vue "app/src/components/common/Navigation.vue | myPrayerJournal | GitHub"
-[api]: /2018/a-tour-of-myprayerjournal/the-api.html "A Tour of myPrayerJournal: The API | The Bit Badger Blog"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/the-api.md b/source/_posts/2018/a-tour-of-myprayerjournal/the-api.md
deleted file mode 100644
index 14d9357..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/the-api.md
+++ /dev/null
@@ -1,111 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: The API"
-date: 2018-08-29 09:37:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- api
-- composition
-- configuration
-- entity
-- f#
-- fish
-- get
-- giraffe
-- handler
-- json
-- kestrel
-- operator
-- patch
-- post
-- rest
-- router
-- routing
-- scott wlaschin
-- spa
-- suave
----
-_NOTES:_
-- _This is post 4 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-Now that we have a wonderful, shiny, [reactive][] [front end][], we need to be able to get some data into it. We'll be communicating via JSON between the app and the server. In this post, we'll also attempt to explain some about the F# language features used as part of the API.
-
-## The Data
-
-The entities are defined in Data.fs ([mpj:Data.fs][Data.fs]). We'll dig into them more fully in [the "data store" post][data], but for now, we'll just focus on the types and fields. We have four types: `History` (lines 33-39), `Note` (lines 67-71), `Request` (lines 94-110), and `JournalRequest` (lines 153-173). A `Request` can have multiple `Note`s and `History` entries, and `JournalRequest` is based on a view that pulls these together and computes things like the current text of the request and when it should be displayed again.
-
-We apply no special JSON transformations, so the fields in these record types are the properties in the exported JSON.
-
-## The URLs
-
-To set the API apart from the rest of the URLs, they all start with `/api/`. Request URLs generally follow the form `request/[id]/[action]`, and there is a separate URL for the journal. Line 54 in `Program.fs` ([mpj:Program.fs][Program.fs]) has the definition of the routes. We used [Giraffe][]'s [Token Router][TR] instead of the traditional one, as we didn't need to support any URL schemes it doesn't. The result really looks like a nice, clean "table of contents" for the routes support by the API.1
-
-We aren't done with routes just yet, though. Let's take a look at that `notFound` handler ([mpj:Handlers.fs][Handlers.fs]); it's on line 27. Since we're serving a SPA, we need to return `index.html`, the entry point of the SPA, for URLs that belong to it. Picture a user sitting at `https://prayerjournal.me/journal` and pressing "Refresh;" we don't want to return a 404! Since the app has a finite set of URL prefixes, we'll check to see if one of those is the URL. If it is, we send the Vue app; if not, we send a 404 response. This way, we can return true 404 responses for the inevitable hacking attempts we'll receive (pro tip, hackers - `/wp-admin/wp-upload.php` does not exist).
-
-## Defining the Handlers
-
-Giraffe uses the term "handler" to define a function that handles a request. Handlers have the signature `HttpFunc -> HttpContext -> Task` (aliased as `HttpHandler`), and can be composed via the `>=>` ("fish") operator. The `option` part in the signature is the key in composing handler functions. The `>=>` operator creates a pipeline that sends the output of one function into the input of another; however, if a function fails to return a `Some` option for the `HttpContext` parameter, it short-circuits the remaining logic.2
-
-The biggest use of that composition in myPrayerJournal is determining if a user is logged in or not. Authorization is also getting [its own post][auth], so we'll just focus on the yes/no answer here. The `authorized` handler (line 71) looks for the presence of a user. If it's there, it returns `next ctx`, where `next` is the next `HttpFunc` and `ctx` is the `HttpContext` it received; this results in a `Task` which continues to process, hopefully following the happy path and eventually returning `Some`. If the user is not there, though, it returns the `notAuthorized` handler, also passing `next` and `ctx`; however, if we look up to line 67 and the definition of the `notAuthorized` handler, we see that it ignores both `next` and `ctx`, and returns `None`. However, notice that this handler has some fish composition in it; `setStatusCode` returns `Some` (it has succeeded) but we short-circuit the pipeline immediately thereafter.
-
-We can see this in use in the handler for the `/api/journal` endpoint, starting on line 137. Both `authorize` and the inline function below it have the `HttpHandler` signature, so we can compose them with the `>=>` operator. If a user is signed in, they get a journal; if not, they get a 403.
-
-When a handler is expecting a parameter from a route, the handler's signature is a bit different. The handler for `/api/request/[id]`, on line 246, has an extra parameter, `reqId`. If we look back in `Program.fs` line 64, we see where this handler is assigned its route; and, if you compare it to the route for `/api/journal` on line 59, you'll see that it looks the same. The difference here is the expectations of `route` (for the journal) vs. `routef` (for the request). `route` expects no parameter, but `routef` will extract the parameters, `Printf` style, and pass them as parameters that precede the `HttpHandler` signature.
-
-## Executing the Handlers
-
-myPrayerJournal has `GET`, `POST`, and `PATCH` routes defined. We'll look at representative examples of each of these over the next few paragraphs.
-
-For our `GET` example, let's return to the `Request.get` handler, starting on line 246. Once we clear the `authorize` hurdle, the code attempts to retrieve a `JournalRequest` by the request ID passed to the handler and the user ID passed as part of the request. If it exists, we return the JSON representation of it; if not, we return a 404. Note the order of parameters to the `json` result handler - it's `json [object] next ctx` (or `json [object] HttpHandler`). We also defined an `asJson` function on line 75; this flips the parameters so that the output object is the last parameter (`asJson next ctx [object]`), enabling the flow seen in the `journal` handler on line 137.
-
-For our `POST` example, we'll use `Request.addNote`, starting on line 218. It checks authorization, and to make sure the request exists for the current user. If everything is as it should be, it then uses Giraffe's `BindJsonAsync<'T>` extension method to create an instance of the expected input form. Since the handler doesn't have a place to specify the expected input object, this type of model binding cannot happen automatically; the upside is, you don't waste CPU cycles trying to do it if you don't need it. Once we have our model bound, we create a new `Note`, add it, then return a 201 response.
-
-`PATCH` handlers are very similar; `Request.snooze` is one such handler, starting on line 291. The flow is very similar as the one for `Request.addNote`, except that we're updating instead of adding, and we return 204 instead of 201.
-
-## Configuring the Web Server
-
-Giraffe enables [Suave][]-like function composition on top of Kestrel and the ASP.NET Core infrastructure. Rather than using the `Startup` class, myPrayerJournal uses a functional configuration strategy. The calls are in `Program.fs` starting on line 115; there are lots of other guides on how to configure ASP.NET Core, so I won't say too much more about it.
-
-Notice, though, line 31. Earlier, we discussed the `>=>` operator and how it worked. This is an example of the `>>` composition operator, which is part of F#. For functions whose output can be run directly into the next function's input, the `>>` operator allows those functions to be composed into a single function. If we were to look at the signature of the composed function within the parentheses, its signature would be `string -> unit`; so, we pass the string "Kestrel" to it, and it runs through and returns `unit`, which is what we expect for a configuration function. Here's how that breaks down:
-- `ctx.Configuration.GetSection`'s signature is `string -> IConfigurationSection`
-- `opts.Configure`'s signature is `IConfiguration -> KestrelConfigurationLoader` (`IConfigurationSection` implements `IConfiguration`)
-- `ignore`'s signature is `'a -> unit`
-
-If this still doesn't make sense, perhaps this will help. The `Configure.kestrel` function could also have been written using the `|>` piping operator instead, with the equivalent code looking like:
-
-{% codeblock lang:fsharp %}
- let kestrel (ctx : WebHostBuilderContext) (opts : KestrelServerOptions) =
- ctx.Configuration.GetSection "Kestrel"
- |> opts.Configure
- |> ignore
-{% endcodeblock %}
-
-
-
-That concludes our tour of the API for now, though we'll be looking at it again next time, when we take a deeper dive into [authentication and authorization using Auth0][auth].
-
----
-
-1 _While we tried to follow REST principles in large part, the REST purists would probably say that it's not quite RESTful enough to claim the name. But, hey, we do use `PATCH`, so maybe we'll get partial credit..._
-
-2 _Scott Wlaschin has a great post entitled ["Railway Oriented Programming"][ROP] that explains this concept in general, and [the fish operator][ROP-fish] specifically. Translating his definition to Giraffe's handlers, the first function is `switch1`, the `next` parameter is `switch2`, and the `HttpContext` is the `x` parameter; instead of `Success` and `Failure`, the return type utilizes the either/or nature of an option being `Some` or `None`. If you want to understand what makes F# such a great programming model, you'll spend more time on his site than on The Bit Badger Blog._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[reactive]: /2018/a-tour-of-myprayerjournal/state-in-the-browser.html "A Tour of myPrayerJournal: State in the Browser | The Bit Badger Blog"
-[front end]: /2018/a-tour-of-myprayerjournal/the-front-end.html "A Tour of myPrayerJournal: The Front End | The Bit Badger Blog"
-[Data.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Data.fs "api/Data.fs | myPrayerJournal | GitHub"
-[data]: /2018/a-tour-of-myprayerjournal/the-data-store.html "A Tour of myPrayerJournal: The Data Store | The Bit Badger Blog"
-[Program.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Program.fs "api/Program.fs | myPrayerJournal | GitHub"
-[Giraffe]: https://github.com/giraffe-fsharp/Giraffe "Giraffe | GitHub"
-[TR]: https://github.com/giraffe-fsharp/Giraffe.TokenRouter "Giraffe.TokenRouter | GitHub"
-[Handlers.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Handlers.fs "app/Handlers.fs | myPrayerJournal | GitHub"
-[auth]: /2018/a-tour-of-myprayerjournal/authentication.html "A Tour of myPrayerJournal: Authentication | The Bit Badger Blog"
-[Suave]: https://suave.io
-[ROP]: https://fsharpforfunandprofit.com/posts/recipe-part2/ "Railway oriented programming | F# for Fun and Profit"
-[ROP-fish]: https://fsharpforfunandprofit.com/posts/recipe-part2/#an-alternative-to-bind "An alternative to bind | Railway oriented programming | F# for Fun and Profit"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/the-data-store.md b/source/_posts/2018/a-tour-of-myprayerjournal/the-data-store.md
deleted file mode 100644
index 35c871a..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/the-data-store.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: The Data Store"
-date: 2018-08-31 22:48:00
-author: Daniel
-categories:
-- [ Databases, PostgreSQL ]
-- [ Programming, .NET, F# ]
-- [ Projects, myPrayerJournal ]
-- [ Projects, OptionConverter ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- api
-- attribute
-- cast
-- creation
-- data
-- dbcontext
-- dbquery
-- dbset
-- design
-- ef core
-- entity framework
-- f#
-- giraffe
-- json
-- migration
-- "null"
-- option
-- postgresql
-- rethinkdb
-- sql
-- table
-- view
----
-_NOTES:_
-- _This is post 6 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-Up to this point in our tour, we've talked about data a good bit, but it has all been in the context of whatever else we were discussing. Let's dig into the data structure a bit, to see how our information is persisted and retrieved.
-
-## Conceptual Design
-
-The initial thought was to create a document store with one document type, the request. The request would have an ID, the ID of the user who created it, and an array of updates/records. Through the initial phases of development, our preferred document database ([RethinkDB][]) was going through a tough period, with their company shutting down; thankfully, they're now part of the Linux Foundation, so they're still around. RethinkDB supports calculated fields in documents, so the plan was to have a few of those to keep us from having to retrieve or search through the array of updates.
-
-We also considered a similar design using [PostgreSQL][]'s native JSON support. While it does not natively support calculated fields, a creative set of indexes could also suffice. As we thought it through a little more, though, this seemed to be over-engineering; this isn't unstructured data, and PostgreSQL handles max-length character fields very well. (This is supposed to be a "minimalist" application, right?) A relational structure would fit our needs quite nicely.
-
-The starting design, then, used 2 tables. `request` had an ID and a user ID; `history` had the request ID, an "as of" date, a status (created, updated, etc.), and the optional text associated with that update. Early in development, the `journal` view brought together the request/user IDs along with the latest history entry that affected the text of the request, as well as the last date/time an action had occurred on the request. When the notes capability was added, it got its own `note` table; its structure was similar to the `history` table, but with non-optional text and without a status. As snoozing and recurrence capabilities were added, those fields were added to the `request` table (and the `journal` view).
-
-The final design uses 3 tables, 2 of which have a one-to-many relationship with the third; and 1 view, which provides the calculated fields we had originally planned for RethinkDB to calculate.
-
-## Database Changes (Migrations)
-
-As we ended up using 3 different server environments over the course of this project, we ended up writing a `DbContext` class based on our existing structure. For the Node.js backend, we created a DDL file ([mpj:ddl.js][ddl.js], v0.8.4+) that checked for the existence of each table and view, and also had the SQL to execute if the check failed. For the Go version ([mpj:data.go][data.go], v0.9.6+), the `EnsureDB` function does a similar thing; looking at line 347, it is checking for a specific column in the `request` table, and running the `ALTER TABLE` statement to add it if it isn't there.
-
-The only change that was required since the F#/Giraffe backend has been in place was the one to support request recurrence. Since we did not end up with a scaffolded EF Core initial migration/model, we simply wrote a SQL script to accomplish these changes ([mpj:sql directory][sql]).1
-
-## The EF Core Model
-
-EF Core uses the familiar `DbContext` class from prior versions of Entity Framework. myPrayerJournal does take advantage of a feature that just arrived in EF Core 2.1, though - the `DbQuery` type. `DbSet`s are collections of entities that generally map to an underlying database table. They can be mapped to views, but unless it's an updateable view, updating those entities results in a runtime error; plus, since they can't be updated, there's no need for the change tracking mechanism to care about the entities returned. `DbQuery` addresses both these concerns, providing lightweight read-only access to data from views.
-
-The `DbContext` class is defined in Data.fs ([mpj:Data.fs][Data.fs]), starting in line 189. It's relatively straightforward, though if you have only ever seen a C# model, it's a bit different. The combination of `val mutable x : [type]` and the `[]` attribute are the F# equivalent of C#'s `[type] x;` declaration, which creates a variable and initializes reference types to `null`. The EF Core runtime provides these instances to their setters (lines 203, 206, 209, and 212), and the application code uses them via the getters (a line earlier, each).
-
-The `OnModelCreating` overridden method (line 214) is called when the runtime first creates its instance of the data model. Within this method, we call the `.configureEF` function of each of our database types. The name of this function isn't prescribed, and we could define the entire model without even referencing the data types of our entities; however, this technique gives us a "configure where it's defined" paradigm with each entity type. While the EF "Code First" model creates tables that don't need a lot of configuring, we must provide more information about the layout of the database tables since we're writing a `DbContext` to target an existing database.
-
-Let's start out by taking a look at `History.configureEF` (line 50). Line 53 says that we're going to the table `history`. This seems to be a no-brainer, but EF Core would (by convention) be expecting a `History` table; since PostgreSQL uses a different syntax for case-sensitive names, these queries would look like `SELECT ... FROM "History" ...`, resulting in a nice "relation does not exist" error. Line 54 defines our compound key (`requestId` and `asOf`). Lines 55-57 define certain properties of the entity as required; if we try to store an entity where these fields are not set, the runtime will raise an exception before even trying to take it to the database. _(F#'s non-nullability makes this a non-issue, but it still needs to be defined to match the database.)_ Line 58 may seem to do nothing, but what it does is make the `text` property immediately visible to the model builder; then, we can define an `OptionConverter`2 for it, which will translate between `null` and `string option` (`None` = `null`, `Some [x]` = `[x]`). _(Lines 60-61 are left over from when I was trying to figure out why line 62 was raising an exception, leading to the addition of line 58; they could safely be removed, and will be for a post-1.0 release.)_
-
-`History` is the most complex configuration, but let's take a peek at `Request.configureEF` (line 126) to see one more interesting technique. Lines 107-110 define the `history` and `notes` collections on the `Request` type; lines 138-145 define the one-to-many relationship (without a foreign key entity in the child types). Note the casts to `IEnumerable` (lines 138 and 142) and `obj` (lines 140 and 144); while F# is good about inferring types in a lot of cases, these functions are two places it is not. We can use the `:>` operator for the cast, because these types are part of the inheritance chain. _(The `:?>` operator is used for potentially unsafe casts.)_
-
-Finally, the attributes above each record type need a bit of explanation; each one has `[]`. The `CLIMutable` attribute creates a no-argument constructor for the record type, which the runtime can use to create instances of the type. (The side effect is that we may get null instances of what is expected to be a non-null type, but we'll look at dealing with that a bit later.) The `NoComparison` and `NoEquality` attributes keep F# from creating field-level equality and comparison methods on the types. While these are normally helpful, there is an edge case where they can raise `NullReferenceException`s, especially when used on null instances. As these record types are simply our data transfer objects (both from SQL and to JSON), we don't need the functionality anyway.
-
-## Reading and Writing Data
-
-EF Core uses the "unit of work" pattern with its `DbContext` class. Each instance maintains knowledge of the entities it's loaded, and does change tracking against those entities, so it knows what commands to issue when `.SaveChanges()` (or `.SaveChangesAsync()`) is called. It doesn't do this for free, though, and while EF Core does this much more efficiently than Entity Framework proper, F# record types do not support mutation; if `req` is a `Request` instance, for example, `{ req with showAfter = 123456789L }` returns a **new** `Request` instance.
-
-This is the problem whose solution is enabled by lines 227-233 in Data.fs. We can manually register an instance of an entity as either added or modified, and when we call `.SaveChanges()`, the runtime will generate the SQL to update the data store accordingly. This also allows us to use `.AsNoTracking()` in our queries (lines 250, 258, 265, and 275), which means that the resultant entities will not be registered with the change tracker, saving that overhead. Notice that we don't specify that on line 243; since `Journal` is defined as a `DbQuery` instead of a `DbSet`, we get change-tracking-avoidance for free.
-
-Generally speaking, the preferred method of writing queries against a `DbContext` instance is to define extension methods against it. These are `static` by default, and they enable the context to be as lightweight as possible, while extending it when necessary. However, since this context is so small, we've created 6 methods on the context that we use to obtain data.
-
-If you've been reading along with the tour, we have already seen a few API handler functions ([mpj:Handlers.fs][Handlers.fs]) that use the data context. Line 137 has the handler for `/api/journal`, the endpoint to retrieve a user's active requests. It uses `.JournalByUserId()`, defined in Data.fs line 242, whose signature is `string -> JournalRequest seq`. (The latter is an F# alias for `IEnumerable`.) Back in the handler, we use `db ctx` to get the context (more on that below), then call the method; we're piping the output of `userId ctx` into it, so it gets its lone parameter from the pipe, then its output is piped to the `asJson` function we discussed [as part of the API][api].
-
-Line 192, the handler for `/api/request/[id]/history`, demonstrates both inserting and updating data. We attempt to retrieve the request by its ID and the user ID; if that fails, we return a 404. If it succeeds, though, we add a history entry (lines 201-207), and optionally update the `showAfter` field of the request based on its recurrence. Finally, the call on line 212 commits the changes for this particular instance. Since the `.SaveChanges[Async]()` methods return the number of records affected, we cannot use the `do!` operator for this; F# makes you explicitly ignore values you aren't either returning or assigning to a name. However, defining `_` as a parameter or name demonstrates that we realize there is a value to be had, we just are not going to do anything with it.
-
-We mentioned that `CLIMutable` record types could be null. Since record types cannot normally be null, we cannot code something like `match [var] with null -> ...`; it's a compiler syntax error. What we can do, though, is use the `box` operator. `box` "boxes" whatever value we have into an object container, where we can then check it against `null`. The function `toOption` in Data.fs on line 11 does this work for us; throughout the retrieval methods, we use it to return `option`s for items that are either present or absent. This is why we could do the `match` statement in the `/api/request/[id]/history` handler against `Some` and `None` values.
-
-## Getting a `DbContext`
-
-Since Giraffe sits atop ASP.NET Core, we use the same technique; we use the `.AddDbContext()` extension method on the `IServiceCollection` interface, and assign it when we set up the dependency injection container. In our case, it's in Program.fs ([mpj:Program.fs][Program.fs]) line 50, where we also direct it to use a PostgreSQL connection defined by the connection string "mpj". (This comes from the unified configuration built from `appsettings.json` and `appsettings.[Environment].json`.) If we look back at Handlers.fs, lines 45-47, we see the definition of the `db ctx` call we used earlier. We're using the Giraffe-provided `GetService<'T>()` extension method to return this instance.
-
-
-
-Our tour is nearing its end, but we still have a few stops to go. Next time, we'll look at how we generated documentation to tell people how to use this app.
-
----
-
-1 _Writing this post has shown me that I need to either create a SQL creation script for the repo, or create an EF Core initial migration/model, so the database ever has to be recreated from scratch. It's good to write about things after you do them!_
-
-2 _This is also a package I wrote; it's [available on NuGet][oc-pkg], and I also wrote [a post about what it does][oc-post]._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[RethinkDB]: https://rethinkdb.com
-[PostgreSQL]: https://www.postgresql.org
-[ddl.js]: https://github.com/bit-badger/myPrayerJournal/blob/3c3f0a7981fa8f82d3cc904630960ca43c910cd2/src/api/src/db/ddl.js "api/db/ddl.js | myPrayerJournal | GitHub"
-[data.go]: https://github.com/bit-badger/myPrayerJournal/blob/d0ea7cf3c631512ea6b3afba61a25c83aaded6c8/src/api/data/data.go#L307 "api/data/data.go (Line 307) | myPrayerJournal | GitHub"
-[sql]: https://github.com/bit-badger/myPrayerJournal/tree/1.0.0/src/sql "sql | myPrayerJournal | GitHub"
-[Data.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Data.fs "api/Data.fs | myPrayerJournal | GitHub"
-[Handlers.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Handlers.fs "api/Handlers.fs | myPrayerJournal | GitHub"
-[api]: /2018/a-tour-of-myprayerjournal/the-api.html "A Tour of myPrayerJournal: The API | The Bit Badger Blog"
-[Program.fs]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/api/MyPrayerJournal.Api/Program.fs "api/Program.fs | myPrayerJournal | GitHub"
-[oc-pkg]: https://www.nuget.org/packages/FSharp.EFCore.OptionConverter/ "FSharp.OptionConverter | NuGet"
-[oc-post]: https://blog.bitbadger.solutions/2018/f-sharp-options-with-ef-core.html "F# Options with EF Core | The Bit Badger Blog"
diff --git a/source/_posts/2018/a-tour-of-myprayerjournal/the-front-end.md b/source/_posts/2018/a-tour-of-myprayerjournal/the-front-end.md
deleted file mode 100644
index 6e2bf25..0000000
--- a/source/_posts/2018/a-tour-of-myprayerjournal/the-front-end.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal: The Front End"
-date: 2018-08-25 08:20:00
-author: Daniel
-categories:
-- [ Programming, JavaScript, Vue ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal ]
-tags:
-- components
-- events
-- javascript
-- layout
-- parent/child
-- pug
-- router
-- routing
-- script
-- style
-- template
-- toast
-- vue
----
-_NOTES:_
-- _This is post 2 in a series; see [the introduction][intro] for all of them, and the requirements for which this software was built._
-- _Links that start with the text "mpj:" are links to the 1.0.0 tag (1.0 release) of myPrayerJournal, unless otherwise noted._
-
-[Vue][] is a front-end JavaScript framework that aims to have very little boilerplate and ceremony, while still presenting a componentized abstraction that can scale to enterprise-level if required1. Vue components can be coded using inline templates or multiple files (splitting code and template). Vue also provides Single File Components (SFCs, using the `.vue` extension), which allow you to put template, code, and style all in the same spot; these encapsulate the component, but allow all three parts to be expressed as if they were in separate files (rather than, for example, having an HTML snippet as a string in a JavaScript file). The Vetur plugin for [Visual Studio Code][vscode] provides syntax coloring support for each of the three sections of the file.
-
-## Layout
-
-Using the default template, `main.js` is the entry point; it creates a Vue instance and attaches it to an element named `app`. This file also supports registering common components, so they do not have to be specifically imported and referenced in components that wish to use them. For myPrayerJournal, we registered our common components there ([mpj:main.js][main.js]). We also registered a few third-party Vue components to support a progress bar (activated during API activity) and toasts (pop-up notifications).
-
-`App.vue` is also part of the default template, and is the component that `main.js` attaches to the `app` elements ([mpj:App.vue][App.vue]). It serves as the main template for our application; if you have done much template work, you'll likely recognize the familiar pattern of header/content/footer.
-
-This is also our first look at an SFC, so let's dig in there. The top part is the template; we used [Pug (formerly Jade)][pug] for our templates. The next part is enclosed in `script` tags, and is the script for the page. For this component, we import one additional component (`Navigation.vue`) and the version from `package.json`, then export an object that conforms to Vue's expected component structure. Finally, styles for the component are enclosed in `style` tags. If the `scoped` attribute is present on the style tag, Vue will generate data attributes for each element, and render the declared styles as only affecting elements with that attribute. myPrayerJournal doesn't use scoped styles that much; Vue recommends classes instead, if practical, to reduce complexity in the compiled app.
-
-Also of note in `App.js` is the code surrounding the use of the `toast` component. In the template, it's declared as `toast(ref='toast')`. Although we registered it in `main.js` and can use it anywhere, if we put it in other components, they create their own instance of it. The `ref` attribute causes Vue to generate a reference to that element in the component's `$refs` collection. This enables us to, from any component loaded by the router (which we'll discuss a bit later), access the toast instance by using `this.$parent.$refs.toast`, which allows us to send toasts whenever we want, and have the one instance handle showing them and fading them out. (Without this, toasts would appear on top of each other, because the independent instances have no idea what the others are currently showing.)
-
-## Routing
-
-Just as URLs are important in a regular application, they are important in a Vue app. The Vue router is a separate component, but can be included in the new project template via the Vue CLI. In `App.vue`, the `router-view` item renders the output from the router; we wire in the router in `main.js`. Configuring the router ([mpj:router.js][router.js]) is rather straightforward:
-- Import all of the components that should appear to be a page (i.e., not modals or common components)
-- Assign each route a path and name, and specify the component
-- For URLs that contain data (a segment starting with `:`), ensure `props: true` is part of the route configuration
-
-The `scrollBehavior` function, as it appears in the source, makes the Vue app mimic how a traditional web application would handle scrolling. If the user presses the back button, or you programmatically go back 1 page in history, the page will return to the point where it was previously, not the top of the page.
-
-To specify a link to a route, we use the `router-link` tag rather than a plain `a` tag. This tag takes a `:to` parameter, which is an object with a `name` property; if it requires parameters/properties, a `params` property is included. [mpj:Navigation.vue][Navigation.vue] is littered with the former; see the `showEdit` method in [mpj:RequestCard.vue][RequestCard.vue] for the structure on the latter (and also an example of programmatic navigation vs. `router-link`).
-
-## Components
-
-When software developers hear "components," they generally think of reusable pieces of software that can be pulled together to make a system. While that isn't wrong, it's important to understand that "reusable" does not necessarily mean "reused." For example, the privacy policy ([mpj:PrivacyPolicy.vue][PrivacyPolicy.vue]) is a component, but reusing it throughout the application would be... well, let's just say a "sub-optimal" user experience.
-
-However, that does not mean that none of our components will be reused. `RequestCard`, which we referenced above, is used in a loop in the `Journal` component ([mpj:Journal.vue][Journal.vue]); it is reused for every request in the journal. In fact, it is reused even for requests that should not be shown; behavior associated with the `shouldDisplay` property makes the component display nothing if a request is snoozed or is in a recurrence period. Instead of the journal being responsible for answering the question "Should I display this request?", the request display answers the question "Should I render anything?". This may seem different from typical server-side page generation logic, but it will make more sense once we discuss state management (next post).
-
-Looking at some other reusable (and reused) components, the page title component ([mpj:PageTitle.vue][PageTitle.vue]) changes the title on the HTML document, and optionally also displays a title at the top of the page. The "date from now" component ([mpj:DateFromNow.vue][DateFromNow.vue]) is the most frequently reused component. Every time it is called, it generates a relative date, with the actual date/time as a tool tip; it also sets a timeout to update this every 10 seconds. This keeps the relative time in sync, even if the router destination stays active for a long time.
-
-Finally, it's also worth mentioning that SFCs do not have to have all three sections defined. Thanks to conventions, and depending on your intended use, none of the sections are required. The "date from now" component only has a `script` section, while the privacy policy component only has a `template` section.
-
-## Component Interaction
-
-Before we dive into the specifics of events, let's look again at `Journal` and `RequestCard`. In the current structure, `RequestCard` will always have `Journal` as a parent, and `Journal` will always have `App` as its parent. This means that `RequestCard` could, technically, get its toast implementation via `this.$parent.$parent.toast`; however, this type of coupling is very fragile2. Requiring `toast` as a parameter to `RequestCard` means that, wherever `RequestCard` is implemented, if it's given a `toast` parameter, it can display toasts for the actions that would occur on that request. `Journal`, as a direct descendant from `App`, can get its reference to the toast instance from its parent, then pass it along to child components; this only gives us one layer of dependency.
-
-In Vue, generally speaking, parent components communicate with child components via props (which we see with passing the toast instance to `RequestCard`); child components communicate with parents via events. The names of events are not prescribed; the developer comes up with them, and they can be as terse or descriptive as desired. Events can optionally have additional data that goes with it. The Vue instance supports subscribing to event notifications, as well as emitting events. We can also create a separate Vue instance to use as an event bus if we like. myPrayerJournal uses both of these techniques in different places.
-
-As an example of the first, let's look at the interaction between `ActiveRequests` ([mpj:ActiveRequests.vue][ActiveRequests.vue]) and `RequestListItem` ([mpj:RequestListItem.vue][RLI.vue]). On lines 41 and 42 of `ActiveRequests` (the parent), it subscribes to the `requestUnsnoozed` and `requestNowShown` events. Both these events trigger the page to refresh its underlying data from the journal. `RequestListItem`, lines 67 and 79, both use `this.$parent.$emit` to fire off these events. This model allows the child to emit events at will, and if the parent does not subscribe, there are no errors. For example, `AnswerdRequests` ([mpj:AnsweredRequests.vue][AnsweredRequests.vue]) does not subscribe to either of these events. (`RequestListItem` will not show the buttons that cause those events to be emitted, but even if it did, emitting the event would not cause an error.)
-
-An example of the second technique, a dedicated parent/child event bus, can be seen back in `Journal` and `RequestCard`. Adding notes and snoozing requests are modal windows3. Rather than specifying an instance of these per request, which could grow rather quickly, `Journal` only instantiates one instance of each modal (lines 19-22). It also creates the dedicated Vue instance (line 46), and passes it to the modal windows and each `RequestCard` instance (lines 15, 20, and 22). Via this event bus, any `RequestCard` instance can trigger the notes or snooze modals to be shown. Look through `NotesEdit` ([mpj:NotesEdit.vue][NotesEdit.vue]) to see how the child listens for the event, and also how it resets its state (the `closeDialog()` method) so it will be fresh for the next request.
-
-
-
-That wraps up our tour of Vue routes and components; next time, we'll take a look at Vuex, and how it helps us maintain [state in the browser][state].
-
----
-1 _That's my summary; I'm sure they've got much more eloquent ways to describe it._
-
-2 _...and kinda ugly, but maybe that's just me._
-
-3 _Up until nearly the end of development, editing requests was a modal as well. Adding recurrence made it too busy, so it got to be its own page._
-
-
-[intro]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[Vue]: https://vuejs.org
-[main.js]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/main.js "app/src/main.js | myPrayerJournal | GitHub"
-[App.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/App.vue "app/src/App.vue | myPrayerJournal | GitHub"
-[pug]: https://pugjs.org
-[vscode]: https://code.visualstudio.com
-[router.js]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/router.js "app/src/router.js | myPrayerJournal | GitHub"
-[Navigation.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/common/Navigation.vue "app/src/components/common/Navigation.vue | myPrayerJournal | GitHub"
-[RequestCard.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/RequestCard.vue#L45 "app/src/components/request/RequestCard.vue | myPrayerJournal | GitHub"
-[PrivacyPolicy.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/legal/PrivacyPolicy.vue "app/src/components/legal/PrivacyPolicy.vue | myPrayerJournal | GitHub"
-[Journal.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/Journal.vue "app/src/components/Journal.vue | myPrayerJournal | GitHub"
-[PageTitle.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/common/PageTitle.vue "app/src/components/common/PageTitle.vue | myPrayerJournal | GitHub"
-[DateFromNow.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/common/DateFromNow.vue "app/src/components/common/DateFromNow.vue | myPrayerJournal | GitHub"
-[ActiveRequests.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/ActiveRequests.vue "app/src/components/request/ActiveRequests.vue | myPrayerJournal | GitHub"
-[RLI.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/RequestListItem.vue "app/src/components/request/RequestListItem.vue | myPrayerJournal | GitHub"
-[AnsweredRequests.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/AnsweredRequests.vue "app/src/components/request/AnsweredRequests.vue | myPrayerJournal | GitHub"
-[NotesEdit.vue]: https://github.com/bit-badger/myPrayerJournal/blob/1.0.0/src/app/src/components/request/NotesEdit.vue "app/src/components/request/NotesEdit.vue | myPrayerJournal | GitHub"
-[state]: /2018/a-tour-of-myprayerjournal/state-in-the-browser.html "A Tour of myPrayerJournal: State in the Browser | The Bit Badger Blog"
diff --git a/source/_posts/2018/f-sharp-options-with-ef-core.md b/source/_posts/2018/f-sharp-options-with-ef-core.md
deleted file mode 100644
index f554077..0000000
--- a/source/_posts/2018/f-sharp-options-with-ef-core.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-layout: post
-title: F# Options with EF Core
-date: 2018-07-08 17:00:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Projects, OptionConverter ]
-tags:
-- f#
-- ef core
-- entity framework core
----
-**UPDATE:** The code described below is now available as a [NuGet package][ng].
-
-The 2.1 release of [Entity Framework Core][efcore] brought the ability to do [value conversions][vc]. This is implemented through an abstract class, `ValueConverter`, which you can implement to convert a data type. They also provided [several built-in converters][bic] that you don't have to write, such as storing `enum`s as strings. To use a value converter, you provide a new instance of it and attach it to a property in your model's `OnModelCreating` event.
-
-F# provides an `Option<'T>` type as a way to represent a value that may or may not be present. There are many benefits to defining optional values as `'T option` rather than checking for null; you can [read all about it][opt] if you'd like.
-
-As I was working on a project, I already used `Option.ofObj` to convert my possibly-null results from queries to options; at the field level, though, I was working with default values. Could I use this new feature to handle `null`able columns as well? As it turns out, yes!
-
-Here is the code for the value converter.
-
-{% codeblock lang:fsharp %}
-module Conversion =
-
- open Microsoft.FSharp.Linq.RuntimeHelpers
- open System
- open System.Linq.Expressions
-
- let toOption<'T> =
- <@ Func<'T, 'T option>(fun (x : 'T) -> match box x with null -> None | _ -> Some x) @>
- |> LeafExpressionConverter.QuotationToExpression
- |> unbox>>
-
- let fromOption<'T> =
- <@ Func<'T option, 'T>(fun (x : 'T option) -> match x with Some y -> y | None -> Unchecked.defaultof<'T>) @>
- |> LeafExpressionConverter.QuotationToExpression
- |> unbox>>
-
-type OptionConverter<'T> () =
- inherit ValueConverter<'T option, 'T> (Conversion.fromOption, Conversion.toOption)
-{% endcodeblock %}
-
-The `Conversion` module contains the functions that we'll need to provide in the `ValueConverter` constructor. _(With the way class inheritance is coded in F#, and the way `ValueConverter` wants its expressions in its constructor, this is a necessary step. I would have liked to have seen a no-argument constructor and overridable properties as an option, but I'm not complaining; this is a really great feature.)_ Within those functions, we make use of [code quotations][quot], then convert the quotation expressions to Linq expressions.
-
-One other note; in the `toOption` function, if we used `Option.ofObj` instead of `box x`, the code would not support value types. This means that things like an `int option` field wouldn't be supported.
-
-Now that we have our option converter, let's hook it into our model. In my project, each entity type has a static `configureEF` function, and I call those from `OnModelCreating`. Here's an abridged version of one of my entity types:
-
-{% codeblock lang:fsharp %}
- []
- []
- []
- Member =
- { /// ...
- /// E-mail format
- format : string option
- /// ...
- }
- with
- /// ...
- static member configureEF (mb : ModelBuilder) =
- /// ... HasColumnName statements, etc.
- mb.Model.FindEntityType(typeof).FindProperty("format").SetValueConverter(OptionConverter ())
- |> ignore
-{% endcodeblock %}
-
-This line of code finds the type within the model, the property within the type, and provides the new instance of our option converter to it. In this entity, a `None` here indicates that the member uses the group's default e-mail format; `Some` would indicate that they've specified which format they prefer.
-
-That's all there is to it! Define the converter once, and plug it in to all the optional fields; now we have nullable fields translated to options by EF Core. ["Magic unicorn,"][mu] indeed!
-
-_(Credits: Many thanks to Jiří Činčura for the [excellent value conversion blog post][vcblog] and Tomas Petricek for his [Stack Overflow answer on converting quotation expressions to Linq expressions][so].)_
-
-[efcore]: https://docs.microsoft.com/en-us/ef/core/
-[vc]: https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions
-[bic]: https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions#built-in-converters
-[opt]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/options
-[quot]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/code-quotations
-[mu]: https://twitter.com/efmagicunicorns
-[vcblog]: https://www.tabsoverspaces.com/233708-using-value-converter-for-custom-encryption-of-field-on-entity-framework-core-2-1
-[so]: https://stackoverflow.com/a/23146624
-[ng]: https://www.nuget.org/packages/FSharp.EFCore.OptionConverter/
diff --git a/source/_posts/2021/a-tour-of-myprayerjournal-v3/bootstrap-integration.md b/source/_posts/2021/a-tour-of-myprayerjournal-v3/bootstrap-integration.md
deleted file mode 100644
index a7fb683..0000000
--- a/source/_posts/2021/a-tour-of-myprayerjournal-v3/bootstrap-integration.md
+++ /dev/null
@@ -1,344 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal v3: Bootstrap Integration"
-date: 2021-11-29 16:51:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Programming, htmx ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal v3 ]
-tags:
-- bootstrap
-- css
-- events
-- f#
-- giraffe
-- html
-- htmx
-- javascript
-- migration
-- modal
-- notification
-- single page application
-- spa
-- toast
-- vue
----
-
-_NOTE: This is the third post in a series; see [the introduction][intro] for information on requirements and links to other posts in the series._
-
-Many modern Single Page Application (SPA) frameworks include (or have plugins for) CSS transitions and effects. Combined with the speed of not having to do a full refresh, this is one of their best features. One might not think that a framework like [htmx][], which simply swaps out sections of the page, would have this; but if one were to think that, one would be wrong. Sadly, though, I did not utilize those aspects of htmx while I was migrating myPrayerJournal from v2 to v3; however, I will highlight the htmx way to do this in [last section of this post][css-in-htmx].
-
-myPrayerJournal v2 used a [Vue][] plugin that provided Bootstrap v4 support; myPrayerJournal v3 uses [Bootstrap][] v5. The main motivation I had to remain with Bootstrap was that I liked the actual appearance, and I know how it works. The majority of my "learning" on this project dealt with htmx; I did not want to add a UI redesign to the mix. Before we jump into the implementation, let me briefly explain the framework.
-
-## About Bootstrap
-
-Bootstrap was originally called Twitter Bootstrap; it was the CSS framework that Twitter developed in their early iterations. It was, by far, the most popular framework at the time, and it was innovative in its grid layout system. Long before there was browser support for the styles that make layouts much easier to develop, and more responsive to differing screen sizes, Bootstrap's grid layout and size breakpoints made it easy to build a website that worked for desktop, tablet, or phone. Of course, there is a limit to what you can do with styling, so Bootstrap also has a JavaScript library that augments these styles, enabling the interactivity to which the modern web user is accustomed.
-
-Version 5 of Bootstrap continues this tradition; however, it brings in even more utility classes, and supports Flex layouts as well. It is a mature library that continues to be maintained, and the project's philosophy seems to be "just enough" - it's not going to do everything for everyone, but in the majority of cases, it has exactly what the developer needs. It is not a bloated library that needs tree-shaking to avoid a ridiculous download size.
-
-It is, by far, the largest payload in the initial page request:
-
-- Bootstrap - 48.6 kB (CSS is 24.8 kB; JavaScript is 23.8 kB, deferred until after render)
-- htmx - 11.8 kB
-- myPrayerJournal - 4.4 kB (CSS is 1.2 kB, JavaScript is 3.2 kB)
-
-However, this gets the entire style and script, and allows us to use their layouts and interactive components. But, how do we get that interactivity from the server?
-
-## Hooking in to the htmx Request Pipeline
-
-htmx provides [several events][htmx-evts] to which an application can listen. In myPrayerJournal v3, [I used `htmx:afterOnLoad`][v3-onload] because I did not need the new content to be swapped in yet when the function fired. There are `afterSwap` and `afterSettle` events which will fire once those events have occurred, if you need to defer processing until those are complete.
-
-There are two different Bootstrap script-driven components myPrayerJournal uses; let's take a look at toasts.
-
-## A Toast ~~to~~ Via htmx
-
-[Toasts][bs-toast] are pop-up notifications that appear on the screen, usually for a short time, then fade out. In some cases, particularly if the toast is alerting the user to an error, it will stay on the screen until the user dismisses it, usually by clicking an "x" in the upper right-hand corner _(even if the developer used a Mac!)_. Bootstrap provides a host of options for their toast component; for our uses, though, we will:
-
-- Place toasts in the bottom right-hand corner;
-- Allow multiple toasts to be visible at once;
-- Auto-hide success toasts; require others to be dismissed manually.
-
-There are several different aspects that make this work.
-
-### The Toaster
-
-Just like IRL toast comes out of a toaster, our toasts need a place from which to emerge. In the [prior post][prior], I mentioned that the footer does not get reloaded when a "page" request is made. There is also an element above the footer that also remains across these requests - defined here as the "toaster" (my term, not Bootstrap's).
-
-```fsharp
-/// Element used to display toasts
-let toaster =
- div [ _ariaLive "polite"; _ariaAtomic "true"; _id "toastHost" ] [
- div [ _class "toast-container position-absolute p-3 bottom-0 end-0"; _id "toasts" ] []
- ]
-```
-
-This renders two empty `div`s with the appropriate style attributes; toasts placed in the `#toasts` `div` will display as we want them to.
-
-### Showing the Toast
-
-Bootstrap provides `data-` attributes that can make toasts appear; however, since we are creating these in script, we need to use their JavaScript functions. The message coming from the server has the format `TYPE|||The message`. Let's look at [the showToast function][v3-toast] (the largest custom JavaScript function in the entire application):
-
-```javascript
-const mpj = {
- // ...
- showToast (message) {
- const [level, msg] = message.split("|||")
-
- let header
- if (level !== "success") {
- const heading = typ => `${typ.toUpperCase()}`
-
- header = document.createElement("div")
- header.className = "toast-header"
- header.innerHTML = heading(level === "warning" ? level : "error")
-
- const close = document.createElement("button")
- close.type = "button"
- close.className = "btn-close"
- close.setAttribute("data-bs-dismiss", "toast")
- close.setAttribute("aria-label", "Close")
- header.appendChild(close)
- }
-
- const body = document.createElement("div")
- body.className = "toast-body"
- body.innerText = msg
-
- const toastEl = document.createElement("div")
- toastEl.className = `toast bg-${level === "error" ? "danger" : level} text-white`
- toastEl.setAttribute("role", "alert")
- toastEl.setAttribute("aria-live", "assertlive")
- toastEl.setAttribute("aria-atomic", "true")
- toastEl.addEventListener("hidden.bs.toast", e => e.target.remove())
- if (header) toastEl.appendChild(header)
-
- toastEl.appendChild(body)
- document.getElementById("toasts").appendChild(toastEl)
- new bootstrap.Toast(toastEl, { autohide: level === "success" }).show()
- },
- // ...
-}
-```
-
-Here's what's going on in the code above:
-
-- Line 4 splits the level from the message
-- Lines 6-20 (`let header`) create a header and close button if the message is not a success
-- Lines 22-24 (`const body`) create the body `div` with attributes Bootstrap's styling expects
-- Lines 26-30 (`const toastEl`) create the `div` that will contain the toast
-- Line 31 adds an event handler to remove the element from the DOM once the toast is hidden
-- Lines 32 and 34 add the optional header and mandatory body to the toast `div`
-- Line 35 adds the toast to the page (within the `toasts` inner `div` defined above)
-- Line 36 initializes the Bootstrap JavaScript component, auto-hiding on success, and shows the toast
-
-_(If you've never used JavaScript to create elements that are added to an HTML document, this probably looks weird and verbose; if you have, you look at it and think "well, they're not wrong...")_
-
-So, we have our toaster, we know how to put ~~bread~~ notifications in it - but how do we get the notifications from the server?
-
-### Receiving the Toast
-
-The code to handle this is part of the `htmx:afterOnLoad` handler:
-
-```javascript
-htmx.on("htmx:afterOnLoad", function (evt) {
- const hdrs = evt.detail.xhr.getAllResponseHeaders()
- // Show a message if there was one in the response
- if (hdrs.indexOf("x-toast") >= 0) {
- mpj.showToast(evt.detail.xhr.getResponseHeader("x-toast"))
- }
- // ...
-})
-```
-
-This looks for a custom HTTP header of `X-Toast` (all headers are lowercase from that `xhr` call), and if it's found, we pass the value of that header to the function above. This check occurs after every htmx network request, so there is nothing special to configure; "page" requests are not the only requests capable of returning a toast notification.
-
-There is one more part; how does the toast get to the browser?
-
-### Sending the Toast
-
-The last paragraph gave it away; we set a header on the response. This seems straightforward, and is in most cases; but [once again, POST-Redirect-GET][part1-prg] (P-R-G) complicates things. Here are the final two lines of the successful path of [the request update handler][v3-upd8]:
-
-```fsharp
-Messages.pushSuccess ctx "Prayer request updated successfully" nextUrl
-return! seeOther nextUrl next ctx
-```
-
-If we set a message in the response header, then redirect (remember that `XMLHttpRequest` handles redirects silently), the header gets lost in the redirect. Here, `Messages.pushSuccess` places the success message (and return URL) in a dictionary, indexed by the user's ID. Within the function that renders every result (partial, "page"-like, or full results), this dictionary is checked for a message and URL, and if one exists, it includes it. (If it is returned to the function below, it has already been removed from the dictionary.)
-
-```fsharp
-/// Send a partial result if this is not a full page load (does not append no-cache headers)
-let partialStatic (pageTitle : string) content : HttpHandler =
- fun next ctx -> backgroundTask {
- let isPartial = ctx.Request.IsHtmx && not ctx.Request.IsHtmxRefresh
- let! pageCtx = pageContext ctx pageTitle content
- let view = (match isPartial with true -> partial | false -> view) pageCtx
- return!
- (next, ctx)
- ||> match user ctx with
- | Some u ->
- match Messages.pop u with
- | Some (msg, url) -> setHttpHeader "X-Toast" msg >=> withHxPush url >=> writeView view
- | None -> writeView view
- | None -> writeView view
- }
-```
-
-A quick overview of this function:
-
-- Line 4 determines if this an htmx boosted request (a "page"-like requests)
-- Line 5 creates a rendering context for the page
-- Line 6 renders the view to a string, calling `partial` or `view` with the page rendering context
-- Lines 10-13 are only executed if a user is logged on, and line 12 is the one that appends a message and a new URL
-
-> **_A quick note about line 12:_** the `>=>` operator joins Giraffe `HttpHandler`s together. An `HttpHandler` takes an `HttpContext` and the next function to be executed, and returns a `Task` (an asynchronous call that may or may not return a context). If there is no context returned, the chain stops; the function can also return an altered context. It is good practice for an `HttpHandler` to make a single change to the context; this keeps them simple, and allows them to be plugged in however the developer desires. Thus, the `setHttpHeader` call adds the `X-Toast` header, the `withHxPush` call adds the `HX-Push` header, and the `writeView` call sets the response body to the rendered view.
-
-The new URL part does not actually make the browser do anything; it simply pushes the given URL onto the browser's history stack. Technically, the browser receives the content from the P-R-G as the response to its POST; as we're replacing the current page, though, we need to make sure the URL stays in sync.
-
-Of note is that not all toasts are this complex. For example, the "cancel snooze" handler return looks like this:
-
-```fsharp
-return! (withSuccessMessage "Request unsnoozed" >=> Components.requestItem requestId) next ctx
-```
-
-...while the `withSuccessMessage` handler is:
-
-```fsharp
-/// Add a success message header to the response
-let withSuccessMessage : string -> HttpHandler =
- sprintf "success|||%s" >> setHttpHeader "X-Toast"
-```
-
-No dictionary, no redirect, just a single response that will show a toast.
-
-You made it - the toast section is toast! There is one more interesting interaction, though; that of the modal dialog.
-
-## Modal Dialogs
-
-Bootstrap's [implementation of modal dialogs][bs-modal] also uses JavaScript; however, for the purposes of the modals used in myPrayerJournal v3, we can use the `data-` attributes to show them. Here is the view for a modal dialog that allows the user to snooze a request (hiding it from the active list until the specified date); this is rendered a single time on the journal view page:
-
-```fsharp
-div [
- _id "snoozeModal"
- _class "modal fade"
- _tabindex "-1"
- _ariaLabelledBy "snoozeModalLabel"
- _ariaHidden "true"
- ] [
- div [ _class "modal-dialog modal-sm" ] [
- div [ _class "modal-content" ] [
- div [ _class "modal-header" ] [
- h5 [ _class "modal-title"; _id "snoozeModalLabel" ] [ str "Snooze Prayer Request" ]
- button [ _type "button"; _class "btn-close"; _data "bs-dismiss" "modal"; _ariaLabel "Close" ] []
- ]
- div [ _class "modal-body"; _id "snoozeBody" ] [ ]
- div [ _class "modal-footer" ] [
- button [ _type "button"; _id "snoozeDismiss"; _class "btn btn-secondary"; _data "bs-dismiss" "modal" ] [
- str "Close"
- ]
- ]
- ]
- ]
- ]
-```
-
-Notice that `#snoozeBody` is empty; we fill that when the user clicks the snooze icon:
-
-```fsharp
-button [
- _type "button"
- _class "btn btn-secondary"
- _title "Snooze Request"
- _data "bs-toggle" "modal"
- _data "bs-target" "#snoozeModal"
- _hxGet $"/components/request/{reqId}/snooze"
- _hxTarget "#snoozeBody"
- _hxSwap HxSwap.InnerHtml
- ] [ icon "schedule" ]
-```
-
-This uses `data-bs-toggle` and `data-bs-target`, Bootstrap attributes, to show the modal. It also uses `hx-get` to load the snooze form for that particular request, with `hx-target` targeting the `#snoozeBody` `div` from the modal definition. Here is how that form is defined:
-
-```fsharp
-/// The snooze edit form
-let snooze requestId =
- let today = System.DateTime.Today.ToString "yyyy-MM-dd"
- form [
- _hxPatch $"/request/{RequestId.toString requestId}/snooze"
- _hxTarget "#journalItems"
- _hxSwap HxSwap.OuterHtml
- ] [
- div [ _class "form-floating pb-3" ] [
- input [ _type "date"; _id "until"; _name "until"; _class "form-control"; _min today; _required ]
- label [ _for "until" ] [ str "Until" ]
- ]
- p [ _class "text-end mb-0" ] [ button [ _type "submit"; _class "btn btn-primary" ] [ str "Snooze" ] ]
- ]
-```
-
-Here, the form uses `hx-patch` to submit the data to the snooze endpoint. The target for the response, though, is `#journalItems`; this is the element that holds all of the prayer request cards. Snoozing a request will remove it from the active list, so the list needs to be refreshed; this will make that happen.
-
-Look back at the modal definition; at the bottom, there is a "Close" button. We will use this to dismiss the modal once the update succeeds. In the Giraffe handler to snooze a request, here is its `return` statement:
-
-```fsharp
-return!
- (withSuccessMessage $"Request snoozed until {until.until}"
- >=> hideModal "snooze"
- >=> Components.journalItems) next ctx
-```
-
-Notice that `hideModal` handler?
-
-```fsharp
-/// Hide a modal window when the response is sent
-let hideModal (name : string) : HttpHandler =
- setHttpHeader "X-Hide-Modal" name
-```
-
-Yes, it's another HTTP header! One can certainly get carried away with custom HTTP headers, but their very existence is to communicate with the client (browser) outside of the visible content of the page. Here, we're passing the name "snooze" to this header; in our `htmx:afterOnLoad` handler, we'll consume this header:
-
-```javascript
-htmx.on("htmx:afterOnLoad", function (evt) {
- const hdrs = evt.detail.xhr.getAllResponseHeaders()
- // ...
- // Hide a modal window if requested
- if (hdrs.indexOf("x-hide-modal") >= 0) {
- document.getElementById(evt.detail.xhr.getResponseHeader("x-hide-modal") + "Dismiss").click()
- }
-})
-```
-
-The "Close" button on our modal was given the `id` of `snoozeDismiss`; this mimics the user clicking the button, which Bootstrap's `data-` attributes handle from there. Of all the design choices and implementations I did in this conversion, this part strikes me as the most "hack"y. However, I did try to hook into the Bootstrap modal itself, and hide it via script; however, it didn't like initializing a modal a second time, and I could not get a reference to it from the `htmx:afterOnLoad` handler. Clicking the button works, though, even when it's done from script.
-
-## CSS Transitions in htmx
-
-This post has already gotten much longer than I had planned, but I wanted to make sure I covered this.
-
-- When htmx requests are in flight, the framework makes it easy to [show indicators][ind].
-- I mentioned swapping and settling when discussing the events htmx exposes. The way this is done, [CSS transitions][trans] will render as expected. They have [a host of examples][exmpls] to spark your imagination.
-
-As I was keeping the UI the same, I did not end up using these options; however, their presence demonstrates that htmx is a true batteries-included SPA framework.
-
----
-
-Up next, we'll step away from the front end and [dig into LiteDB][part3].
-
-
-[intro]: /2021/a-tour-of-myprayerjournal-v3/introduction.html "A Tour of myPrayerJournal v3: Introduction | The Bit Badger Blog"
-[htmx]: https://htmx.org "htmx"
-[css-in-htmx]: #CSS-Transitions-in-htmx "CSS Interactivity with htmx | A Tour of myPrayerJournal v3: Bootstrap Integration | The Bit Badger Blog"
-[Vue]: https://vuejs.org "Vue.js"
-[Bootstrap]: https://getbootstrap.com "Bootstrap"
-[htmx-evts]: https://htmx.org/reference/#events "Events | Reference | htmx"
-[v3-onload]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/wwwroot/script/mpj.js#L72 "myPrayerJournal v3 htmx:afterOnLoad function"
-[bs-toast]: https://getbootstrap.com/docs/5.1/components/toasts/ "Toasts | Bootstrap"
-[prior]: /2021/a-tour-of-myprayerjournal-v3/the-user-interface.html#%E2%80%9CNew-Page%E2%80%9D-in-htmx "A Tour of myPrayerJournal v3: The User Interface | The Bit Badger Blog"
-[v3-toast]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/wwwroot/script/mpj.js#L9 "myPrayerJournal v3 showToast function"
-[part1-prg]: /2021/a-tour-of-myprayerjournal-v3/the-user-interface.html#POST-Redirect-GET "A Tour of myPrayerJournal v3: The User Interface | The Bit Badger Blog"
-[v3-upd8]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Handlers.fs#L503 "myPrayerJournal v3 request update handler"
-[bs-modal]: https://getbootstrap.com/docs/5.1/components/modal/ "Modal | Bootstrap"
-[ind]: https://htmx.org/docs/#indicators "Request Indicators | Docs | htmx"
-[trans]: https://htmx.org/docs/#css_transitions "CSS Transitions | Docs | htmx"
-[exmpls]: https://htmx.org/examples/animations/ "Animations | Examples | htmx"
-[part3]: /2021/a-tour-of-myprayerjournal-v3/the-data-store.html "A Tour of myPrayerJournal v3: The Data Store | The Bit Badger Blog"
diff --git a/source/_posts/2021/a-tour-of-myprayerjournal-v3/conclusion.md b/source/_posts/2021/a-tour-of-myprayerjournal-v3/conclusion.md
deleted file mode 100644
index 8e05a41..0000000
--- a/source/_posts/2021/a-tour-of-myprayerjournal-v3/conclusion.md
+++ /dev/null
@@ -1,105 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal v3: Conclusion"
-date: 2021-12-07 16:26:00
-author: Daniel
-categories:
-- [ Databases, LiteDB ]
-- [ Programming, .NET, F# ]
-- [ Programming, htmx ]
-- [ Projects, Giraffe.Htmx ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal v3 ]
-tags:
-- complexity
-- f#
-- giraffe
-- hateoas
-- headers
-- html
-- htmx
-- javascript
-- jetbrains
-- khalid abuhakmeh
-- litedb
-- mapping
-- migration
-- nuget
-- open source
-- rest
-- simplicity
-- view engine
-- writing
----
-
-_NOTE: This is the final post in a series; see [the introduction][intro] for information on requirements and links to other posts in the series._
-
-We've gone in depth on several different aspects of this application and the technologies it uses. Now, let's zoom out and look at some big-picture lessons learned.
-
-## What I Liked
-
-Generally speaking, I liked everything. That does not make for a very informative post, though, so here are a few things that worked really well.
-
-### Simplification Via htmx
-
-One of the key concepts in a Representational State Transfer (REST) API is that of Hypermedia as the Engine of Application State (HATEOAS). In short, this means that the state of an application is held within the hypermedia that is exchanged between client and server; and, in practice, the server is responsible for altering that state. This is completely different from the JSON API / JavaScript framework model, even if they use `GET`, `POST`, `PUT`, and `PATCH` properly.
-
-_(This is a near over-simplification; the paper that initially proposed these concepts -- in much, much more detail -- earned its author a doctoral degree.)_
-
-The simplicity of this model is great; and, when I say "simplicity," I am speaking of a lack of complexity, not a naïveté of approach. I was able to remove a large amount of complexity and synchronization from the client/server interactions between myPrayerJournal v2 and v3. State management used to be the most complex part of the application. Now, the most complex part is the HTML rendering; since that is what controls the state, though, this makes sense. I have 25 years of experience writing HTML, and even at its most complex, it simply is not.
-
-### LiteDB
-
-This was a very simple application - and, despite its being open for any user with a Google or Microsoft account, I have been the only regular user of the application. LiteDB's setup was easy, implementation was easy, and it performs really well. I suspect this would be the case with many concurrent users. If the application were to grow, and I find that my suspicion was not borne out by reality, I could create a database file per user, and back up the data directory instead of a specific file. As with [htmx][], the lack of complexity makes the application easily maintainable.
-
-## What I Learned
-
-Throughout this entire series of posts, most of the content would fall under this heading. There are a few things that did not fit into those posts, though.
-
-### htmx Support in .NET
-
-[I developed `Giraffe.Htmx` as a part of this effort][g-h], and mentioned that I became aware of htmx on an episode of _.NET Rocks!_. The project I developed is very F#-centric, and uses features of the language that are not exposed in C# or VB.NET. However, there are two packages that work with the standard ASP.NET Core paradigm. [`Htmx`][a-h] provides server-side support for the htmx request and response headers, similar to `Giraffe.Htmx`, and [`Htmx.TagHelpers`][a-h-h] contains tag helpers for use in Razor, similar to what `Giraffe.ViewEngine.Htmx` does for Giraffe View Engine. Both are written by [Khalid Abuhakmeh][ka], a developer advocate at [JetBrains][] (which generously [licensed their tools to this project][jb-oss], and produces [the best developer font ever][jb-mono]).
-
-While I did not use these projects, I did look at the source, and they look good. Open source libraries go from good to great by people using them, then providing constructive feedback (and pull requests, if you are able).
-
-### Write about Your Code
-
-Yes, [I'm cheating a bit with this one, as it was one of the takeaways from the v1 tour][v1-write], but it's still true. Writing about your code has several benefits:
-
-- You understand your code more fully.
-- Others can see not just the code you wrote, but understand the thought process behind it.
-- Readers can provide you feedback. _(This may not always seem helpful; regardless of its tone, though, thinking through whether the point of their critique is justified can help you learn.)_
-
-And, really, knowledge sharing is what makes the open-source ecosystem work. Closed / proprietary projects have their place, but if you do something interesting, write about it!
-
-## What Could Be Better
-
-Dove-tailing from the previous section, writing can also help you think through your code; if you try to explain it, and and have trouble, that should serve as a warning that there are improvements to be had. These are the areas where this project has room to get better.
-
-### Deferred Features
-
-There were 2 changes I had originally planned for myPrayerJournal v3 that did not get accomplished. One is a new "pray through the requests" view, with a distraction-free next-card-up presentation. The other is that updating requests sends them to the bottom of the list, even if they have not been marked as prayed; this will require calculating a separate "last prayed" date instead of using the "as of" date from the latest history entry.
-
-The migration introduced a third deferred change. When v1/v2 ran in the browser, the dates and times were displayed in the user's local timezone. With the HTML being generated on the server, though, dates and times are now displayed in UTC. The purpose of the application is to focus the user's attention on their prayer requests, not to make them have to do timezone math in their head! htmx has an `hx-headers` attribute that specifies headers to pass along with the request; I plan to use [a JavaScript call][js-intl] to set a header on the `body` tag when a full page loads (`hx-headers` is inherited), then use that timezone to adjust it back to the user's current timezone.
-
-### That LiteDB Mapping
-
-I did a good bit of tap-dancing in the [LiteDB data model and mapping descriptions][part3], mildly defending the design decisions I had made there. The recurrence should be designed differently, and there should be individual type mappings rather than mapping the entire document. Yes, it worked for my purpose, and this project was more about Vue to htmx than ensuring a complete F#-to-LiteDB mapping of domain types. As I implement the features above, though, I believe I will end up fixing those issues as well.
-
-----
-
-Thank you for joining me on this tour; I hope it has been enjoyable, and maybe even educational.
-
-
-[intro]: /2021/a-tour-of-myprayerjournal-v3/introduction.html "A Tour of myPrayerJournal v3: Introduction | The Bit Badger Blog"
-[htmx]: https://htmx.org "htmx"
-[g-h]: https://github.com/bit-badger/Giraffe.Htmx "Giraffe.Htmx"
-[a-h]: https://www.nuget.org/packages/Htmx/ "Htmx | NuGet"
-[a-h-h]: https://www.nuget.org/packages/Htmx.TagHelpers/ "Htmx.TagHelpers | NuGet"
-[ka]: https://khalidabuhakmeh.com "Khalid Abuhakmeh"
-[JetBrains]: https://www.jetbrains.com "JetBrains"
-[jb-oss]: https://www.jetbrains.com/community/opensource/#support "Licenses for Open Source Development | JetBrains"
-[jb-mono]: https://www.jetbrains.com/lp/mono/ "JetBrains Mono"
-[v1-write]: /2018/a-tour-of-myprayerjournal/conclusion.html#Write-about-Your-Code "A Tour of myPrayerJournal: Conclusion | The Bit Badger Blog"
-[js-intl]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions "Intl.DateTimeFormat.prototype.resolvedOptions | MDN"
-[part3]: /2021/a-tour-of-myprayerjournal-v3/the-data-store.html "A Tour of myPrayerJournal v3: The Data Store | The Bit Badger Blog"
diff --git a/source/_posts/2021/a-tour-of-myprayerjournal-v3/introduction.md b/source/_posts/2021/a-tour-of-myprayerjournal-v3/introduction.md
deleted file mode 100644
index b48dbb0..0000000
--- a/source/_posts/2021/a-tour-of-myprayerjournal-v3/introduction.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal v3: Introduction"
-date: 2021-11-26 16:04:00
-author: Daniel
-categories:
-- [ Databases, LiteDB ]
-- [ Programming, .NET, F# ]
-- [ Programming, htmx ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal v3 ]
-tags:
-- f#
-- giraffe
-- htmx
-- introduction
-- javascript
-- journaling
-- litedb
-- prayer
-- requirements
-- vue
----
-This is the first of 5 posts in this series.
-
-- **Part 0: Introduction** _(this post)_
-- **[Part 1: The User Interface][part1]** - A look at htmx and Giraffe working together to create the web UI
-- **[Part 2: Bootstrap Integration][part2]** - A little bit of JavaScript goes a long way
-- **[Part 3: The Data Store][part3]** - Migration to and usage of LiteDB
-- **[Part 4: Conclusion][part4]** - Lessons learned and areas for improvement
-
-## Background
-
-Around 3 years ago, I wrote an 8-part series called ["A Tour of myPrayerJournal"][tour1], recounting the decisions and implementation of its initial release. Version 2 did not get its own tour, as it used a similar architecture. There were also some nagging library issues that were never resolved, leading to v2 being an overall unsatisfying step in the evolution of this application.
-
-When [Vue][] v3 was announced, this sounded like a great opportunity, with first-class TypeScript support and a new component syntax that promised better performance and a better developer experience. This past summer, I completed a project with the mature Vue v3 framework, and was generally pleased with the results. Just after I returned to my previously abandoned migration attempt on this project (with early Vue v3 support), I heard about **htmx**. With a few attributes, and a server that can handle a few HTTP headers, you can build an interactive site, with performance rivaling or exceeding that of the typical Single Page Application (SPA) - or, at this point, so they claimed.
-
-I also picked up **LiteDB** on another project over the summer, and it worked well. I thought, why not give these technologies a try, and see if I would like the result?
-
-_(SPOILER ALERT: I did!)_
-
-## The Requirements
-
-Requirements for v3 were, for the most part, to update the application to Vue v3. Without rehashing the entire list (see the other intro post), the basic idea is that a prayer request is represented by a card, and this card keeps up with all changes made to it. Also, the system can present the cards that are active, arranged with the oldest action date first, and allow you to tick through the cards. (This is the flow to enable the user to "pray through their list.")
-
-The goal is to remain a minimalist program; the focus should be on prayer, not using a website. To that end, I had envisioned a "one-at-a-time" scenario that would clear out distractions and present the cards in the same order. I had also planned to separate the "last prayed" date from the "last activity" date; currently, updating the text of a request moves it to the bottom of the stack. However, both of these improvements were deferred to v3.1; v3 restores the (adequate) functionality of v1, while being much lighter-weight.
-
-## The Tech Stack
-
-This stack did not go through nearly as many iterations as v1.
-
-**[Giraffe][]** is a library that enables F# developers to create ASP.NET Core endpoints in a functional style. It's a mature library (v1 used Giraffe!), and continues to be improved. It also provides an optional "Giraffe View Engine," which will get more attention in the user interface post; the views for v3 are produced via this view engine.
-
-**[htmx][]** is a JavaScript library that asks... well, several questions. Why should links and buttons be the only interactive elements? Why should you have to replace the whole page every time? What would HTML look like if it had been developed the way a typical programming language would be? It uses a small set of attributes to answer these questions differently, making interactive sites possible without writing any JavaScript. (The custom JavaScript file in v3 is 82 lines, including comments - and the majority of that is [Bootstrap][] interaction.)
-
-Since, in the htmx way, the web server returns rendered HTML, the requests can be a bit larger than the equivalent API calls that return JSON for a SPA framework to render. However, this is offset somewhat by the fact that the browser just has to swap that HTML fragment in; the processing is faster and much less complex.
-
-What really swung me over the fence to giving it a shot, though, was a point Carson (the author of the library) made while talking with Carl and Richard on the _[.NET Rocks!][]_ podcast. Having a server render the HTML, and the browser merely displaying it, keeps your application logic on the server; the only JavaScript you need to write is what is required for the user interface. This eliminates a host of synchronization issues with SPAs and their associated APIs - duplicating shapes of data, ensuring calculations are in sync, etc. It also keeps your application logic from needing to be exposed to the public Internet; this doesn't entirely prevent exploits, but the prospective hacker doesn't start with a full copy of your code.
-
-**[LiteDB][]** could be described as SQLite for documents. Collections of Plain-Old CLR Objects (POCOs) can be stored, retrieved, searched, indexed, and deleted, all while running in the current process, and requiring no separate database server install. While it does not require any special configuration to do this, it does also provide the ability to transform these objects. This gives complete control as to how much or how little transformation you want to specify; and, as we'll see in part 3, this came in handy for this application.
-
-## Where We Go from Here
-
-In the [next post][part1], we'll take a look at Giraffe, its View Engine, htmx, and how they all work together. The [post after that][part2] will dive into the aforementioned 82 lines of JavaScript to see how we can control Bootstrap's client/browser behavior from the server. After that, we'll [dig in on LiteDB][part3], to include how we serialize some common F# constructs. Finally, we'll [wrap up the series][part4] with overarching lessons learned, and other thoughts which may not fit nicely into one of the other posts.
-
-
-[part1]: /2021/a-tour-of-myprayerjournal-v3/the-user-interface.html "A Tour of myPrayerJournal v3: The User Interface | The Bit Badger Blog"
-[part2]: /2021/a-tour-of-myprayerjournal-v3/bootstrap-integration.html "A Tour of myPrayerJournal v3: Bootstrap Integration | The Bit Badger Blog"
-[part3]: /2021/a-tour-of-myprayerjournal-v3/the-data-store.html "A Tour of myPrayerJournal v3: The Data Store | The Bit Badger Blog"
-[part4]: /2021/a-tour-of-myprayerjournal-v3/conclusion.html "A Tour of myPrayerJournal v3: Conclusion | The Bit Badger Blog"
-[tour1]: /2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog"
-[Vue]: https://vuejs.org "Vue"
-[Giraffe]: https://giraffe.wiki "Giraffe"
-[htmx]: https://htmx.org "htmx"
-[Bootstrap]: https://getbootstrap.com "Bootstrap"
-[LiteDB]: https://litedb.org "LiteDB"
-[.NET Rocks!]: https://www.dotnetrocks.com/?show=1749 "htmx with Carson Gross | .NET Rocks!"
diff --git a/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-data-store.md b/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-data-store.md
deleted file mode 100644
index a56c032..0000000
--- a/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-data-store.md
+++ /dev/null
@@ -1,291 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal v3: The Data Store"
-date: 2021-12-01 17:33:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Databases, LiteDB ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal v3 ]
-tags:
-- async
-- bson
-- discriminated union
-- ef core
-- f#
-- giraffe
-- json
-- linq
-- litedb
-- mapping
-- postgresql
-- ravendb
----
-
-_NOTE: This is the fourth post in a series; see [the introduction][intro] for information on requirements and links to other posts in the series._
-
-myPrayerJournal v1 used [PostgreSQL][] with [Entity Framework Core][ef-core] for its backing store (which had [a stop on the v1 tour][v1-data]). v2 used [RavenDB][], and while I didn't write a tour of it, you can [see the data access logic][v2-data] if you'd like. Let's take a look at the technology we used for v3.
-
-## About LiteDB
-
-[LiteDB][] is a single-file, in-process database, similar to [SQLite][]. It uses a document model for its data store, storing Plain Old CLR Objects (POCOs) as Binary JSON (BSON) documents in its file. It supports cross-collection references, customizable mappings, different access modes, and transactions. It allows documents to be queried via LINQ syntax or via its own SQL-like language.
-
-As I mentioned in the introduction, I picked it up for another project, and really enjoyed the experience. Its configuration could not be easier -- the connection string is _literally_ a path and file name -- and it had good performance as well. The way it locks its database file, I can copy it while the application is up, which is great for backups. It was definitely a good choice for this project.
-
-## The Domain Model
-
-When I converted from PostgreSQL to RavenDB, the data structure ended up with one document per request; the history log and notes were stored as F# lists (arrays in JSON) within that single document. RavenDB supports indexes which can hold calculated values, so I had made an index that had the latest request text, and the latest time an action was taken on a request. When v2 displayed any list of requests, I queried the index, and got the calculated fields for free.
-
-The model for v3 is very similar.
-
-```fsharp
-/// Request is the identifying record for a prayer request
-[]
-type Request = {
- /// The ID of the request
- id : RequestId
- /// The time this request was initially entered
- enteredOn : Instant
- /// The ID of the user to whom this request belongs ("sub" from the JWT)
- userId : UserId
- /// The time at which this request should reappear in the user's journal by manual user choice
- snoozedUntil : Instant
- /// The time at which this request should reappear in the user's journal by recurrence
- showAfter : Instant
- /// The type of recurrence for this request
- recurType : Recurrence
- /// How many of the recurrence intervals should occur between appearances in the journal
- recurCount : int16
- /// The history entries for this request
- history : History list
- /// The notes for this request
- notes : Note list
- }
-```
-
-A few notes would probably be good here:
-
-- The `CLIMutable` attribute allows this non-nullable record type to be null, and generates a zero-argument constructor that reflection-based processes can use to create an instance. Both of these are needed to interface with a C#-oriented data layer.
-- By default, F# creates comparison and equality implementations for record types. This type, though, is a simple data transfer object, so the `NoEquality` and `NoComparison` attributes prevent these from being generated.
-- Though not shown here, `History` has an "as-of" date/time, an action that was taken, and an optional request text field; `Note` has the same thing, minus the action but requiring the text field.
-
-## Customizing the POCO Mapping
-
-If you look at the fields in the `Request` type above, you'll spot exactly one primitive data type (`int16`). `Instant` comes from [NodaTime][], but the remainder are custom types. These are POCOs, but not your typical POCOs; by tweaking the mappings, we can get a much more efficient BSON representation.
-
-### Discriminated Unions
-
-F# supports discriminated unions (DUs), which can be used in different ways to construct a domain model in such a way that an invalid state cannot be represented (TL;DR - "make invalid states unrepresentable"). One way of doing this is via the single-case DU:
-
-```fsharp
-/// The identifier of a user (the "sub" part of the JWT)
-type UserId =
- | UserId of string
-```
-
-Requests are associated with the user, via the `sub` field in the JWT received from [Auth0][]. That field is a string; but, in the handler that retrieves this from the `Authorization` header, it is returned as `UserId [sub-value]`. In this way, that string cannot be confused with any other string (such as a note, or a prayer request).
-
-Another way DUs can be used is to generate enum-like types, where each item is its own type:
-
-```fsharp
-/// How frequently a request should reappear after it is marked "Prayed"
-type Recurrence =
- | Immediate
- | Hours
- | Days
- | Weeks
-```
-
-Here, these four values will refer to a recurrence, and it will take no others. This barely scratches the surface on DUs, but it should give you enough familiarity with them so that the rest of this makes sense.
-
-> _For the F#-fluent - you may be asking "Why didn't he define this with `Hours of int16`, `Days of int16`, etc. instead of putting the number in `Request` separate from the type?" The answer is a combination of evolution -- this is the way it worked in v1 -- and convenience. I very well could have done it that way, and probably should at some point._
-
-### Converting These Types in myPrayerJournal v2
-
-F# does an excellent job of transparently representing DUs, `Option` types, and others to F# code, while their underlying implementation is a CLR type; however, when they are serialized using traditional reflection-based serializers, the normally-transparent properties appear in the output. RavenDB (and Giraffe, when v1 was developed) uses [JSON.NET][] for its serialization, so it was easy to write a converter for the `UserId` type:
-
-```fsharp
-/// JSON converter for user IDs
-type UserIdJsonConverter () =
- inherit JsonConverter ()
- override __.WriteJson(writer : JsonWriter, value : UserId, _ : JsonSerializer) =
- (UserId.toString >> writer.WriteValue) value
- override __.ReadJson(reader: JsonReader, _ : Type, _ : UserId, _ : bool, _ : JsonSerializer) =
- (string >> UserId) reader.Value
-```
-
-Without this converter, a property "x", with a user ID value of "abc", would be serialized as:
-
-```json
-{ "x": { "Case": "UserId", "Value": "abc" } }
-```
-
-With this converter, though, the same structure would be:
-
-```json
-{ "x": "abc" }
-```
-
-For a database where you are querying on a value, or a JSON-consuming front end web framework, the latter is definitely what you want.
-
-### Converting These Types in myPrayerJournal v3
-
-With all of the above being said -- LiteDB does not use JSON.NET; it uses its own custom `BsonMapper` class. This means that the conversions for these types would need to change. LiteDB does support creating mappings for custom types, though, so this task looked to be a simple conversion task. As I got into it, though, I realized that nearly every field I was using needed some type of conversion. So, rather than create converters for each different type, I created one for the document as a whole.
-
-It was surprisingly straightforward, once I figured out the types! Here are the functions to convert the request type to its BSON equivalent, and back:
-
-```fsharp
-/// Map a request to its BSON representation
-let requestToBson req : BsonValue =
- let doc = BsonDocument ()
- doc["_id"] <- RequestId.toString req.id
- doc["enteredOn"] <- req.enteredOn.ToUnixTimeMilliseconds ()
- doc["userId"] <- UserId.toString req.userId
- doc["snoozedUntil"] <- req.snoozedUntil.ToUnixTimeMilliseconds ()
- doc["showAfter"] <- req.showAfter.ToUnixTimeMilliseconds ()
- doc["recurType"] <- Recurrence.toString req.recurType
- doc["recurCount"] <- BsonValue req.recurCount
- doc["history"] <- BsonArray (req.history |> List.map historyToBson |> Seq.ofList)
- doc["notes"] <- BsonArray (req.notes |> List.map noteToBson |> Seq.ofList)
- upcast doc
-
-/// Map a BSON document to a request
-let requestFromBson (doc : BsonValue) =
- { id = RequestId.ofString doc["_id"].AsString
- enteredOn = Instant.FromUnixTimeMilliseconds doc["enteredOn"].AsInt64
- userId = UserId doc["userId"].AsString
- snoozedUntil = Instant.FromUnixTimeMilliseconds doc["snoozedUntil"].AsInt64
- showAfter = Instant.FromUnixTimeMilliseconds doc["showAfter"].AsInt64
- recurType = Recurrence.ofString doc["recurType"].AsString
- recurCount = int16 doc["recurCount"].AsInt32
- history = doc["history"].AsArray |> Seq.map historyFromBson |> List.ofSeq
- notes = doc["notes"].AsArray |> Seq.map noteFromBson |> List.ofSeq
- }
-```
-
-Each of these round-trips as the same value; line 6 (`doc["userId"]`) stores the string representation of the user ID, while line 19 (`userId =`) creates a strongly-typed `UserId` from the string stored in database.
-
-> _The downside to this technique is that LINQ won't work; passing a `UserId` would look for the default serialized version, not the simplified string version. This is not a show-stopper, though, especially for such a small application as this. If I had wanted to use LINQ for queries, I would have written several type-specific converters instead._
-
-## Querying the Data
-
-In v2, there were two different types; `Request` was what was stored in the database, and `JournalRequest` was the type that included the calculated fields included in the index. This conversion came into the application; `ofRequestFull` is a function that performs the calculations, and returns an item which has full history and notes, while `ofRequestLite` does the same thing without the history and notes lists.
-
-With that knowledge, here is the function that retrieves the user's current journal:
-
-```fsharp
-/// Retrieve the user's current journal
-let journalByUserId userId (db : LiteDatabase) = backgroundTask {
- let! jrnl = db.requests.Find (Query.EQ ("userId", UserId.toString userId)) |> toListAsync
- return
- jrnl
- |> Seq.map JournalRequest.ofRequestLite
- |> Seq.filter (fun it -> it.lastStatus <> Answered)
- |> Seq.sortBy (fun it -> it.asOf)
- |> List.ofSeq
- }
-```
-
-Line 3 contains the LiteDB query; when it is done, `jrnl` has the type `System.Collections.Generic.List`. This "list" is different than an F# list; it is a concrete, doubly-linked list. F# lists are immutable, recursive item/tail pairs, so F# views the former as a form of sequence (as it extends `IEnumerable`). Thus, the `Seq` module calls in the return statement are the appropriate ones to use. They execute lazily, so filters should appear as early as possible; this reduces the number of latter transformations that may need to occur.
-
-Looking at this example, if we were to sort first, the entire sequence would need to be sorted. Then, when we filter out the requests that are answered, we would remove items from that sequence. With sorting last, we only have to address the full sequence once, and we are sorting a (theoretically) smaller number of items. Conversely, we do have to run the `map` on the original sequence, as `lastStatus` is one of the calculated fields in the object created by `ofRequestLite`. Sometimes you can filter early, sometimes you cannot.
-
-_(Is this micro-optimizing? Maybe; but, in my experience, taking a few minutes to think through collection pipeline ordering is a lot easier than trying to figure out why (or where) one starts to bog down. Following good design principles isn't premature optimization, IMO.)_
-
-## Getting a Database Connection
-
-The example in the previous section has a final parameter of `(db: LiteDatabase)`. As Giraffe sits atop ASP.NET Core, myPrayerJournal uses the traditional dependency injection (DI) container. Here is how it is configured:
-
-```fsharp
-/// Configure dependency injection
-let services (bldr : WebApplicationBuilder) =
- // ...
- let db = new LiteDatabase (bldr.Configuration.GetConnectionString "db")
- Data.Startup.ensureDb db
- bldr.Services
- // ...
- .AddSingleton db
- |> ignore
- // ...
-```
-
-The connection string comes from `appsettings.json`. `Data.Startup.ensureDb` makes sure that requests are indexed by user ID, as that is the parameter by which request lists are queried; this also registers the converter functions discussed above. LiteDB has an option to open the file for shared access or exclusive access; this implementation opens it for exclusive access, so we can register that connection as a singleton. (LiteDB handles concurrent queries itself.)
-
-Getting the database instance out of DI is, again, a standard Giraffe technique:
-
-```fsharp
-/// Get the LiteDB database
-let db (ctx : HttpContext) = ctx.GetService ()
-```
-
-This can be called in any request handler; here is the handler that displays the journal cards:
-
-```fsharp
-// GET /components/journal-items
-let journalItems : HttpHandler =
- requiresAuthentication Error.notAuthorized
- >=> fun next ctx -> backgroundTask {
- let now = now ctx
- let! jrnl = Data.journalByUserId (userId ctx) (db ctx)
- let shown = jrnl |> List.filter (fun it -> now > it.snoozedUntil && now > it.showAfter)
- return! renderComponent [ Views.Journal.journalItems now shown ] next ctx
- }
-```
-
-## Making LiteDB Async
-
-I found it curious that LiteDB's data access methods do not have async equivalents (ones that would return `Task` instead of just `T`). My supposition is that this is a case of YAGNI. LiteDB maintains a log file, and makes writes to that first; then, when it's not busy, it synchronizes the log to the file it uses for its database. However, I wanted to control when that occurs, and the rest of the request/function pipelines are async, so I set about making async wrappers for the applicable function calls.
-
-Here are the data retrieval functions:
-
-```fsharp
-/// Convert a sequence to a list asynchronously (used for LiteDB IO)
-let toListAsync<'T> (q : 'T seq) =
- (q.ToList >> Task.FromResult) ()
-
-/// Convert a sequence to a list asynchronously (used for LiteDB IO)
-let firstAsync<'T> (q : 'T seq) =
- q.FirstOrDefault () |> Task.FromResult
-
-/// Async wrapper around a request update
-let doUpdate (db : LiteDatabase) (req : Request) =
- db.requests.Update req |> ignore
- Task.CompletedTask
-```
-
-And, for the log synchronization, an extension method on `LiteDatabase`:
-
-```fsharp
-/// Extensions on the LiteDatabase class
-type LiteDatabase with
- // ...
- /// Async version of the checkpoint command (flushes log)
- member this.saveChanges () =
- this.Checkpoint ()
- Task.CompletedTask
-```
-
-None of these actually make the underlying library use async I/O; however, they do let the application's main thread yield until the I/O is done. Also, despite the `saveChanges` name, this is **not required** to save data into LiteDB; it is there once the insert or update is done (or, optionally, when the transaction is committed).
-
-## Final Thoughts
-
-As I draft this, this paragraph is on line 280 of this post's source; the entire [Data.fs][] file is 209 lines, including blank lines and comments. The above is a moderately long-winded explanation of what is nicely terse code. If I had used traditional C#-style POCOs, the code would likely have been shorter still. The backup of the LiteDB file is right at half the size of the equivalent RavenDB backup, so the POCO-to-BSON mapping paid off there. I'm quite pleased with the outcome of using LiteDB for this project.
-
-Our [final stop on the tour][part4] will wrap up with overall lessons learned on the project.
-
-
-[intro]: /2021/a-tour-of-myprayerjournal-v3/introduction.html "A Tour of myPrayerJournal v3: Introduction | The Bit Badger Blog"
-[PostgreSQL]: https://www.postgresql.org "PostgreSQL"
-[ef-core]: https://docs.microsoft.com/en-us/ef/core/ "Overview of Entity Framework Core | Microsoft Docs"
-[v1-data]: /2018/a-tour-of-myprayerjournal/the-data-store.html "A Tour of myPrayerJournal: The Data Store | The Bit Badger Blog"
-[RavenDB]: https://ravendb.net "RavenDB"
-[v2-data]: https://github.com/bit-badger/myPrayerJournal/blob/2.2/src/MyPrayerJournal.Api/Data.fs "myPrayerJournal v2 data access module"
-[LiteDB]: https://www.litedb.org "LiteDB"
-[SQLite]: https://sqlite.org "SQLite"
-[NodaTime]: https://nodatime.org "NodaTime"
-[Auth0]: https://auth0.com "Auth0"
-[JSON.NET]: https://www.newtonsoft.com/json "JSON.NET"
-[lite-map]: https://www.litedb.org/docs/object-mapping/ "Object Mapping - LiteDB"
-[Data.fs]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Data.fs "myPrayerJournal v3 Data.fs file"
-[part4]: /2021/a-tour-of-myprayerjournal-v3/conclusion.html "A Tour of myPrayerJournal v3: Conclusion | The Bit Badger Blog"
diff --git a/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-user-interface.md b/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-user-interface.md
deleted file mode 100644
index 9759e24..0000000
--- a/source/_posts/2021/a-tour-of-myprayerjournal-v3/the-user-interface.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-layout: post
-title: "A Tour of myPrayerJournal v3: The User Interface"
-date: 2021-11-28 14:17:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Programming, htmx ]
-- [ Projects, Giraffe.Htmx ]
-- [ Projects, myPrayerJournal ]
-- [ Series, A Tour of myPrayerJournal v3 ]
-tags:
-- angular
-- aurelia
-- bootstrap
-- elm
-- ember
-- f#
-- giraffe
-- html
-- htmx
-- javascript
-- migration
-- nuget
-- post-redirect-get
-- pug
-- react
-- single page application
-- spa
-- view engine
-- vue
----
-
-_NOTE: This is the second post in a series; see [the introduction][intro] for information on requirements and links to other posts in the series._
-
-If you are a seasoned Single Page Application (SPA) framework developer, you likely think about interactivity in a particular way. Initially, I focused on replacing each interactive piece in isolation. In the end, though, requests for "pages" returned almost everything but the HTML head info and the displayed footer - and I was happy about it. Keep that in mind as I walk you down the path I have already traveled; keep an open mind, and read to the end before forming strong opinions either way.
-
-## The $.05 Tour of Pug and Giraffe View Engine
-
-Understanding the syntax of both [Pug][] and [Giraffe View Engine][gve] will help you if you click any of the source code example links. While a complete explanation of these two templating languages would make this long post much longer than it already is, here are some short examples of their syntax. Using a string variable `who` with the contents "World", we will show both languages rendering:
-
-```html
-
Hello World
-```
-
-myPrayerJournal v2 used Pug templates in [Vue][] to render the user interface. Pug uses indentation-sensitive tag/content pairs (or blocks), with JavaScript syntax for attributes, to generate HTML. To generate the example paragraph, the shortest template would look like:
-
-```pug
-p.greeting(id="example") Hello #[strong= who]
-```
-
-myPrayerJournal v3 uses Giraffe View Engine, which uses F# lists to generate HTML from a very HTML-looking domain-specific language (DSL). The example paragraph would be generated with:
-
-```fsharp
-p [ _id "example"; _class "greeting" ] [ str "Hello "; strong [] [ who ] ]
-```
-
-Given those examples, let's dig into the conversion.
-
-## The Menu
-
-The menu across the top of the application was one of the first items I needed to convert. The menu needs to be different, depending on whether there is a user logged on or not. Also, if a user is logged on, the menu can still be different; the "Snoozed" menu item only appears if the user has any snoozed requests. The application uses [Auth0][] to manage users (which is how it is open to Microsoft and Google accounts), and I wanted to preserve this; my requests are tied to the ID provided by Auth0, so that did not need to change.
-
-In the Vue version, the system used Auth0's SPA library that exposed whether there was a user logged on or not. Also, once a user was logged on, the API sent all the user's active requests, which included snoozed requests; once this API call returned, the application can turn on the "Snoozed" menu item. In the [htmx][] version, though, this information is all generated on the server. My initial process was to use an `hx-get` to get the menu HTML snippet, using an `hx-trigger` of `load` to fill in this spot of the page when the page was loaded. I also (initially) implemented a custom HTML header to include in responses, and if that header was found, I would trigger a refresh on the menu; the eventual solution included the navbar in "page" refreshes.
-
-_(See the [Vue "Navigation" component][v2-nav] that became the [Giraffe View Engine "navbar" function][v3-nav])_
-
-## "New Page" in htmx
-
-This leads directly into a discussion of how myPrayerJournal is still considered a SPA. In the Vue version, "pages" were Vue Single-File Components (SFCs) under the `/components` directory. (In the years since myPrayerJournal v1, the default Vue template has changed to place these SFCs under `/views`, while `/components` is reserved for shared components.) These view components rendered into a custom component within the `main` tag (using Vue router's [`router-view` tag][v2-router]), while the `nav` component was reactive, based on the user logging on/off and snoozing requests.
-
-In myPrayerJournal v3, "page" views target the [`#top` `section` element][v3-top]. If the request is for a full page load, the HTML `head` content is rendered, as is the `body`'s `footer` content; none of these change until a new version of the application is released. If the request is an htmx request, though, the only thing rendered is a new `#top` section, which includes the navigation bar and the page content. While this does approach a full "page load", there are some key differences:
-
-- The page contents are refreshed based on one HTTP request (no extra request or processing required for the navbar);
-- The HTML `head` content is responsible for most of the large HTTP requests, such as those for JavaScript libraries (and is excluded from non-full-page views);
-- The page footer is not included.
-
-Note the difference between the [full `view` layout][v3-full] and the [`partial` layout][v3-partial]. Also, within the application's request handlers, there is a [partial return function][v3-part-return] that determines whether this is an htmx-initiated page view request (in which case a partial view is returned) or a full page request (which returns the entire template).
-
-## Updating the Page Title
-
-One of the most unexpectedly-vexing parts of a SPA is determining how the browser's title bar will be updated when navigation occurs. _(I understand why it's challenging; what I do not understand is why it took major frameworks so long to devise a built-in way of handling this.)_ Coming from that world, I had originally implemented yet another custom header, pushing the title from the server, and used a request listener to update the title if the header was present. As I dug in further, though, I learned that htmx will update the document title any time a request payload has an HTML `title` element in its `head`. If you look at both layouts in the preceding paragraph, you'll notice that they include a `head` element with a `title` tag. This is how easy it should be, and with htmx, this is how easy it is.
-
-At this point, there is a pattern emerging. The thought process behind an htmx-powered website is much different than a JavaScript-based SPA framework; and, in the majority of cases, it has been less complex. Now, let me contradict what I just said.
-
-## POST-Redirect-GET
-
-In myPrayerJournal v2, updating a prayer request followed this flow:
-
-- Display the edit page, with the request details filled in
-- When the user saved the request, return an empty `200 OK` response
-- Using Vue, display a notification, refresh the journal, then re-render the page where the user had been when they clicked "Edit" (there are multiple places from which requests can be edited)
-
-While there are no redirects here, this is the classic traditional-web-application scenario where the "POST-Redirect-GET" (P-R-G) pattern is used. By using this pattern, the "Back" button on the browser still works. If you try to go back to the result of a POST request, the browser will warn you that your action will result in the data being resubmitted (not usually what you want to do). By redirecting, though, the result of a POST becomes a GET, which does not change any data. For traditional web applications, this is the user-friendliest way to handle updates.
-
-In the htmx examples, they show [an example of inline editing][in-edit]. This led to my first plan - change the request edit "page" to be a component, where the HTML for the displayed list was replaced by the form, and then the "Save" action returns the new HTML. This requires no P-R-G, as these actions have no effect on the "Back" button. It worked fine, but there were some things that weren't quite right:
-
-- New requests needed their own page; I was going to have to duplicate the edit form for the "new" page, and introduce some complexity in determining how to render the results.
-- Some updates required refreshing the list of requests, not just replacing the text and action buttons.
-
-At this point, I was also starting to realize "if you think something is hard to do in htmx, you probably aren't trying to do it correctly." So, I decided to try to replicate the "edit page" flow of v2 in v3. Creating [the page][v3-edit] was easy enough, and I was able to use the `returnTo` parameter in the function to both provide a "Cancel" button and redirect the user to the right place after saving. Easy, right? Well... Not quite.
-
-htmx uses `XMLHttpRequest` (XHR) to send its requests, which has some interesting behavior; it follows redirects! When I submitted my form, it received the request (with htmx's `HX-Request` header set), and the server returned the redirect. XHR saw this, and followed it; however, it used the same method. (It was POSTing to the new URL.) The fix for this, though, was not easy to find, but easy to implement; use HTTP response code `303` (see other) instead of `307` (moved temporarily). Using this, combined with using `hx-target="#top"` on the form, allowed the P-R-G pattern to work successfully without double-POSTing and without a full-page refresh.
-
-## htmx Support in Giraffe and Giraffe View Engine
-
-As I developed this, I was also building up extensions for Giraffe to handle the htmx request and response headers, as well as the attributes needed to generate htmx-aware markup from Giraffe View Engine. [This project][g-h], called Giraffe.Htmx, is now published on NuGet. There are two packages; `Giraffe.Htmx` provides server-side support for the request and response headers, and `Giraffe.ViewEngine.Htmx` provides support for generating htmx attributes. I [wrote about it][g-h-rel] when it was released, so I won't rehash the entire thing here.
-
-## Final UI Thoughts
-
-htmx is much less complex than any other front-end JavaScript SPA framework I have ever used - which, for context, includes [Angular][], Vue, [React][], [Ember][], [Aurelia][], and [Elm][]. Both in development and in production use, I cannot tell that the payloads are slightly larger; navigation is fast and smooth. Though I have yet to change anything since going live with myPrayerJournal v3, I know that maintenance will be quite straightforward (to be further explored in the conclusion post).
-
-The UI for myPrayerJournal uses [Bootstrap][], a UI framework which has its own script, and htmx plays quite nicely with it. The [next post][part2] in this series will describe how I interact with both Bootstrap and htmx, using modals and toasts on this "traditional" web application.
-
-
-[intro]: /2021/a-tour-of-myprayerjournal-v3/introduction.html "A Tour of myPrayerJournal v3: Introduction | The Bit Badger Blog"
-[Pug]: https://pugjs.org/ "Pug"
-[gve]: https://giraffe.wiki/view-engine "Giraffe View Engine"
-[Vue]: https://vuejs.org "Vue.js"
-[Auth0]: https://auth0.com "Auth0"
-[htmx]: https://htmx.org "htmx"
-[v2-nav]: https://github.com/bit-badger/myPrayerJournal/blob/2.2/src/app/src/components/common/Navigation.vue "myPrayerJournal v2 Navigation Vue component"
-[v3-nav]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Views/Layout.fs#L39 "myPrayerJournal v3 navbar function"
-[v2-router]: https://github.com/bit-badger/myPrayerJournal/blob/2.2/src/app/src/App.vue#L16 "myPrayerJournal v2 router-view tag"
-[v3-top]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Views/Layout.fs#L140 "myPrayerJournal v3 #top section"
-[v3-full]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Views/Layout.fs#L136 "myPrayerJournal v3 full layout"
-[v3-partial]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Views/Layout.fs#L147 "myPrayerJournal v3 partial layout"
-[v3-part-return]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Handlers.fs#L162 "myPrayerJournal v3 partial return function"
-[in-edit]: https://htmx.org/examples/click-to-edit/ "Click to Edit | htmx"
-[v3-edit]: https://github.com/bit-badger/myPrayerJournal/blob/3/src/MyPrayerJournal/Views/Request.fs#L139 "myPrayerJournal v3 Request Edit page"
-[g-h]: https://github.com/bit-badger/Giraffe.Htmx "Giraffe.Htmx"
-[g-h-rel]: /2021/introducing-giraffe-htmx.html "Introducing Giraffe.Htmx | The Bit Badger Blog"
-[Angular]: https://angular.io "Angular"
-[React]: https://reactjs.org "React"
-[Ember]: https://emberjs.com "Ember"
-[Aurelia]: https://aurelia.io "Aurelia"
-[Elm]: https://elm-lang.org "Elm"
-[Bootstrap]: https://getbootstrap.com "Bootstrap"
-[part2]: /2021/a-tour-of-myprayerjournal-v3/bootstrap-integration.html "A Tour of myPrayerJournal v3: Bootstrap Integration | The Bit Badger Blog"
diff --git a/source/_posts/2021/introducing-giraffe-htmx.md b/source/_posts/2021/introducing-giraffe-htmx.md
deleted file mode 100644
index 76239c3..0000000
--- a/source/_posts/2021/introducing-giraffe-htmx.md
+++ /dev/null
@@ -1,54 +0,0 @@
----
-layout: post
-title: Introducing Giraffe.Htmx
-date: 2021-11-09 16:06:00
-author: Daniel
-categories:
-- [ Programming, .NET, F# ]
-- [ Programming, htmx ]
-- [ Projects, Giraffe.Htmx ]
-tags:
-- f#
-- giraffe
-- htmx
-- view engine
----
-[Giraffe][] is a library that sits atop ASP.NET Core and allows developers to build web applications in a functional style; `dotnet new giraffe` is _literally_ my starting point when I begin a new web application project. _(Rather than write three more sentences filled with effusive praise, I'll just leave it at that; it's great.)_ It also provides a view engine (that builds upon [Suave][]'s "experimental" view engine) which uses an F# DSL to define HTML in a strongly-typed way. It has been incredibly efficient for a while, but with .NET's work over the past two releases at improving performance, and Giraffe's adoption of those techniques, it is lightning fast.
-
-[htmx][] is a library that brings interactivity to HTML through the use of attributes and HTTP headers. Whereas projects like [Vue][], [Angular][], and [React][] prescribe completely different programming paradigms than traditional web development, htmx provides partial-page-swapping and progressive enhancement within straight HTML. This brings a lot of the benefits of the SPA architecture to vanilla HTML, without requiring a completely different paradigm than the one we have used on the web for 30 years. In practice, this greatly reduces the complexity required to produce an interactive web application.
-
-The **Giraffe.Htmx** project provides a bridge between these two libraries. The project consists of two different NuGut packages.
-
-- `Giraffe.Htmx` provides extensions to Giraffe (and its exposure of ASP.NET Core's `HttpContext`) that expose the [request headers][req-hdr] which htmx uses, and provides Giraffe-style `HttpHandler`s to set htmx's recognized [response headers][res-hdr]. The request headers are exposed as `Option`s, and if present, are converted to the expected type. Response headers can be set in a similar way (i.e., passing `true` instead of `"true"` for a boolean header).
-
-```fsharp
- let myHandler : HttpHander =
- fun next ctx ->
- match ctx.Request.HxPrompt with
- | Some prompt -> ... // do something with the text the user provided
- | None -> ... // the user provided no text (likely was not even prompted)
- ...
-```
-
-- `Giraffe.ViewEngine.Htmx` extends Giraffe's view engine with [attribute][attrs] functions (ex. `_hxBoost` equates to `hx-boost="true"`) to generate HTML with htmx attributes. As with the headers, the values for each attribute are expected in their strongly-typed form, and the library handles the necessary string conversion. For attributes that have a defined set of values, there are also modules that provide those values; the example below demonstrates both the attributes and the `HxTrigger` module.
-
-```fsharp
- let autoLoad =
- div [ _hxGet "/this/endpoint"; _hxTrigger HxTrigger.Load ] [ str "Loading..." ]
-```
-
-Head over to [the project site][site] for NuGet links and more examples!
-
-p.s. As of this writing, the current (and only) version of this library is at v0.9.1. Both libraries should be ready for development use. For `Giraffe.ViewEngine.Htmx`, I intend to write helpers for `hx-headers` and `hx-vals` that will allow a list of `string * string` tuples to be passed. I also need to write READMEs for both NuGet packages. Once those are done, this will be v1-ready.
-
-
-[Giraffe]: https://giraffe.wiki "Giraffe"
-[Suave]: https://suave.io "Suave"
-[htmx]: https://htmx.org "htmx"
-[Vue]: https://vuejs.org "Vue.js"
-[Angular]: https://angular.io "Angular"
-[React]: https://reactjs.org "React"
-[req-hdr]: https://htmx.org/docs/#request_headers "Request Headers | htmx Docs"
-[res-hdr]: https://htmx.org/docs/#response_headers "Response Headers | htmx Docs"
-[attrs]: https://htmx.org/docs/#attributes "Attributes | htmx Docs"
-[site]: https://github.com/bit-badger/Giraffe.Htmx "Giraffe.Htmx | GitHub"
diff --git a/source/linux/index.md b/source/linux/index.md
deleted file mode 100644
index 8253801..0000000
--- a/source/linux/index.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-layout: page
-title: Linux Resources
-date: 2005-09-01 00:00:00
----
-We at Bit Badger Solutions love Linux! Below are the resources we provide.
-
-* [Installing Linux on an Averatec 6200 Laptop][averatec]
-* [xine RPMs for the x86_64 EL Architecture][xine]
-* [Bit Badger Solutions Software Repository][repo]
-* [Linux posts][posts] on this blog
-
-[averatec]: /linux/installing-wbel4-rhel4-on-an-averatec-6200-laptop/
-[xine]: /linux/xine-rpms-for-el-x86_64-architecture/
-[repo]: //hosted.djs-consulting.com/software/
-[posts]: /category/linux/
\ No newline at end of file
diff --git a/source/linux/installing-wbel4-rhel4-on-an-averatec-6200-laptop/index.md b/source/linux/installing-wbel4-rhel4-on-an-averatec-6200-laptop/index.md
deleted file mode 100644
index 004ec87..0000000
--- a/source/linux/installing-wbel4-rhel4-on-an-averatec-6200-laptop/index.md
+++ /dev/null
@@ -1,128 +0,0 @@
----
-layout: page
-title: Installing WBEL4 (RHEL4) on an Averatec 6200 Laptop
-date: 2005-09-01 00:00:00
----
-
-
-
-
-As an early Father's Day 2005 present, I received a new Averatec 6240 laptop. Being the Linux enthusiast that I am, within 24 hours of getting it, I had wiped the Windows XP Home Edition® that came on it. The previous week, I had downloaded [White Box Enterprise Linux (http://www.whiteboxlinux.org)][wbel] version 4, with an eye to upgrading my existing computer, so I had a recent set of CDs burned already. (WBEL is a clone of Red Hat Enterprise Linux, as is CentOS, so these instructions may be helpful for all RHEL derivatives.) I've organized this into topics - just click one to jump right to it.
-
-_(Note: This information is provided as information only, and a reflection of what I did to get my laptop running the way I wanted it. It may or may not work for you - no guarantee is specified or implied, and I cannot be held responsible for any hardware failure or data loss you may encounter by following any of the steps in this guide. At any rate, it's still probably worth double what you're paying for it... ;>)_
-
-**A Work in Progress** - This page is not complete - check the "What's Left?" topic to see what changes still need to be made before I'll consider it "complete". This page is as complete as it's ever going to be.
-
-## What Do I Have?
-
-To determine what type of hardware you have, you can use the command `/sbin/lspci`. On this laptop, I was able to boot with [Knoppix][], one of the most feature-rich Linux Live CD distributions out there. The list on this laptop is shown below...
-
-
0000:00:00.0 Host bridge: Silicon Integrated Systems [SiS] 760/M760 Host (rev 03)
-0000:00:01.0 PCI bridge: Silicon Integrated Systems [SiS] SG86C202
-0000:00:02.0 ISA bridge: Silicon Integrated Systems [SiS] SiS85C503/5513 (LPC Bridge) (rev 25)
-0000:00:02.5 IDE interface: Silicon Integrated Systems [SiS] 5513 [IDE]
-0000:00:02.6 Modem: Silicon Integrated Systems [SiS] AC'97 Modem Controller (rev a0)
-0000:00:02.7 Multimedia audio controller: Silicon Integrated Systems [SiS] Sound Controller (rev a0)
-0000:00:03.0 USB Controller: Silicon Integrated Systems [SiS] USB 1.0 Controller (rev 0f)
-0000:00:03.1 USB Controller: Silicon Integrated Systems [SiS] USB 1.0 Controller (rev 0f)
-0000:00:03.3 USB Controller: Silicon Integrated Systems [SiS] USB 2.0 Controller
-0000:00:04.0 Ethernet controller: Silicon Integrated Systems [SiS] SiS900 PCI Fast Ethernet (rev 91)
-0000:00:0a.0 CardBus bridge: ENE Technology Inc CB1410 Cardbus Controller (rev 01)
-0000:00:0e.0 Network controller: RaLink Ralink RT2500 802.11 Cardbus Reference Card (rev 01)
-0000:00:18.0 Host bridge: Advanced Micro Devices [AMD] K8 NorthBridge
-0000:00:18.1 Host bridge: Advanced Micro Devices [AMD] K8 NorthBridge
-0000:00:18.2 Host bridge: Advanced Micro Devices [AMD] K8 NorthBridge
-0000:00:18.3 Host bridge: Advanced Micro Devices [AMD] K8 NorthBridge
-0000:01:00.0 VGA compatible controller: Silicon Integrated Systems [SiS] 661FX/M661FX/M661MX/741/M741/760/M760 PCI/AGP
-
-
-This may seem like a waste of time (especially if you don't have a Knoppix CD lying around already, but this information can be invaluable when you try to get these devices working. A couple of things jump out from the above list - most of the hardware in this box was made by Silicon Integrated Systems, with the notable exception of the cardbus controller and the 802.11 (wireless) network adapter.
-
-## Partitioning
-
-Partitioning was a particular concern for me, as I wanted to set up a dual-boot Windows/Linux installation. Windows must have its files on the first partition for it to successfully boot, so I set up Windows first. I messed up a bit, as I tried to declare a 100MB boot partition as the first partition. Windows insisted on formatting it, so it could put its boot files on it, so I basically have a wasted 100MB at the front of my drive. (Not a big deal...)
-
-I created a 12GB partition for Windows, and a 15GB partition for "shared" data - I formatted it as FAT32 (vfat), so that both Windows and Linux can read it. This was fine, but combined with my extra 100MB partition, the WBEL installer was unable to automatically partition the remaining free space. This isn't a big problem - there are two pretty simple rules to remember about partitions that Linux needs...
-
-* There must be a root ("/") partition (I calculated the size of this by subtracting the amount of swap space I needed (see the next rule), then allocating the remaining free space to the root partition)
-* There must be a swap partition (actually the "swap" filesystem type) that is twice as big as your RAM (for this machine, that meant 1024MB)
-
-Here is my current partition table...
-
-
# /sbin/fdisk -l
-
-Disk /dev/hda: 60.0 GB, 60011642880 bytes
-255 heads, 63 sectors/track, 7296 cylinders
-Units = cylinders of 16065 * 512 = 8225280 bytes
-
-Device Boot Start End Blocks Id System
-/dev/hda1 * 1 13 104391 6 FAT16
-/dev/hda2 14 7295 58492665 f W95 Ext'd (LBA)
-/dev/hda5 14 1580 12586896 7 HPFS/NTFS
-/dev/hda6 1581 3589 16137261 b W95 FAT32
-/dev/hda7 3590 7158 28667961 83 Linux
-/dev/hda8 7159 7289 1052226 82 Linux swap
-
-
-## Installing
-
-Installing Linux is naturally the first thing you'll need to do. However, the default install options did not work for me. What did work was `linux nofb xdriver=sis`. This tells anaconda to not use a framebuffer (which, as I read, is incompatible with most of the LCD flat-panels that laptops have), and to use the "sis" (Silicon Integrated Systems) driver. Even with this, the installer will not detect the SiS video card or the flat-panel display - but that's okay, just let it install with the VESA driver and a generic 1024x768 layout. It'll be stretched, but definitely readable. (See the "video" topic for how to fix this.) Also, if you really mess something up, you'll need to pass those parameters in the rescue mode - the full command is `linux rescue nofb xdriver=sis`.
-
-I picked the server install, and selected most packages - this setup allows me to run both GNOME and KDE, and build applications for either. Be sure to install the system files, so you can compile kernel modules if you need them (which you'll need to do for the xdriver and wireless driver). Do not skip the OpenOffice.org I18N libraries - even though they're huge, it won't run without them. (I learned that the hard way.)
-
-## Video
-
-I mentioned that during the install, the monitor would not be detected. Using the system viedo config, you can set the LCD panel to 1280x800. Then, head over to [Thomas Winischhofer's site about the SiS video driver][wini-site]. He is the author of the SiS driver that's distributed with Linux, and his site has a lot of information about this chipset. On his site, he has built on that base, in his own time, and created a very usable driver for the SiS chipset. There are links to download various products - I downloaded the driver and the sisctrl program, and built them.
-
-Once I restarted the machine, it was better, but not quite there. I posted on the forums (also on the Winischhofer site) about my problem, and the author himself responded ([the thread is here][wini-forum]). In my case, 1280x800 was not put in by the driver - but, I think it may have been because I hadn't set the LCD panel settings when I installed the driver.
-
-## Wireless Networking
-
-The RaLink wireless ethernet card has a very capable open-source driver. It can be downloaded from [SerialMonkey's web site][sm]. I downloaded the driver, followed the instructions, and couldn't get it to work. It installed the adapter as ra0, but Linux was finding it as eth1 - and I couldn't get eth1 to change to ra0, or ra0 to change to eth1. I finally posted a message on the [driver's SourceForge.net forums][sf-forum], and the author told me that I needed to use `make install-fedora` instead of just `make install`.
-
-Every so often, I had problems getting the wireless card to connect with my home LAN. I changed my DHCP lease times from two weeks to two hours, and that problem cleared up. I think, for some reason, the router was not sensing when the wireless card would disconnect - so, when it tried to connect again, the router would just ignore it. Windows didn't seem to have similar problems, but that's a small tweak to make that hasn't affected any of the other computers on the network. I have gotten good responses from the developers of the wireless driver, and hope to be able to help them track this down if they're interested. (They are concentrating most of their new work on a new driver called "rt2x00" that will work for all RaLink RT2400 and RT2500 series network adapters, so this feature may be available in them. They've also moved their forums - [the official support forms can be found here][sm-forum].)
-
-## Other Tweaks
-
-They'll be here soon!
-
-## What’s Left?
-
-Issues I'm still working on...
-
-* **PCMCIA** - This is so slow initializing that rhgb (Red Hat's graphical booter) actually switches back to console one. I'm sure there's a way to make it not take so long, I just need to figure out what it is.
-* **Audio Input** - I tried to use the microphone in jack, and nothing would take sound from it.
-* **Shared Data Between XP and WBEL** - This is working differently than WBEL3 did - once I figure it out, it'll be here too.
-
-
-[wbel]: http://www.whiteboxlinux.org
-[Knoppix]: http://wwww.knoppix.com
-[wini-site]: http://www.winischhofer.at/linuxsisvga.shtml
-[wini-forum]: http://www.winischhofer.at/sisforum/viewtopic.php?t=76
-[sm]: http://rt2x00.serialmonkey.com/wiki/index.php/Main_Page
-[sf-forum]: http://sourceforge.net/forum/forum.php?thread_id=1294781&forum_id=370891
-[sm-forum]: http://rt2x00.serialmonkey.com/phpBB2/index.php
diff --git a/source/linux/xine-rpms-for-el-x86_64-architecture/index.md b/source/linux/xine-rpms-for-el-x86_64-architecture/index.md
deleted file mode 100644
index 40c306d..0000000
--- a/source/linux/xine-rpms-for-el-x86_64-architecture/index.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-layout: page
-title: xine RPMs for EL / x86_64 Architecture
-date: 2005-09-01 00:00:00
----
-The xine RPMs are now distributed through this blog. Information about the RPMs can be found in the [About the xine RPMs][abt] post, including how you can use RSS or Atom feeds to be notified of updated builds.
-
-You can also [view the list of available RPMs][list] or simply [browse the available xine files][browse].
-
-
-[abt]: /2005/about-the-xine-rpms.html "About the xine RPMs • The Bit Badger Blog"
-[list]: /category/hosted-64-bit-software/xine-rpms/ "“xine RPMs” Category • The Bit Badger Blog"
-[browse]: //hosted.djs-consulting.com/software/xine "xine RPMs • Bit Badger Solutions Software Repository"
diff --git a/theme/index.liquid b/theme/index.liquid
new file mode 100644
index 0000000..bfc8cc1
--- /dev/null
+++ b/theme/index.liquid
@@ -0,0 +1,56 @@
+{% if is_category or is_tag %}
+
{{ page_title }}
+ {%- if subtitle %}
+
{{ subtitle }}
+ {%- endif %}
+{% endif %}
+{%- for post in model.posts %}
+
+
+ {% endif -%}
+
\ No newline at end of file
diff --git a/theme/single-post.liquid b/theme/single-post.liquid
new file mode 100644
index 0000000..757ffc8
--- /dev/null
+++ b/theme/single-post.liquid
@@ -0,0 +1,64 @@
+{%- assign post = model.posts | first -%}
+
+